From 92b7dd3335a6572debeacfb5faa82c63a5e67888 Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Fri, 8 Jun 2018 20:03:25 +0200 Subject: Some minor fixes --- main/app/sprinkles/core/asset-bundles.json | 280 +- .../core/assets/SiteAssets/css/DarkTheme.css | 202 +- .../core/assets/SiteAssets/css/LightTheme.css | 208 +- .../core/assets/SiteAssets/css/animate.css | 7026 ++-- .../sprinkles/core/assets/SiteAssets/css/main.css | 1019 +- .../core/assets/SiteAssets/css/normalize.css | 680 +- .../core/assets/SiteAssets/css/swiper.css | 206 +- .../assets/SiteAssets/icons/BurgerMenuShort.svg | 114 +- .../SiteAssets/icons/BurgerMenuShortActivated.svg | 114 +- .../SiteAssets/icons/ExploreGlobeOutline.svg | 420 +- .../icons/ExploreGlobeOutlineActivated.svg | 420 +- .../assets/SiteAssets/icons/FriendFeedOutline.svg | 164 +- .../icons/FriendFeedOutlineActivated.svg | 164 +- .../SiteAssets/icons/MessageBubbleOutline.svg | 146 +- .../icons/MessageBubbleOutlineActivated.svg | 146 +- .../assets/SiteAssets/icons/UserGroupOutline.svg | 160 +- .../SiteAssets/icons/UserGroupOutlineActivated.svg | 160 +- .../core/assets/SiteAssets/icons/UserOutline.svg | 108 +- .../SiteAssets/icons/UserOutlineActivated.svg | 108 +- .../sprinkles/core/assets/SiteAssets/js/asemica.js | 478 +- .../sprinkles/core/assets/SiteAssets/js/asemica.pl | 1250 +- .../sprinkles/core/assets/SiteAssets/js/chat.js | 704 +- .../core/assets/SiteAssets/js/console.image.js | 558 +- .../sprinkles/core/assets/SiteAssets/js/console.js | 148 +- .../core/assets/SiteAssets/js/encryption.js | 38240 +++++++++---------- .../core/assets/SiteAssets/js/fontawesome.js | 3828 +- .../sprinkles/core/assets/SiteAssets/js/jquery.js | 5354 +-- .../sprinkles/core/assets/SiteAssets/js/linkify.js | 736 +- .../sprinkles/core/assets/SiteAssets/js/main.js | 430 +- .../core/assets/SiteAssets/js/openpgp.worker.js | 136 +- .../sprinkles/core/assets/SiteAssets/js/popups.js | 6780 ++-- .../sprinkles/core/assets/SiteAssets/js/push.js | 1422 +- .../sprinkles/core/assets/SiteAssets/js/swiper.js | 1110 +- .../php/Chatserver/bin/WebChatServer.php | 34 +- .../assets/SiteAssets/php/Chatserver/bin/nohup.out | 12 +- .../php/Chatserver/src/ChatProcessor.php | 510 +- .../core/assets/SiteAssets/php/SavePublicKey.php | 32 +- .../core/assets/SiteAssets/php/composer.json | 22 +- .../core/assets/SiteAssets/php/scripts.php | 26 +- .../core/assets/SiteAssets/php/stylesheet.php | 14 +- .../php/vendor/cboden/ratchet/.gitignore | 8 +- .../php/vendor/natxet/CssMin/src/CssMin.php | 9488 ++--- .../assets/font-starcraft/css/font-starcraft.css | 144 +- .../assets/font-starcraft/fonts/font-starcraft.svg | 86 +- .../assets/userfrosting/css/AdminLTE-skins-all.css | 4356 +-- .../assets/userfrosting/css/tablesorter-reflow.css | 130 +- .../core/assets/userfrosting/css/uf-alerts.css | 40 +- .../core/assets/userfrosting/css/uf-collection.css | 30 +- .../core/assets/userfrosting/css/userfrosting.css | 412 +- .../core/assets/userfrosting/favicons/ieconfig.xml | 24 +- .../assets/userfrosting/favicons/manifest.json | 102 +- .../userfrosting/favicons/safari-pinned-tab.svg | 492 +- .../core/assets/userfrosting/images/logo.svg | 1028 +- .../core/assets/userfrosting/js/AdminLTE-custom.js | 232 +- .../core/assets/userfrosting/js/AdminLTE.js | 1524 +- .../core/assets/userfrosting/js/attrchange.js | 262 +- .../js/fortress-jqueryvalidation-methods.js | 114 +- .../assets/userfrosting/js/handlebars-helpers.js | 238 +- .../core/assets/userfrosting/js/query-string.js | 130 +- .../js/tablesorter/widget-sort2Hash.js | 554 +- .../core/assets/userfrosting/js/uf-captcha.js | 26 +- .../core/assets/userfrosting/js/uf-collection.js | 698 +- .../core/assets/userfrosting/js/uf-copy.js | 100 +- .../core/assets/userfrosting/js/uf-form.js | 594 +- .../core/assets/userfrosting/js/uf-init.js | 54 +- .../userfrosting/js/uf-jqueryvalidation-config.js | 98 +- .../core/assets/userfrosting/js/uf-modal.js | 370 +- .../core/assets/userfrosting/js/uf-table.js | 1412 +- .../userfrosting/js/uf-tablesorter-parsers.js | 106 +- main/app/sprinkles/core/bower.json | 94 +- main/app/sprinkles/core/composer.json | 96 +- main/app/sprinkles/core/config/default.php | 366 +- main/app/sprinkles/core/config/dev.php | 58 +- main/app/sprinkles/core/config/production.php | 80 +- main/app/sprinkles/core/config/testing.php | 46 +- main/app/sprinkles/core/locale/ar/messages.php | 224 +- main/app/sprinkles/core/locale/ar/validate.php | 50 +- main/app/sprinkles/core/locale/de_DE/errors.php | 106 +- main/app/sprinkles/core/locale/de_DE/main.php | 38 +- main/app/sprinkles/core/locale/de_DE/validate.php | 64 +- main/app/sprinkles/core/locale/en_US/errors.php | 102 +- main/app/sprinkles/core/locale/en_US/main.php | 38 +- main/app/sprinkles/core/locale/en_US/messages.php | 240 +- main/app/sprinkles/core/locale/en_US/validate.php | 66 +- main/app/sprinkles/core/locale/es_ES/errors.php | 102 +- main/app/sprinkles/core/locale/es_ES/messages.php | 230 +- main/app/sprinkles/core/locale/fa/errors.php | 104 +- main/app/sprinkles/core/locale/fa/messages.php | 220 +- main/app/sprinkles/core/locale/fa/validate.php | 62 +- main/app/sprinkles/core/locale/fr_FR/main.php | 40 +- main/app/sprinkles/core/locale/fr_FR/messages.php | 208 +- main/app/sprinkles/core/locale/fr_FR/validate.php | 64 +- main/app/sprinkles/core/locale/it_IT/messages.php | 246 +- main/app/sprinkles/core/locale/it_IT/validate.php | 64 +- main/app/sprinkles/core/locale/pt_PT/messages.php | 204 +- main/app/sprinkles/core/locale/pt_PT/validate.php | 50 +- main/app/sprinkles/core/locale/ru_RU/errors.php | 102 +- main/app/sprinkles/core/locale/ru_RU/messages.php | 240 +- main/app/sprinkles/core/locale/ru_RU/validate.php | 66 +- main/app/sprinkles/core/locale/th_TH/errors.php | 102 +- main/app/sprinkles/core/locale/th_TH/messages.php | 204 +- main/app/sprinkles/core/locale/th_TH/validate.php | 50 +- main/app/sprinkles/core/locale/tlh/errors.php | 106 +- main/app/sprinkles/core/locale/tlh/main.php | 40 +- main/app/sprinkles/core/locale/tlh/validate.php | 64 +- main/app/sprinkles/core/locale/valitron/ar.php | 56 +- main/app/sprinkles/core/locale/valitron/de.php | 66 +- main/app/sprinkles/core/locale/valitron/el.php | 68 +- main/app/sprinkles/core/locale/valitron/en.php | 68 +- main/app/sprinkles/core/locale/valitron/es.php | 68 +- main/app/sprinkles/core/locale/valitron/fr.php | 68 +- main/app/sprinkles/core/locale/valitron/id.php | 66 +- main/app/sprinkles/core/locale/valitron/it.php | 62 +- main/app/sprinkles/core/locale/valitron/ja.php | 66 +- main/app/sprinkles/core/locale/valitron/lv.php | 62 +- main/app/sprinkles/core/locale/valitron/pt-br.php | 56 +- main/app/sprinkles/core/locale/valitron/ro.php | 66 +- main/app/sprinkles/core/locale/valitron/ru.php | 66 +- main/app/sprinkles/core/locale/valitron/th.php | 68 +- main/app/sprinkles/core/locale/valitron/zh-cn.php | 56 +- main/app/sprinkles/core/locale/valitron/zh-tw.php | 56 +- main/app/sprinkles/core/locale/zh_CN/messages.php | 210 +- main/app/sprinkles/core/locale/zh_CN/validate.php | 58 +- main/app/sprinkles/core/routes/routes.php | 54 +- main/app/sprinkles/core/src/Alert/AlertStream.php | 276 +- .../sprinkles/core/src/Alert/CacheAlertStream.php | 162 +- .../core/src/Alert/SessionAlertStream.php | 134 +- .../core/src/Controller/SimpleController.php | 72 +- main/app/sprinkles/core/src/Core.php | 236 +- main/app/sprinkles/core/src/Database/Builder.php | 400 +- .../core/src/Database/DatabaseInvalidException.php | 42 +- .../src/Database/Migrations/v400/SessionsTable.php | 94 +- .../Database/Migrations/v400/ThrottlesTable.php | 102 +- .../Database/Models/Concerns/HasRelationships.php | 544 +- .../sprinkles/core/src/Database/Models/Model.php | 266 +- .../core/src/Database/Models/Throttle.php | 74 +- .../Relations/BelongsToManyConstrained.php | 236 +- .../Database/Relations/BelongsToManyThrough.php | 446 +- .../src/Database/Relations/BelongsToManyUnique.php | 46 +- .../src/Database/Relations/Concerns/Syncable.php | 260 +- .../src/Database/Relations/Concerns/Unique.php | 1086 +- .../src/Database/Relations/HasManySyncable.php | 46 +- .../src/Database/Relations/MorphManySyncable.php | 46 +- .../src/Database/Relations/MorphToManyUnique.php | 46 +- .../core/src/Error/ExceptionHandlerManager.php | 182 +- .../core/src/Error/Handler/ExceptionHandler.php | 534 +- .../Error/Handler/ExceptionHandlerInterface.php | 66 +- .../src/Error/Handler/HttpExceptionHandler.php | 124 +- .../src/Error/Handler/NotFoundExceptionHandler.php | 76 +- .../Error/Handler/PhpMailerExceptionHandler.php | 60 +- .../core/src/Error/Renderer/ErrorRenderer.php | 126 +- .../src/Error/Renderer/ErrorRendererInterface.php | 60 +- .../core/src/Error/Renderer/HtmlRenderer.php | 294 +- .../core/src/Error/Renderer/JsonRenderer.php | 110 +- .../core/src/Error/Renderer/PlainTextRenderer.php | 126 +- .../core/src/Error/Renderer/WhoopsRenderer.php | 1376 +- .../core/src/Error/Renderer/XmlRenderer.php | 94 +- main/app/sprinkles/core/src/Facades/Debug.php | 56 +- main/app/sprinkles/core/src/Facades/Translator.php | 56 +- .../src/Http/Concerns/DeterminesContentType.php | 152 +- .../app/sprinkles/core/src/Log/DatabaseHandler.php | 104 +- main/app/sprinkles/core/src/Log/MixedFormatter.php | 116 +- .../app/sprinkles/core/src/Mail/EmailRecipient.php | 258 +- main/app/sprinkles/core/src/Mail/MailMessage.php | 350 +- main/app/sprinkles/core/src/Mail/Mailer.php | 400 +- .../sprinkles/core/src/Mail/StaticMailMessage.php | 148 +- .../sprinkles/core/src/Mail/TwigMailMessage.php | 178 +- main/app/sprinkles/core/src/Model/UFModel.php | 54 +- main/app/sprinkles/core/src/Router.php | 200 +- .../core/src/ServicesProvider/ServicesProvider.php | 1242 +- main/app/sprinkles/core/src/Sprunje/Sprunje.php | 1094 +- .../sprinkles/core/src/Throttle/ThrottleRule.php | 266 +- main/app/sprinkles/core/src/Throttle/Throttler.php | 344 +- .../core/src/Throttle/ThrottlerException.php | 38 +- main/app/sprinkles/core/src/Twig/CacheHelper.php | 114 +- main/app/sprinkles/core/src/Twig/CoreExtension.php | 240 +- .../core/src/Util/BadClassNameException.php | 38 +- main/app/sprinkles/core/src/Util/Captcha.php | 308 +- .../sprinkles/core/src/Util/CheckEnvironment.php | 662 +- main/app/sprinkles/core/src/Util/ClassMapper.php | 180 +- .../sprinkles/core/src/Util/EnvironmentInfo.php | 134 +- .../sprinkles/core/src/Util/ShutdownHandler.php | 324 +- main/app/sprinkles/core/src/Util/Util.php | 348 +- .../sprinkles/core/templates/forms/csrf.html.twig | 4 +- .../core/templates/navigation/breadcrumb.html.twig | 6 +- .../core/templates/navigation/main-nav.html.twig | 62 +- .../sprinkles/core/templates/pages/about.html.twig | 370 +- .../core/templates/pages/abstract/base.html.twig | 196 +- .../templates/pages/abstract/default.html.twig | 94 +- .../core/templates/pages/abstract/error.html.twig | 68 +- .../templates/pages/abstract/mainsite.html.twig | 290 +- .../templates/pages/error/config-errors.html.twig | 44 +- .../sprinkles/core/templates/pages/index.html.twig | 338 +- .../sprinkles/core/templates/pages/legal.html.twig | 24 +- .../templates/pages/partials/analytics.html.twig | 44 +- .../core/templates/pages/partials/config.js.twig | 26 +- .../templates/pages/partials/favicons.html.twig | 102 +- .../core/templates/pages/partials/footer.html.twig | 16 +- .../core/templates/pages/partials/legal.html.twig | 234 +- .../core/templates/pages/partials/page.js.twig | 8 +- .../templates/pages/partials/privacy.html.twig | 90 +- .../core/templates/pages/privacy.html.twig | 24 +- .../sprinkles/core/templates/pages/test.html.twig | 80 +- .../templates/tables/table-paginated.html.twig | 128 +- .../templates/tables/table-tool-menu.html.twig | 54 +- .../core/tests/Integration/DatabaseTests.php | 2542 +- .../core/tests/Unit/BelongsToManyThroughTest.php | 202 +- .../core/tests/Unit/DatabaseSyncableTest.php | 228 +- main/app/sprinkles/core/tests/Unit/SprunjeTest.php | 192 +- 209 files changed, 61403 insertions(+), 61406 deletions(-) (limited to 'main/app/sprinkles/core') diff --git a/main/app/sprinkles/core/asset-bundles.json b/main/app/sprinkles/core/asset-bundles.json index b62df84..366c50f 100644 --- a/main/app/sprinkles/core/asset-bundles.json +++ b/main/app/sprinkles/core/asset-bundles.json @@ -1,140 +1,140 @@ -{ - "bundle": { - "js/main": { - "scripts": [ - "SiteAssets/js/jquery.js", - "vendor/bootstrap/dist/js/bootstrap.js", - "vendor/handlebars/handlebars.js", - "vendor/jquery-validation/dist/jquery.validate.js", - "vendor/jquery-validation/dist/additional-methods.js", - "vendor/jquery-slimscroll/jquery.slimscroll.js", - "vendor/icheck/icheck.min.js", - "vendor/fastclick/lib/fastclick.js", - "vendor/select2/dist/js/select2.full.js", - "vendor/clipboard/dist/clipboard.js", - "userfrosting/js/attrchange.js", - "userfrosting/js/AdminLTE.js", - "userfrosting/js/AdminLTE-custom.js", - "userfrosting/js/fortress-jqueryvalidation-methods.js", - "userfrosting/js/uf-jqueryvalidation-config.js", - "userfrosting/js/uf-alerts.js", - "userfrosting/js/uf-form.js", - "userfrosting/js/uf-modal.js", - "userfrosting/js/uf-copy.js", - "userfrosting/js/uf-init.js" - ], - "options": { - "result": { - "type": { - "scripts": "plain" - } - } - } - }, - "js/form-widgets": { - "scripts": [ - "vendor/speakingurl/speakingurl.min.js", - "userfrosting/js/uf-collection.js" - ], - "options": { - "result": { - "type": { - "scripts": "plain" - } - } - } - }, - "js/main-site": { - "scripts": [ - "SiteAssets/js/console.js", - "SiteAssets/js/fontawesome.js", - "SiteAssets/js/linkify.js", - "SiteAssets/js/encryption.js", - "SiteAssets/js/swiper.js", - "SiteAssets/js/popups.js", - "SiteAssets/js/push.js", - "SiteAssets/js/chat.js", - "SiteAssets/js/main.js" - ], - "options": { - "result": { - "type": { - "scripts": "plain" - } - } - } - }, - "css/main": { - "styles": [ - "vendor/font-awesome/css/font-awesome.css", - "vendor/bootstrap/dist/css/bootstrap.css", - "vendor/select2/dist/css/select2.css", - "vendor/icheck/skins/square/_all.css", - "vendor/ionicons/css/ionicons.css", - "userfrosting/css/uf-jqueryvalidation.css", - "userfrosting/css/uf-alerts.css", - "userfrosting/css/AdminLTE.css", - "userfrosting/css/AdminLTE-skins-all.css", - "userfrosting/css/userfrosting.css" - ], - "options": { - "result": { - "type": { - "styles": "plain" - } - } - } - }, - "css/form-widgets": { - "styles": [ - "userfrosting/css/uf-collection.css" - ], - "options": { - "result": { - "type": { - "styles": "plain" - } - } - } - }, - "css/main-site": { - "styles": [ - "SiteAssets/css/normalize.css", - "SiteAssets/css/swiper.css", - "SiteAssets/css/animate.css", - "SiteAssets/css/main.css" - ], - "options": { - "result": { - "type": { - "styles": "plain" - } - } - } - }, - "css/DarkTheme": { - "styles": [ - "SiteAssets/css/DarkTheme.css" - ], - "options": { - "result": { - "type": { - "styles": "plain" - } - } - } - }, - "css/LightTheme": { - "styles": [ - "SiteAssets/css/LightTheme.css" - ], - "options": { - "result": { - "type": { - "styles": "plain" - } - } - } - } - } -} +{ + "bundle": { + "js/main": { + "scripts": [ + "SiteAssets/js/jquery.js", + "vendor/bootstrap/dist/js/bootstrap.js", + "vendor/handlebars/handlebars.js", + "vendor/jquery-validation/dist/jquery.validate.js", + "vendor/jquery-validation/dist/additional-methods.js", + "vendor/jquery-slimscroll/jquery.slimscroll.js", + "vendor/icheck/icheck.min.js", + "vendor/fastclick/lib/fastclick.js", + "vendor/select2/dist/js/select2.full.js", + "vendor/clipboard/dist/clipboard.js", + "userfrosting/js/attrchange.js", + "userfrosting/js/AdminLTE.js", + "userfrosting/js/AdminLTE-custom.js", + "userfrosting/js/fortress-jqueryvalidation-methods.js", + "userfrosting/js/uf-jqueryvalidation-config.js", + "userfrosting/js/uf-alerts.js", + "userfrosting/js/uf-form.js", + "userfrosting/js/uf-modal.js", + "userfrosting/js/uf-copy.js", + "userfrosting/js/uf-init.js" + ], + "options": { + "result": { + "type": { + "scripts": "plain" + } + } + } + }, + "js/form-widgets": { + "scripts": [ + "vendor/speakingurl/speakingurl.min.js", + "userfrosting/js/uf-collection.js" + ], + "options": { + "result": { + "type": { + "scripts": "plain" + } + } + } + }, + "js/main-site": { + "scripts": [ + "SiteAssets/js/console.js", + "SiteAssets/js/fontawesome.js", + "SiteAssets/js/linkify.js", + "SiteAssets/js/encryption.js", + "SiteAssets/js/swiper.js", + "SiteAssets/js/popups.js", + "SiteAssets/js/push.js", + "SiteAssets/js/chat.js", + "SiteAssets/js/main.js" + ], + "options": { + "result": { + "type": { + "scripts": "plain" + } + } + } + }, + "css/main": { + "styles": [ + "vendor/font-awesome/css/font-awesome.css", + "vendor/bootstrap/dist/css/bootstrap.css", + "vendor/select2/dist/css/select2.css", + "vendor/icheck/skins/square/_all.css", + "vendor/ionicons/css/ionicons.css", + "userfrosting/css/uf-jqueryvalidation.css", + "userfrosting/css/uf-alerts.css", + "userfrosting/css/AdminLTE.css", + "userfrosting/css/AdminLTE-skins-all.css", + "userfrosting/css/userfrosting.css" + ], + "options": { + "result": { + "type": { + "styles": "plain" + } + } + } + }, + "css/form-widgets": { + "styles": [ + "userfrosting/css/uf-collection.css" + ], + "options": { + "result": { + "type": { + "styles": "plain" + } + } + } + }, + "css/main-site": { + "styles": [ + "SiteAssets/css/normalize.css", + "SiteAssets/css/swiper.css", + "SiteAssets/css/animate.css", + "SiteAssets/css/main.css" + ], + "options": { + "result": { + "type": { + "styles": "plain" + } + } + } + }, + "css/DarkTheme": { + "styles": [ + "SiteAssets/css/DarkTheme.css" + ], + "options": { + "result": { + "type": { + "styles": "plain" + } + } + } + }, + "css/LightTheme": { + "styles": [ + "SiteAssets/css/LightTheme.css" + ], + "options": { + "result": { + "type": { + "styles": "plain" + } + } + } + } + } +} diff --git a/main/app/sprinkles/core/assets/SiteAssets/css/DarkTheme.css b/main/app/sprinkles/core/assets/SiteAssets/css/DarkTheme.css index 84c1b82..9c95617 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/css/DarkTheme.css +++ b/main/app/sprinkles/core/assets/SiteAssets/css/DarkTheme.css @@ -1,101 +1,101 @@ -html, body { - background-color: #0c1d34; - color: #426A91; -} - -a { - color: #4a93c0; -} - -hr { - border-top: 1px solid #112a42; -} - -img { - pointer-events: none; -} - -.main-carousel { - background: #EEE; -} - -.carousel-cell { - background: #0c1d34; -} - -.LeftButtonHeader { - filter: invert(.5); - -webkit-filter: invert(.5); - -moz-filter: invert(.5); -} - -.HeaderCaption { - color: lightgrey; -} - -.RightButtonHeader { - filter: invert(.5); - -webkit-filter: invert(.5); - -moz-filter: invert(.5); -} - -.UserSearchBar { - color: #f3f4f5; - background-color: #13223C; -} - -.SearchResults .full_name { - grid-column-start: 3; - justify-self: center; /* OR start */ - align-self: center; -} - -.ServerChatMessage { - background: linear-gradient(to right, #ad4eff, #7c41f9); - color: #FFF; -} - -.TypingIndicatorMessage { - background-color: #13223c; - color: #a7a8a9; -} - -.MessageSent { - background-color: #12213b; - color: #537eaf; -} - -.MessageReceived { - background-color: #13223c; - color: #a7a8a9; -} - -.ChatInput { - color: #f3f4f5; - background-color: #13223C; -} - -.spinner > div { - background-color: #a7a8a9; -} - -.GenderFab { - color: white; -} - -.GenderFab.Female { - background: linear-gradient(to right, #ff7a88, #ff9676); -} - -.GenderFab.Male { - background: linear-gradient(to right, #11c1d5, #1ddcb6); -} - -.Navbar { - background-color: #13223c; -} - -.NavbarLine { - background: #eb12b5; -} - +html, body { + background-color: #0c1d34; + color: #426A91; +} + +a { + color: #4a93c0; +} + +hr { + border-top: 1px solid #112a42; +} + +img { + pointer-events: none; +} + +.main-carousel { + background: #EEE; +} + +.carousel-cell { + background: #0c1d34; +} + +.LeftButtonHeader { + filter: invert(.5); + -webkit-filter: invert(.5); + -moz-filter: invert(.5); +} + +.HeaderCaption { + color: lightgrey; +} + +.RightButtonHeader { + filter: invert(.5); + -webkit-filter: invert(.5); + -moz-filter: invert(.5); +} + +.UserSearchBar { + color: #f3f4f5; + background-color: #13223C; +} + +.SearchResults .full_name { + grid-column-start: 3; + justify-self: center; /* OR start */ + align-self: center; +} + +.ServerChatMessage { + background: linear-gradient(to right, #ad4eff, #7c41f9); + color: #FFF; +} + +.TypingIndicatorMessage { + background-color: #13223c; + color: #a7a8a9; +} + +.MessageSent { + background-color: #12213b; + color: #537eaf; +} + +.MessageReceived { + background-color: #13223c; + color: #a7a8a9; +} + +.ChatInput { + color: #f3f4f5; + background-color: #13223C; +} + +.spinner > div { + background-color: #a7a8a9; +} + +.GenderFab { + color: white; +} + +.GenderFab.Female { + background: linear-gradient(to right, #ff7a88, #ff9676); +} + +.GenderFab.Male { + background: linear-gradient(to right, #11c1d5, #1ddcb6); +} + +.Navbar { + background-color: #13223c; +} + +.NavbarLine { + background: #eb12b5; +} + diff --git a/main/app/sprinkles/core/assets/SiteAssets/css/LightTheme.css b/main/app/sprinkles/core/assets/SiteAssets/css/LightTheme.css index 36508b3..8b511f2 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/css/LightTheme.css +++ b/main/app/sprinkles/core/assets/SiteAssets/css/LightTheme.css @@ -1,104 +1,104 @@ -html, body { - background-color: #fdfeff; - color: #426A91; -} - -a { - color: #4a93c0; -} - -hr { - border-top: 1px solid #e7e7e7; -} - -img { - pointer-events: none; -} - -.main-carousel { - background: #EEE; -} - -.carousel-cell { - background: #FDFEFF; -} - -.LeftButtonHeader { - filter: invert(.5); - -webkit-filter: invert(.5); - -moz-filter: invert(.5); -} - -.HeaderCaption { - color: #888888; -} - -.RightButtonHeader { - filter: invert(.5); - -webkit-filter: invert(.5); - -moz-filter: invert(.5); -} - -.UserSearchBar { - color: #f3f4f5; - background-color: #c8c9ca; -} - -.SearchResults .full_name { - grid-column-start: 3; - justify-self: center; /* OR start */ - align-self: center; -} - -.ServerChatMessage { - background: linear-gradient(to right, #ad4eff, #7c41f9); - color: #FFF; -} - -.TypingIndicatorMessage { - background-color: #DFDFDF; - color: #a7a8a9; -} - -.MessageSent { - background-color: #376cf4; - color: #efefef; -} - -.MessageReceived { - background-color: #dfdfdf; - color: #6a6b6c; -} - -.ChatInput { - color: #393a3b; - background-color: #c8c9ca; -} - -.spinner > div { - background-color: #98999a; -} - -.GenderFab { - color: white; -} - -.GenderFab.Female { - background: linear-gradient(to right, #ff7a88, #ff9676); -} - -.GenderFab.Male { - background: linear-gradient(to right, #11c1d5, #1ddcb6); -} - -.Navbar { - background-color: #FDFEFF; - -webkit-box-shadow: 0 -1px 5px rgba(50, 50, 50, 0.3); - -moz-box-shadow: 0 -1px 5px rgba(50, 50, 50, 0.3); - box-shadow: 0 -1px 5px rgba(50, 50, 50, 0.3); -} - -.NavbarLine { - background: #eb12b5; -} - +html, body { + background-color: #fdfeff; + color: #426A91; +} + +a { + color: #4a93c0; +} + +hr { + border-top: 1px solid #e7e7e7; +} + +img { + pointer-events: none; +} + +.main-carousel { + background: #EEE; +} + +.carousel-cell { + background: #FDFEFF; +} + +.LeftButtonHeader { + filter: invert(.5); + -webkit-filter: invert(.5); + -moz-filter: invert(.5); +} + +.HeaderCaption { + color: #888888; +} + +.RightButtonHeader { + filter: invert(.5); + -webkit-filter: invert(.5); + -moz-filter: invert(.5); +} + +.UserSearchBar { + color: #f3f4f5; + background-color: #c8c9ca; +} + +.SearchResults .full_name { + grid-column-start: 3; + justify-self: center; /* OR start */ + align-self: center; +} + +.ServerChatMessage { + background: linear-gradient(to right, #ad4eff, #7c41f9); + color: #FFF; +} + +.TypingIndicatorMessage { + background-color: #DFDFDF; + color: #a7a8a9; +} + +.MessageSent { + background-color: #376cf4; + color: #efefef; +} + +.MessageReceived { + background-color: #dfdfdf; + color: #6a6b6c; +} + +.ChatInput { + color: #393a3b; + background-color: #c8c9ca; +} + +.spinner > div { + background-color: #98999a; +} + +.GenderFab { + color: white; +} + +.GenderFab.Female { + background: linear-gradient(to right, #ff7a88, #ff9676); +} + +.GenderFab.Male { + background: linear-gradient(to right, #11c1d5, #1ddcb6); +} + +.Navbar { + background-color: #FDFEFF; + -webkit-box-shadow: 0 -1px 5px rgba(50, 50, 50, 0.3); + -moz-box-shadow: 0 -1px 5px rgba(50, 50, 50, 0.3); + box-shadow: 0 -1px 5px rgba(50, 50, 50, 0.3); +} + +.NavbarLine { + background: #eb12b5; +} + diff --git a/main/app/sprinkles/core/assets/SiteAssets/css/animate.css b/main/app/sprinkles/core/assets/SiteAssets/css/animate.css index 6f01a37..a739d89 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/css/animate.css +++ b/main/app/sprinkles/core/assets/SiteAssets/css/animate.css @@ -1,3514 +1,3514 @@ -@charset "UTF-8"; - -/*! - * animate.css -http://daneden.me/animate - * Version - 3.6.0 - * Licensed under the MIT license - http://opensource.org/licenses/MIT - * - * Copyright (c) 2018 Daniel Eden - */ - -.animated { - -webkit-animation-duration: 1s; - animation-duration: 1s; - -webkit-animation-fill-mode: both; - animation-fill-mode: both; -} - -.animated.infinite { - -webkit-animation-iteration-count: infinite; - animation-iteration-count: infinite; -} - -@-webkit-keyframes bounce { - from, - 20%, - 53%, - 80%, - to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 40%, - 43% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - -webkit-transform: translate3d(0, -30px, 0); - transform: translate3d(0, -30px, 0); - } - - 70% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - -webkit-transform: translate3d(0, -15px, 0); - transform: translate3d(0, -15px, 0); - } - - 90% { - -webkit-transform: translate3d(0, -4px, 0); - transform: translate3d(0, -4px, 0); - } -} - -@keyframes bounce { - from, - 20%, - 53%, - 80%, - to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 40%, - 43% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - -webkit-transform: translate3d(0, -30px, 0); - transform: translate3d(0, -30px, 0); - } - - 70% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - -webkit-transform: translate3d(0, -15px, 0); - transform: translate3d(0, -15px, 0); - } - - 90% { - -webkit-transform: translate3d(0, -4px, 0); - transform: translate3d(0, -4px, 0); - } -} - -.bounce { - -webkit-animation-name: bounce; - animation-name: bounce; - -webkit-transform-origin: center bottom; - transform-origin: center bottom; -} - -@-webkit-keyframes flash { - from, - 50%, - to { - opacity: 1; - } - - 25%, - 75% { - opacity: 0; - } -} - -@keyframes flash { - from, - 50%, - to { - opacity: 1; - } - - 25%, - 75% { - opacity: 0; - } -} - -.flash { - -webkit-animation-name: flash; - animation-name: flash; -} - -/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ - -@-webkit-keyframes pulse { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 50% { - -webkit-transform: scale3d(1.05, 1.05, 1.05); - transform: scale3d(1.05, 1.05, 1.05); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -@keyframes pulse { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 50% { - -webkit-transform: scale3d(1.05, 1.05, 1.05); - transform: scale3d(1.05, 1.05, 1.05); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -.pulse { - -webkit-animation-name: pulse; - animation-name: pulse; -} - -@-webkit-keyframes rubberBand { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 30% { - -webkit-transform: scale3d(1.25, 0.75, 1); - transform: scale3d(1.25, 0.75, 1); - } - - 40% { - -webkit-transform: scale3d(0.75, 1.25, 1); - transform: scale3d(0.75, 1.25, 1); - } - - 50% { - -webkit-transform: scale3d(1.15, 0.85, 1); - transform: scale3d(1.15, 0.85, 1); - } - - 65% { - -webkit-transform: scale3d(0.95, 1.05, 1); - transform: scale3d(0.95, 1.05, 1); - } - - 75% { - -webkit-transform: scale3d(1.05, 0.95, 1); - transform: scale3d(1.05, 0.95, 1); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -@keyframes rubberBand { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 30% { - -webkit-transform: scale3d(1.25, 0.75, 1); - transform: scale3d(1.25, 0.75, 1); - } - - 40% { - -webkit-transform: scale3d(0.75, 1.25, 1); - transform: scale3d(0.75, 1.25, 1); - } - - 50% { - -webkit-transform: scale3d(1.15, 0.85, 1); - transform: scale3d(1.15, 0.85, 1); - } - - 65% { - -webkit-transform: scale3d(0.95, 1.05, 1); - transform: scale3d(0.95, 1.05, 1); - } - - 75% { - -webkit-transform: scale3d(1.05, 0.95, 1); - transform: scale3d(1.05, 0.95, 1); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -.rubberBand { - -webkit-animation-name: rubberBand; - animation-name: rubberBand; -} - -@-webkit-keyframes shake { - from, - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 10%, - 30%, - 50%, - 70%, - 90% { - -webkit-transform: translate3d(-10px, 0, 0); - transform: translate3d(-10px, 0, 0); - } - - 20%, - 40%, - 60%, - 80% { - -webkit-transform: translate3d(10px, 0, 0); - transform: translate3d(10px, 0, 0); - } -} - -@keyframes shake { - from, - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 10%, - 30%, - 50%, - 70%, - 90% { - -webkit-transform: translate3d(-10px, 0, 0); - transform: translate3d(-10px, 0, 0); - } - - 20%, - 40%, - 60%, - 80% { - -webkit-transform: translate3d(10px, 0, 0); - transform: translate3d(10px, 0, 0); - } -} - -.shake { - -webkit-animation-name: shake; - animation-name: shake; -} - -@-webkit-keyframes headShake { - 0% { - -webkit-transform: translateX(0); - transform: translateX(0); - } - - 6.5% { - -webkit-transform: translateX(-6px) rotateY(-9deg); - transform: translateX(-6px) rotateY(-9deg); - } - - 18.5% { - -webkit-transform: translateX(5px) rotateY(7deg); - transform: translateX(5px) rotateY(7deg); - } - - 31.5% { - -webkit-transform: translateX(-3px) rotateY(-5deg); - transform: translateX(-3px) rotateY(-5deg); - } - - 43.5% { - -webkit-transform: translateX(2px) rotateY(3deg); - transform: translateX(2px) rotateY(3deg); - } - - 50% { - -webkit-transform: translateX(0); - transform: translateX(0); - } -} - -@keyframes headShake { - 0% { - -webkit-transform: translateX(0); - transform: translateX(0); - } - - 6.5% { - -webkit-transform: translateX(-6px) rotateY(-9deg); - transform: translateX(-6px) rotateY(-9deg); - } - - 18.5% { - -webkit-transform: translateX(5px) rotateY(7deg); - transform: translateX(5px) rotateY(7deg); - } - - 31.5% { - -webkit-transform: translateX(-3px) rotateY(-5deg); - transform: translateX(-3px) rotateY(-5deg); - } - - 43.5% { - -webkit-transform: translateX(2px) rotateY(3deg); - transform: translateX(2px) rotateY(3deg); - } - - 50% { - -webkit-transform: translateX(0); - transform: translateX(0); - } -} - -.headShake { - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - -webkit-animation-name: headShake; - animation-name: headShake; -} - -@-webkit-keyframes swing { - 20% { - -webkit-transform: rotate3d(0, 0, 1, 15deg); - transform: rotate3d(0, 0, 1, 15deg); - } - - 40% { - -webkit-transform: rotate3d(0, 0, 1, -10deg); - transform: rotate3d(0, 0, 1, -10deg); - } - - 60% { - -webkit-transform: rotate3d(0, 0, 1, 5deg); - transform: rotate3d(0, 0, 1, 5deg); - } - - 80% { - -webkit-transform: rotate3d(0, 0, 1, -5deg); - transform: rotate3d(0, 0, 1, -5deg); - } - - to { - -webkit-transform: rotate3d(0, 0, 1, 0deg); - transform: rotate3d(0, 0, 1, 0deg); - } -} - -@keyframes swing { - 20% { - -webkit-transform: rotate3d(0, 0, 1, 15deg); - transform: rotate3d(0, 0, 1, 15deg); - } - - 40% { - -webkit-transform: rotate3d(0, 0, 1, -10deg); - transform: rotate3d(0, 0, 1, -10deg); - } - - 60% { - -webkit-transform: rotate3d(0, 0, 1, 5deg); - transform: rotate3d(0, 0, 1, 5deg); - } - - 80% { - -webkit-transform: rotate3d(0, 0, 1, -5deg); - transform: rotate3d(0, 0, 1, -5deg); - } - - to { - -webkit-transform: rotate3d(0, 0, 1, 0deg); - transform: rotate3d(0, 0, 1, 0deg); - } -} - -.swing { - -webkit-transform-origin: top center; - transform-origin: top center; - -webkit-animation-name: swing; - animation-name: swing; -} - -@-webkit-keyframes tada { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 10%, - 20% { - -webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); - transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); - } - - 30%, - 50%, - 70%, - 90% { - -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); - transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); - } - - 40%, - 60%, - 80% { - -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); - transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -@keyframes tada { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 10%, - 20% { - -webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); - transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); - } - - 30%, - 50%, - 70%, - 90% { - -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); - transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); - } - - 40%, - 60%, - 80% { - -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); - transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -.tada { - -webkit-animation-name: tada; - animation-name: tada; -} - -/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ - -@-webkit-keyframes wobble { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 15% { - -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); - transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); - } - - 30% { - -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); - transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); - } - - 45% { - -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); - transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); - } - - 60% { - -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); - transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); - } - - 75% { - -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); - transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes wobble { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 15% { - -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); - transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); - } - - 30% { - -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); - transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); - } - - 45% { - -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); - transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); - } - - 60% { - -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); - transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); - } - - 75% { - -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); - transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.wobble { - -webkit-animation-name: wobble; - animation-name: wobble; -} - -@-webkit-keyframes jello { - from, - 11.1%, - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 22.2% { - -webkit-transform: skewX(-12.5deg) skewY(-12.5deg); - transform: skewX(-12.5deg) skewY(-12.5deg); - } - - 33.3% { - -webkit-transform: skewX(6.25deg) skewY(6.25deg); - transform: skewX(6.25deg) skewY(6.25deg); - } - - 44.4% { - -webkit-transform: skewX(-3.125deg) skewY(-3.125deg); - transform: skewX(-3.125deg) skewY(-3.125deg); - } - - 55.5% { - -webkit-transform: skewX(1.5625deg) skewY(1.5625deg); - transform: skewX(1.5625deg) skewY(1.5625deg); - } - - 66.6% { - -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg); - transform: skewX(-0.78125deg) skewY(-0.78125deg); - } - - 77.7% { - -webkit-transform: skewX(0.390625deg) skewY(0.390625deg); - transform: skewX(0.390625deg) skewY(0.390625deg); - } - - 88.8% { - -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg); - transform: skewX(-0.1953125deg) skewY(-0.1953125deg); - } -} - -@keyframes jello { - from, - 11.1%, - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 22.2% { - -webkit-transform: skewX(-12.5deg) skewY(-12.5deg); - transform: skewX(-12.5deg) skewY(-12.5deg); - } - - 33.3% { - -webkit-transform: skewX(6.25deg) skewY(6.25deg); - transform: skewX(6.25deg) skewY(6.25deg); - } - - 44.4% { - -webkit-transform: skewX(-3.125deg) skewY(-3.125deg); - transform: skewX(-3.125deg) skewY(-3.125deg); - } - - 55.5% { - -webkit-transform: skewX(1.5625deg) skewY(1.5625deg); - transform: skewX(1.5625deg) skewY(1.5625deg); - } - - 66.6% { - -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg); - transform: skewX(-0.78125deg) skewY(-0.78125deg); - } - - 77.7% { - -webkit-transform: skewX(0.390625deg) skewY(0.390625deg); - transform: skewX(0.390625deg) skewY(0.390625deg); - } - - 88.8% { - -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg); - transform: skewX(-0.1953125deg) skewY(-0.1953125deg); - } -} - -.jello { - -webkit-animation-name: jello; - animation-name: jello; - -webkit-transform-origin: center; - transform-origin: center; -} - -@-webkit-keyframes bounceIn { - from, - 20%, - 40%, - 60%, - 80%, - to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - } - - 0% { - opacity: 0; - -webkit-transform: scale3d(0.3, 0.3, 0.3); - transform: scale3d(0.3, 0.3, 0.3); - } - - 20% { - -webkit-transform: scale3d(1.1, 1.1, 1.1); - transform: scale3d(1.1, 1.1, 1.1); - } - - 40% { - -webkit-transform: scale3d(0.9, 0.9, 0.9); - transform: scale3d(0.9, 0.9, 0.9); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(1.03, 1.03, 1.03); - transform: scale3d(1.03, 1.03, 1.03); - } - - 80% { - -webkit-transform: scale3d(0.97, 0.97, 0.97); - transform: scale3d(0.97, 0.97, 0.97); - } - - to { - opacity: 1; - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -@keyframes bounceIn { - from, - 20%, - 40%, - 60%, - 80%, - to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - } - - 0% { - opacity: 0; - -webkit-transform: scale3d(0.3, 0.3, 0.3); - transform: scale3d(0.3, 0.3, 0.3); - } - - 20% { - -webkit-transform: scale3d(1.1, 1.1, 1.1); - transform: scale3d(1.1, 1.1, 1.1); - } - - 40% { - -webkit-transform: scale3d(0.9, 0.9, 0.9); - transform: scale3d(0.9, 0.9, 0.9); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(1.03, 1.03, 1.03); - transform: scale3d(1.03, 1.03, 1.03); - } - - 80% { - -webkit-transform: scale3d(0.97, 0.97, 0.97); - transform: scale3d(0.97, 0.97, 0.97); - } - - to { - opacity: 1; - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -.bounceIn { - -webkit-animation-duration: 0.75s; - animation-duration: 0.75s; - -webkit-animation-name: bounceIn; - animation-name: bounceIn; -} - -@-webkit-keyframes bounceInDown { - from, - 60%, - 75%, - 90%, - to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - } - - 0% { - opacity: 0; - -webkit-transform: translate3d(0, -3000px, 0); - transform: translate3d(0, -3000px, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(0, 25px, 0); - transform: translate3d(0, 25px, 0); - } - - 75% { - -webkit-transform: translate3d(0, -10px, 0); - transform: translate3d(0, -10px, 0); - } - - 90% { - -webkit-transform: translate3d(0, 5px, 0); - transform: translate3d(0, 5px, 0); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes bounceInDown { - from, - 60%, - 75%, - 90%, - to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - } - - 0% { - opacity: 0; - -webkit-transform: translate3d(0, -3000px, 0); - transform: translate3d(0, -3000px, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(0, 25px, 0); - transform: translate3d(0, 25px, 0); - } - - 75% { - -webkit-transform: translate3d(0, -10px, 0); - transform: translate3d(0, -10px, 0); - } - - 90% { - -webkit-transform: translate3d(0, 5px, 0); - transform: translate3d(0, 5px, 0); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.bounceInDown { - -webkit-animation-name: bounceInDown; - animation-name: bounceInDown; -} - -@-webkit-keyframes bounceInLeft { - from, - 60%, - 75%, - 90%, - to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - } - - 0% { - opacity: 0; - -webkit-transform: translate3d(-3000px, 0, 0); - transform: translate3d(-3000px, 0, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(25px, 0, 0); - transform: translate3d(25px, 0, 0); - } - - 75% { - -webkit-transform: translate3d(-10px, 0, 0); - transform: translate3d(-10px, 0, 0); - } - - 90% { - -webkit-transform: translate3d(5px, 0, 0); - transform: translate3d(5px, 0, 0); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes bounceInLeft { - from, - 60%, - 75%, - 90%, - to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - } - - 0% { - opacity: 0; - -webkit-transform: translate3d(-3000px, 0, 0); - transform: translate3d(-3000px, 0, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(25px, 0, 0); - transform: translate3d(25px, 0, 0); - } - - 75% { - -webkit-transform: translate3d(-10px, 0, 0); - transform: translate3d(-10px, 0, 0); - } - - 90% { - -webkit-transform: translate3d(5px, 0, 0); - transform: translate3d(5px, 0, 0); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.bounceInLeft { - -webkit-animation-name: bounceInLeft; - animation-name: bounceInLeft; -} - -@-webkit-keyframes bounceInRight { - from, - 60%, - 75%, - 90%, - to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - } - - from { - opacity: 0; - -webkit-transform: translate3d(3000px, 0, 0); - transform: translate3d(3000px, 0, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(-25px, 0, 0); - transform: translate3d(-25px, 0, 0); - } - - 75% { - -webkit-transform: translate3d(10px, 0, 0); - transform: translate3d(10px, 0, 0); - } - - 90% { - -webkit-transform: translate3d(-5px, 0, 0); - transform: translate3d(-5px, 0, 0); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes bounceInRight { - from, - 60%, - 75%, - 90%, - to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - } - - from { - opacity: 0; - -webkit-transform: translate3d(3000px, 0, 0); - transform: translate3d(3000px, 0, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(-25px, 0, 0); - transform: translate3d(-25px, 0, 0); - } - - 75% { - -webkit-transform: translate3d(10px, 0, 0); - transform: translate3d(10px, 0, 0); - } - - 90% { - -webkit-transform: translate3d(-5px, 0, 0); - transform: translate3d(-5px, 0, 0); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.bounceInRight { - -webkit-animation-name: bounceInRight; - animation-name: bounceInRight; -} - -@-webkit-keyframes bounceInUp { - from, - 60%, - 75%, - 90%, - to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - } - - from { - opacity: 0; - -webkit-transform: translate3d(0, 3000px, 0); - transform: translate3d(0, 3000px, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(0, -20px, 0); - transform: translate3d(0, -20px, 0); - } - - 75% { - -webkit-transform: translate3d(0, 10px, 0); - transform: translate3d(0, 10px, 0); - } - - 90% { - -webkit-transform: translate3d(0, -5px, 0); - transform: translate3d(0, -5px, 0); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes bounceInUp { - from, - 60%, - 75%, - 90%, - to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - } - - from { - opacity: 0; - -webkit-transform: translate3d(0, 3000px, 0); - transform: translate3d(0, 3000px, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(0, -20px, 0); - transform: translate3d(0, -20px, 0); - } - - 75% { - -webkit-transform: translate3d(0, 10px, 0); - transform: translate3d(0, 10px, 0); - } - - 90% { - -webkit-transform: translate3d(0, -5px, 0); - transform: translate3d(0, -5px, 0); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.bounceInUp { - -webkit-animation-name: bounceInUp; - animation-name: bounceInUp; -} - -@-webkit-keyframes bounceOut { - 20% { - -webkit-transform: scale3d(0.9, 0.9, 0.9); - transform: scale3d(0.9, 0.9, 0.9); - } - - 50%, - 55% { - opacity: 1; - -webkit-transform: scale3d(1.1, 1.1, 1.1); - transform: scale3d(1.1, 1.1, 1.1); - } - - to { - opacity: 0; - -webkit-transform: scale3d(0.3, 0.3, 0.3); - transform: scale3d(0.3, 0.3, 0.3); - } -} - -@keyframes bounceOut { - 20% { - -webkit-transform: scale3d(0.9, 0.9, 0.9); - transform: scale3d(0.9, 0.9, 0.9); - } - - 50%, - 55% { - opacity: 1; - -webkit-transform: scale3d(1.1, 1.1, 1.1); - transform: scale3d(1.1, 1.1, 1.1); - } - - to { - opacity: 0; - -webkit-transform: scale3d(0.3, 0.3, 0.3); - transform: scale3d(0.3, 0.3, 0.3); - } -} - -.bounceOut { - -webkit-animation-duration: 0.75s; - animation-duration: 0.75s; - -webkit-animation-name: bounceOut; - animation-name: bounceOut; -} - -@-webkit-keyframes bounceOutDown { - 20% { - -webkit-transform: translate3d(0, 10px, 0); - transform: translate3d(0, 10px, 0); - } - - 40%, - 45% { - opacity: 1; - -webkit-transform: translate3d(0, -20px, 0); - transform: translate3d(0, -20px, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } -} - -@keyframes bounceOutDown { - 20% { - -webkit-transform: translate3d(0, 10px, 0); - transform: translate3d(0, 10px, 0); - } - - 40%, - 45% { - opacity: 1; - -webkit-transform: translate3d(0, -20px, 0); - transform: translate3d(0, -20px, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } -} - -.bounceOutDown { - -webkit-animation-name: bounceOutDown; - animation-name: bounceOutDown; -} - -@-webkit-keyframes bounceOutLeft { - 20% { - opacity: 1; - -webkit-transform: translate3d(20px, 0, 0); - transform: translate3d(20px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } -} - -@keyframes bounceOutLeft { - 20% { - opacity: 1; - -webkit-transform: translate3d(20px, 0, 0); - transform: translate3d(20px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } -} - -.bounceOutLeft { - -webkit-animation-name: bounceOutLeft; - animation-name: bounceOutLeft; -} - -@-webkit-keyframes bounceOutRight { - 20% { - opacity: 1; - -webkit-transform: translate3d(-20px, 0, 0); - transform: translate3d(-20px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } -} - -@keyframes bounceOutRight { - 20% { - opacity: 1; - -webkit-transform: translate3d(-20px, 0, 0); - transform: translate3d(-20px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } -} - -.bounceOutRight { - -webkit-animation-name: bounceOutRight; - animation-name: bounceOutRight; -} - -@-webkit-keyframes bounceOutUp { - 20% { - -webkit-transform: translate3d(0, -10px, 0); - transform: translate3d(0, -10px, 0); - } - - 40%, - 45% { - opacity: 1; - -webkit-transform: translate3d(0, 20px, 0); - transform: translate3d(0, 20px, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } -} - -@keyframes bounceOutUp { - 20% { - -webkit-transform: translate3d(0, -10px, 0); - transform: translate3d(0, -10px, 0); - } - - 40%, - 45% { - opacity: 1; - -webkit-transform: translate3d(0, 20px, 0); - transform: translate3d(0, 20px, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } -} - -.bounceOutUp { - -webkit-animation-name: bounceOutUp; - animation-name: bounceOutUp; -} - -@-webkit-keyframes fadeIn { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -@keyframes fadeIn { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -.fadeIn { - -webkit-animation-name: fadeIn; - animation-name: fadeIn; -} - -@-webkit-keyframes fadeInDown { - from { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes fadeInDown { - from { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.fadeInDown { - -webkit-animation-name: fadeInDown; - animation-name: fadeInDown; -} - -@-webkit-keyframes fadeInDownBig { - from { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes fadeInDownBig { - from { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.fadeInDownBig { - -webkit-animation-name: fadeInDownBig; - animation-name: fadeInDownBig; -} - -@-webkit-keyframes fadeInLeft { - from { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes fadeInLeft { - from { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.fadeInLeft { - -webkit-animation-name: fadeInLeft; - animation-name: fadeInLeft; -} - -@-webkit-keyframes fadeInLeftBig { - from { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes fadeInLeftBig { - from { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.fadeInLeftBig { - -webkit-animation-name: fadeInLeftBig; - animation-name: fadeInLeftBig; -} - -@-webkit-keyframes fadeInRight { - from { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes fadeInRight { - from { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.fadeInRight { - -webkit-animation-name: fadeInRight; - animation-name: fadeInRight; -} - -@-webkit-keyframes fadeInRightBig { - from { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes fadeInRightBig { - from { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.fadeInRightBig { - -webkit-animation-name: fadeInRightBig; - animation-name: fadeInRightBig; -} - -@-webkit-keyframes fadeInUp { - from { - opacity: 0; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes fadeInUp { - from { - opacity: 0; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.fadeInUp { - -webkit-animation-name: fadeInUp; - animation-name: fadeInUp; -} - -@-webkit-keyframes fadeInUpBig { - from { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes fadeInUpBig { - from { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.fadeInUpBig { - -webkit-animation-name: fadeInUpBig; - animation-name: fadeInUpBig; -} - -@-webkit-keyframes fadeOut { - from { - opacity: 1; - } - - to { - opacity: 0; - } -} - -@keyframes fadeOut { - from { - opacity: 1; - } - - to { - opacity: 0; - } -} - -.fadeOut { - -webkit-animation-name: fadeOut; - animation-name: fadeOut; -} - -@-webkit-keyframes fadeOutDown { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -@keyframes fadeOutDown { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -.fadeOutDown { - -webkit-animation-name: fadeOutDown; - animation-name: fadeOutDown; -} - -@-webkit-keyframes fadeOutDownBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } -} - -@keyframes fadeOutDownBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } -} - -.fadeOutDownBig { - -webkit-animation-name: fadeOutDownBig; - animation-name: fadeOutDownBig; -} - -@-webkit-keyframes fadeOutLeft { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -@keyframes fadeOutLeft { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -.fadeOutLeft { - -webkit-animation-name: fadeOutLeft; - animation-name: fadeOutLeft; -} - -@-webkit-keyframes fadeOutLeftBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } -} - -@keyframes fadeOutLeftBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } -} - -.fadeOutLeftBig { - -webkit-animation-name: fadeOutLeftBig; - animation-name: fadeOutLeftBig; -} - -@-webkit-keyframes fadeOutRight { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -@keyframes fadeOutRight { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -.fadeOutRight { - -webkit-animation-name: fadeOutRight; - animation-name: fadeOutRight; -} - -@-webkit-keyframes fadeOutRightBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } -} - -@keyframes fadeOutRightBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } -} - -.fadeOutRightBig { - -webkit-animation-name: fadeOutRightBig; - animation-name: fadeOutRightBig; -} - -@-webkit-keyframes fadeOutUp { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -@keyframes fadeOutUp { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -.fadeOutUp { - -webkit-animation-name: fadeOutUp; - animation-name: fadeOutUp; -} - -@-webkit-keyframes fadeOutUpBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } -} - -@keyframes fadeOutUpBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } -} - -.fadeOutUpBig { - -webkit-animation-name: fadeOutUpBig; - animation-name: fadeOutUpBig; -} - -@-webkit-keyframes flip { - from { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg); - transform: perspective(400px) rotate3d(0, 1, 0, -360deg); - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; - } - - 40% { - -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); - transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; - } - - 50% { - -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); - transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 80% { - -webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95); - transform: perspective(400px) scale3d(0.95, 0.95, 0.95); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } -} - -@keyframes flip { - from { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg); - transform: perspective(400px) rotate3d(0, 1, 0, -360deg); - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; - } - - 40% { - -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); - transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; - } - - 50% { - -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); - transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 80% { - -webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95); - transform: perspective(400px) scale3d(0.95, 0.95, 0.95); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } -} - -.animated.flip { - -webkit-backface-visibility: visible; - backface-visibility: visible; - -webkit-animation-name: flip; - animation-name: flip; -} - -@-webkit-keyframes flipInX { - from { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - opacity: 0; - } - - 40% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 60% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg); - transform: perspective(400px) rotate3d(1, 0, 0, 10deg); - opacity: 1; - } - - 80% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg); - transform: perspective(400px) rotate3d(1, 0, 0, -5deg); - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } -} - -@keyframes flipInX { - from { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - opacity: 0; - } - - 40% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 60% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg); - transform: perspective(400px) rotate3d(1, 0, 0, 10deg); - opacity: 1; - } - - 80% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg); - transform: perspective(400px) rotate3d(1, 0, 0, -5deg); - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } -} - -.flipInX { - -webkit-backface-visibility: visible !important; - backface-visibility: visible !important; - -webkit-animation-name: flipInX; - animation-name: flipInX; -} - -@-webkit-keyframes flipInY { - from { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - opacity: 0; - } - - 40% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg); - transform: perspective(400px) rotate3d(0, 1, 0, -20deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 60% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg); - transform: perspective(400px) rotate3d(0, 1, 0, 10deg); - opacity: 1; - } - - 80% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg); - transform: perspective(400px) rotate3d(0, 1, 0, -5deg); - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } -} - -@keyframes flipInY { - from { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - opacity: 0; - } - - 40% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg); - transform: perspective(400px) rotate3d(0, 1, 0, -20deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 60% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg); - transform: perspective(400px) rotate3d(0, 1, 0, 10deg); - opacity: 1; - } - - 80% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg); - transform: perspective(400px) rotate3d(0, 1, 0, -5deg); - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } -} - -.flipInY { - -webkit-backface-visibility: visible !important; - backface-visibility: visible !important; - -webkit-animation-name: flipInY; - animation-name: flipInY; -} - -@-webkit-keyframes flipOutX { - from { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } - - 30% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - opacity: 1; - } - - to { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - opacity: 0; - } -} - -@keyframes flipOutX { - from { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } - - 30% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - opacity: 1; - } - - to { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - opacity: 0; - } -} - -.flipOutX { - -webkit-animation-duration: 0.75s; - animation-duration: 0.75s; - -webkit-animation-name: flipOutX; - animation-name: flipOutX; - -webkit-backface-visibility: visible !important; - backface-visibility: visible !important; -} - -@-webkit-keyframes flipOutY { - from { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } - - 30% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg); - transform: perspective(400px) rotate3d(0, 1, 0, -15deg); - opacity: 1; - } - - to { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - opacity: 0; - } -} - -@keyframes flipOutY { - from { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } - - 30% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg); - transform: perspective(400px) rotate3d(0, 1, 0, -15deg); - opacity: 1; - } - - to { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - opacity: 0; - } -} - -.flipOutY { - -webkit-animation-duration: 0.75s; - animation-duration: 0.75s; - -webkit-backface-visibility: visible !important; - backface-visibility: visible !important; - -webkit-animation-name: flipOutY; - animation-name: flipOutY; -} - -@-webkit-keyframes lightSpeedIn { - from { - -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); - transform: translate3d(100%, 0, 0) skewX(-30deg); - opacity: 0; - } - - 60% { - -webkit-transform: skewX(20deg); - transform: skewX(20deg); - opacity: 1; - } - - 80% { - -webkit-transform: skewX(-5deg); - transform: skewX(-5deg); - opacity: 1; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - } -} - -@keyframes lightSpeedIn { - from { - -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); - transform: translate3d(100%, 0, 0) skewX(-30deg); - opacity: 0; - } - - 60% { - -webkit-transform: skewX(20deg); - transform: skewX(20deg); - opacity: 1; - } - - 80% { - -webkit-transform: skewX(-5deg); - transform: skewX(-5deg); - opacity: 1; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - } -} - -.lightSpeedIn { - -webkit-animation-name: lightSpeedIn; - animation-name: lightSpeedIn; - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; -} - -@-webkit-keyframes lightSpeedOut { - from { - opacity: 1; - } - - to { - -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); - transform: translate3d(100%, 0, 0) skewX(30deg); - opacity: 0; - } -} - -@keyframes lightSpeedOut { - from { - opacity: 1; - } - - to { - -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); - transform: translate3d(100%, 0, 0) skewX(30deg); - opacity: 0; - } -} - -.lightSpeedOut { - -webkit-animation-name: lightSpeedOut; - animation-name: lightSpeedOut; - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; -} - -@-webkit-keyframes rotateIn { - from { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: rotate3d(0, 0, 1, -200deg); - transform: rotate3d(0, 0, 1, -200deg); - opacity: 0; - } - - to { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - } -} - -@keyframes rotateIn { - from { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: rotate3d(0, 0, 1, -200deg); - transform: rotate3d(0, 0, 1, -200deg); - opacity: 0; - } - - to { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - } -} - -.rotateIn { - -webkit-animation-name: rotateIn; - animation-name: rotateIn; -} - -@-webkit-keyframes rotateInDownLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - } -} - -@keyframes rotateInDownLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - } -} - -.rotateInDownLeft { - -webkit-animation-name: rotateInDownLeft; - animation-name: rotateInDownLeft; -} - -@-webkit-keyframes rotateInDownRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - } -} - -@keyframes rotateInDownRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - } -} - -.rotateInDownRight { - -webkit-animation-name: rotateInDownRight; - animation-name: rotateInDownRight; -} - -@-webkit-keyframes rotateInUpLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - } -} - -@keyframes rotateInUpLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - } -} - -.rotateInUpLeft { - -webkit-animation-name: rotateInUpLeft; - animation-name: rotateInUpLeft; -} - -@-webkit-keyframes rotateInUpRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, -90deg); - transform: rotate3d(0, 0, 1, -90deg); - opacity: 0; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - } -} - -@keyframes rotateInUpRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, -90deg); - transform: rotate3d(0, 0, 1, -90deg); - opacity: 0; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - } -} - -.rotateInUpRight { - -webkit-animation-name: rotateInUpRight; - animation-name: rotateInUpRight; -} - -@-webkit-keyframes rotateOut { - from { - -webkit-transform-origin: center; - transform-origin: center; - opacity: 1; - } - - to { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: rotate3d(0, 0, 1, 200deg); - transform: rotate3d(0, 0, 1, 200deg); - opacity: 0; - } -} - -@keyframes rotateOut { - from { - -webkit-transform-origin: center; - transform-origin: center; - opacity: 1; - } - - to { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: rotate3d(0, 0, 1, 200deg); - transform: rotate3d(0, 0, 1, 200deg); - opacity: 0; - } -} - -.rotateOut { - -webkit-animation-name: rotateOut; - animation-name: rotateOut; -} - -@-webkit-keyframes rotateOutDownLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } -} - -@keyframes rotateOutDownLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } -} - -.rotateOutDownLeft { - -webkit-animation-name: rotateOutDownLeft; - animation-name: rotateOutDownLeft; -} - -@-webkit-keyframes rotateOutDownRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } -} - -@keyframes rotateOutDownRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } -} - -.rotateOutDownRight { - -webkit-animation-name: rotateOutDownRight; - animation-name: rotateOutDownRight; -} - -@-webkit-keyframes rotateOutUpLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } -} - -@keyframes rotateOutUpLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } -} - -.rotateOutUpLeft { - -webkit-animation-name: rotateOutUpLeft; - animation-name: rotateOutUpLeft; -} - -@-webkit-keyframes rotateOutUpRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, 90deg); - transform: rotate3d(0, 0, 1, 90deg); - opacity: 0; - } -} - -@keyframes rotateOutUpRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, 90deg); - transform: rotate3d(0, 0, 1, 90deg); - opacity: 0; - } -} - -.rotateOutUpRight { - -webkit-animation-name: rotateOutUpRight; - animation-name: rotateOutUpRight; -} - -@-webkit-keyframes hinge { - 0% { - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - } - - 20%, - 60% { - -webkit-transform: rotate3d(0, 0, 1, 80deg); - transform: rotate3d(0, 0, 1, 80deg); - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - } - - 40%, - 80% { - -webkit-transform: rotate3d(0, 0, 1, 60deg); - transform: rotate3d(0, 0, 1, 60deg); - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - opacity: 1; - } - - to { - -webkit-transform: translate3d(0, 700px, 0); - transform: translate3d(0, 700px, 0); - opacity: 0; - } -} - -@keyframes hinge { - 0% { - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - } - - 20%, - 60% { - -webkit-transform: rotate3d(0, 0, 1, 80deg); - transform: rotate3d(0, 0, 1, 80deg); - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - } - - 40%, - 80% { - -webkit-transform: rotate3d(0, 0, 1, 60deg); - transform: rotate3d(0, 0, 1, 60deg); - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - opacity: 1; - } - - to { - -webkit-transform: translate3d(0, 700px, 0); - transform: translate3d(0, 700px, 0); - opacity: 0; - } -} - -.hinge { - -webkit-animation-duration: 2s; - animation-duration: 2s; - -webkit-animation-name: hinge; - animation-name: hinge; -} - -@-webkit-keyframes jackInTheBox { - from { - opacity: 0; - -webkit-transform: scale(0.1) rotate(30deg); - transform: scale(0.1) rotate(30deg); - -webkit-transform-origin: center bottom; - transform-origin: center bottom; - } - - 50% { - -webkit-transform: rotate(-10deg); - transform: rotate(-10deg); - } - - 70% { - -webkit-transform: rotate(3deg); - transform: rotate(3deg); - } - - to { - opacity: 1; - -webkit-transform: scale(1); - transform: scale(1); - } -} - -@keyframes jackInTheBox { - from { - opacity: 0; - -webkit-transform: scale(0.1) rotate(30deg); - transform: scale(0.1) rotate(30deg); - -webkit-transform-origin: center bottom; - transform-origin: center bottom; - } - - 50% { - -webkit-transform: rotate(-10deg); - transform: rotate(-10deg); - } - - 70% { - -webkit-transform: rotate(3deg); - transform: rotate(3deg); - } - - to { - opacity: 1; - -webkit-transform: scale(1); - transform: scale(1); - } -} - -.jackInTheBox { - -webkit-animation-name: jackInTheBox; - animation-name: jackInTheBox; -} - -/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ - -@-webkit-keyframes rollIn { - from { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); - transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes rollIn { - from { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); - transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); - } - - to { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.rollIn { - -webkit-animation-name: rollIn; - animation-name: rollIn; -} - -/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ - -@-webkit-keyframes rollOut { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); - transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); - } -} - -@keyframes rollOut { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); - transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); - } -} - -.rollOut { - -webkit-animation-name: rollOut; - animation-name: rollOut; -} - -@-webkit-keyframes zoomIn { - from { - opacity: 0; - -webkit-transform: scale3d(0.3, 0.3, 0.3); - transform: scale3d(0.3, 0.3, 0.3); - } - - 50% { - opacity: 1; - } -} - -@keyframes zoomIn { - from { - opacity: 0; - -webkit-transform: scale3d(0.3, 0.3, 0.3); - transform: scale3d(0.3, 0.3, 0.3); - } - - 50% { - opacity: 1; - } -} - -.zoomIn { - -webkit-animation-name: zoomIn; - animation-name: zoomIn; -} - -@-webkit-keyframes zoomInDown { - from { - opacity: 0; - -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); - transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); - -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - } -} - -@keyframes zoomInDown { - from { - opacity: 0; - -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); - transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); - -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - } -} - -.zoomInDown { - -webkit-animation-name: zoomInDown; - animation-name: zoomInDown; -} - -@-webkit-keyframes zoomInLeft { - from { - opacity: 0; - -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); - transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - } -} - -@keyframes zoomInLeft { - from { - opacity: 0; - -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); - transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - } -} - -.zoomInLeft { - -webkit-animation-name: zoomInLeft; - animation-name: zoomInLeft; -} - -@-webkit-keyframes zoomInRight { - from { - opacity: 0; - -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); - transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - } -} - -@keyframes zoomInRight { - from { - opacity: 0; - -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); - transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - } -} - -.zoomInRight { - -webkit-animation-name: zoomInRight; - animation-name: zoomInRight; -} - -@-webkit-keyframes zoomInUp { - from { - opacity: 0; - -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); - transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); - -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - } -} - -@keyframes zoomInUp { - from { - opacity: 0; - -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); - transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); - -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - } -} - -.zoomInUp { - -webkit-animation-name: zoomInUp; - animation-name: zoomInUp; -} - -@-webkit-keyframes zoomOut { - from { - opacity: 1; - } - - 50% { - opacity: 0; - -webkit-transform: scale3d(0.3, 0.3, 0.3); - transform: scale3d(0.3, 0.3, 0.3); - } - - to { - opacity: 0; - } -} - -@keyframes zoomOut { - from { - opacity: 1; - } - - 50% { - opacity: 0; - -webkit-transform: scale3d(0.3, 0.3, 0.3); - transform: scale3d(0.3, 0.3, 0.3); - } - - to { - opacity: 0; - } -} - -.zoomOut { - -webkit-animation-name: zoomOut; - animation-name: zoomOut; -} - -@-webkit-keyframes zoomOutDown { - 40% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - } - - to { - opacity: 0; - -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); - transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); - -webkit-transform-origin: center bottom; - transform-origin: center bottom; - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - } -} - -@keyframes zoomOutDown { - 40% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - } - - to { - opacity: 0; - -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); - transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); - -webkit-transform-origin: center bottom; - transform-origin: center bottom; - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - } -} - -.zoomOutDown { - -webkit-animation-name: zoomOutDown; - animation-name: zoomOutDown; -} - -@-webkit-keyframes zoomOutLeft { - 40% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: scale(0.1) translate3d(-2000px, 0, 0); - transform: scale(0.1) translate3d(-2000px, 0, 0); - -webkit-transform-origin: left center; - transform-origin: left center; - } -} - -@keyframes zoomOutLeft { - 40% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: scale(0.1) translate3d(-2000px, 0, 0); - transform: scale(0.1) translate3d(-2000px, 0, 0); - -webkit-transform-origin: left center; - transform-origin: left center; - } -} - -.zoomOutLeft { - -webkit-animation-name: zoomOutLeft; - animation-name: zoomOutLeft; -} - -@-webkit-keyframes zoomOutRight { - 40% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: scale(0.1) translate3d(2000px, 0, 0); - transform: scale(0.1) translate3d(2000px, 0, 0); - -webkit-transform-origin: right center; - transform-origin: right center; - } -} - -@keyframes zoomOutRight { - 40% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: scale(0.1) translate3d(2000px, 0, 0); - transform: scale(0.1) translate3d(2000px, 0, 0); - -webkit-transform-origin: right center; - transform-origin: right center; - } -} - -.zoomOutRight { - -webkit-animation-name: zoomOutRight; - animation-name: zoomOutRight; -} - -@-webkit-keyframes zoomOutUp { - 40% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - } - - to { - opacity: 0; - -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); - transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); - -webkit-transform-origin: center bottom; - transform-origin: center bottom; - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - } -} - -@keyframes zoomOutUp { - 40% { - opacity: 1; - -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); - transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); - } - - to { - opacity: 0; - -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); - transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); - -webkit-transform-origin: center bottom; - transform-origin: center bottom; - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); - } -} - -.zoomOutUp { - -webkit-animation-name: zoomOutUp; - animation-name: zoomOutUp; -} - -@-webkit-keyframes slideInDown { - from { - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes slideInDown { - from { - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.slideInDown { - -webkit-animation-name: slideInDown; - animation-name: slideInDown; -} - -@-webkit-keyframes slideInLeft { - from { - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes slideInLeft { - from { - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.slideInLeft { - -webkit-animation-name: slideInLeft; - animation-name: slideInLeft; -} - -@-webkit-keyframes slideInRight { - from { - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes slideInRight { - from { - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.slideInRight { - -webkit-animation-name: slideInRight; - animation-name: slideInRight; -} - -@-webkit-keyframes slideInUp { - from { - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes slideInUp { - from { - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.slideInUp { - -webkit-animation-name: slideInUp; - animation-name: slideInUp; -} - -@-webkit-keyframes slideOutDown { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -@keyframes slideOutDown { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -.slideOutDown { - -webkit-animation-name: slideOutDown; - animation-name: slideOutDown; -} - -@-webkit-keyframes slideOutLeft { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -@keyframes slideOutLeft { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -.slideOutLeft { - -webkit-animation-name: slideOutLeft; - animation-name: slideOutLeft; -} - -@-webkit-keyframes slideOutRight { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -@keyframes slideOutRight { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -.slideOutRight { - -webkit-animation-name: slideOutRight; - animation-name: slideOutRight; -} - -@-webkit-keyframes slideOutUp { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -@keyframes slideOutUp { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -.slideOutUp { - -webkit-animation-name: slideOutUp; - animation-name: slideOutUp; -} - -/* The typing effect */ -@keyframes typing { - from { - width: 0 - } - to { - width: 100% - } -} - -/* The typewriter cursor effect */ -@keyframes blink-caret { - from, to { - border-color: transparent - } - 50% { - border-color: orange - } +@charset "UTF-8"; + +/*! + * animate.css -http://daneden.me/animate + * Version - 3.6.0 + * Licensed under the MIT license - http://opensource.org/licenses/MIT + * + * Copyright (c) 2018 Daniel Eden + */ + +.animated { + -webkit-animation-duration: 1s; + animation-duration: 1s; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; +} + +.animated.infinite { + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; +} + +@-webkit-keyframes bounce { + from, + 20%, + 53%, + 80%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 40%, + 43% { + -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + -webkit-transform: translate3d(0, -30px, 0); + transform: translate3d(0, -30px, 0); + } + + 70% { + -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + -webkit-transform: translate3d(0, -15px, 0); + transform: translate3d(0, -15px, 0); + } + + 90% { + -webkit-transform: translate3d(0, -4px, 0); + transform: translate3d(0, -4px, 0); + } +} + +@keyframes bounce { + from, + 20%, + 53%, + 80%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 40%, + 43% { + -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + -webkit-transform: translate3d(0, -30px, 0); + transform: translate3d(0, -30px, 0); + } + + 70% { + -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + -webkit-transform: translate3d(0, -15px, 0); + transform: translate3d(0, -15px, 0); + } + + 90% { + -webkit-transform: translate3d(0, -4px, 0); + transform: translate3d(0, -4px, 0); + } +} + +.bounce { + -webkit-animation-name: bounce; + animation-name: bounce; + -webkit-transform-origin: center bottom; + transform-origin: center bottom; +} + +@-webkit-keyframes flash { + from, + 50%, + to { + opacity: 1; + } + + 25%, + 75% { + opacity: 0; + } +} + +@keyframes flash { + from, + 50%, + to { + opacity: 1; + } + + 25%, + 75% { + opacity: 0; + } +} + +.flash { + -webkit-animation-name: flash; + animation-name: flash; +} + +/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ + +@-webkit-keyframes pulse { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 50% { + -webkit-transform: scale3d(1.05, 1.05, 1.05); + transform: scale3d(1.05, 1.05, 1.05); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +@keyframes pulse { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 50% { + -webkit-transform: scale3d(1.05, 1.05, 1.05); + transform: scale3d(1.05, 1.05, 1.05); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +.pulse { + -webkit-animation-name: pulse; + animation-name: pulse; +} + +@-webkit-keyframes rubberBand { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 30% { + -webkit-transform: scale3d(1.25, 0.75, 1); + transform: scale3d(1.25, 0.75, 1); + } + + 40% { + -webkit-transform: scale3d(0.75, 1.25, 1); + transform: scale3d(0.75, 1.25, 1); + } + + 50% { + -webkit-transform: scale3d(1.15, 0.85, 1); + transform: scale3d(1.15, 0.85, 1); + } + + 65% { + -webkit-transform: scale3d(0.95, 1.05, 1); + transform: scale3d(0.95, 1.05, 1); + } + + 75% { + -webkit-transform: scale3d(1.05, 0.95, 1); + transform: scale3d(1.05, 0.95, 1); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +@keyframes rubberBand { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 30% { + -webkit-transform: scale3d(1.25, 0.75, 1); + transform: scale3d(1.25, 0.75, 1); + } + + 40% { + -webkit-transform: scale3d(0.75, 1.25, 1); + transform: scale3d(0.75, 1.25, 1); + } + + 50% { + -webkit-transform: scale3d(1.15, 0.85, 1); + transform: scale3d(1.15, 0.85, 1); + } + + 65% { + -webkit-transform: scale3d(0.95, 1.05, 1); + transform: scale3d(0.95, 1.05, 1); + } + + 75% { + -webkit-transform: scale3d(1.05, 0.95, 1); + transform: scale3d(1.05, 0.95, 1); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +.rubberBand { + -webkit-animation-name: rubberBand; + animation-name: rubberBand; +} + +@-webkit-keyframes shake { + from, + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 10%, + 30%, + 50%, + 70%, + 90% { + -webkit-transform: translate3d(-10px, 0, 0); + transform: translate3d(-10px, 0, 0); + } + + 20%, + 40%, + 60%, + 80% { + -webkit-transform: translate3d(10px, 0, 0); + transform: translate3d(10px, 0, 0); + } +} + +@keyframes shake { + from, + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 10%, + 30%, + 50%, + 70%, + 90% { + -webkit-transform: translate3d(-10px, 0, 0); + transform: translate3d(-10px, 0, 0); + } + + 20%, + 40%, + 60%, + 80% { + -webkit-transform: translate3d(10px, 0, 0); + transform: translate3d(10px, 0, 0); + } +} + +.shake { + -webkit-animation-name: shake; + animation-name: shake; +} + +@-webkit-keyframes headShake { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + + 6.5% { + -webkit-transform: translateX(-6px) rotateY(-9deg); + transform: translateX(-6px) rotateY(-9deg); + } + + 18.5% { + -webkit-transform: translateX(5px) rotateY(7deg); + transform: translateX(5px) rotateY(7deg); + } + + 31.5% { + -webkit-transform: translateX(-3px) rotateY(-5deg); + transform: translateX(-3px) rotateY(-5deg); + } + + 43.5% { + -webkit-transform: translateX(2px) rotateY(3deg); + transform: translateX(2px) rotateY(3deg); + } + + 50% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} + +@keyframes headShake { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + + 6.5% { + -webkit-transform: translateX(-6px) rotateY(-9deg); + transform: translateX(-6px) rotateY(-9deg); + } + + 18.5% { + -webkit-transform: translateX(5px) rotateY(7deg); + transform: translateX(5px) rotateY(7deg); + } + + 31.5% { + -webkit-transform: translateX(-3px) rotateY(-5deg); + transform: translateX(-3px) rotateY(-5deg); + } + + 43.5% { + -webkit-transform: translateX(2px) rotateY(3deg); + transform: translateX(2px) rotateY(3deg); + } + + 50% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} + +.headShake { + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + -webkit-animation-name: headShake; + animation-name: headShake; +} + +@-webkit-keyframes swing { + 20% { + -webkit-transform: rotate3d(0, 0, 1, 15deg); + transform: rotate3d(0, 0, 1, 15deg); + } + + 40% { + -webkit-transform: rotate3d(0, 0, 1, -10deg); + transform: rotate3d(0, 0, 1, -10deg); + } + + 60% { + -webkit-transform: rotate3d(0, 0, 1, 5deg); + transform: rotate3d(0, 0, 1, 5deg); + } + + 80% { + -webkit-transform: rotate3d(0, 0, 1, -5deg); + transform: rotate3d(0, 0, 1, -5deg); + } + + to { + -webkit-transform: rotate3d(0, 0, 1, 0deg); + transform: rotate3d(0, 0, 1, 0deg); + } +} + +@keyframes swing { + 20% { + -webkit-transform: rotate3d(0, 0, 1, 15deg); + transform: rotate3d(0, 0, 1, 15deg); + } + + 40% { + -webkit-transform: rotate3d(0, 0, 1, -10deg); + transform: rotate3d(0, 0, 1, -10deg); + } + + 60% { + -webkit-transform: rotate3d(0, 0, 1, 5deg); + transform: rotate3d(0, 0, 1, 5deg); + } + + 80% { + -webkit-transform: rotate3d(0, 0, 1, -5deg); + transform: rotate3d(0, 0, 1, -5deg); + } + + to { + -webkit-transform: rotate3d(0, 0, 1, 0deg); + transform: rotate3d(0, 0, 1, 0deg); + } +} + +.swing { + -webkit-transform-origin: top center; + transform-origin: top center; + -webkit-animation-name: swing; + animation-name: swing; +} + +@-webkit-keyframes tada { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 10%, + 20% { + -webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); + transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); + } + + 30%, + 50%, + 70%, + 90% { + -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + } + + 40%, + 60%, + 80% { + -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +@keyframes tada { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 10%, + 20% { + -webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); + transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); + } + + 30%, + 50%, + 70%, + 90% { + -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + } + + 40%, + 60%, + 80% { + -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +.tada { + -webkit-animation-name: tada; + animation-name: tada; +} + +/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ + +@-webkit-keyframes wobble { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 15% { + -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); + transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); + } + + 30% { + -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); + transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); + } + + 45% { + -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); + transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); + } + + 60% { + -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); + transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); + } + + 75% { + -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); + transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes wobble { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 15% { + -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); + transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); + } + + 30% { + -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); + transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); + } + + 45% { + -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); + transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); + } + + 60% { + -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); + transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); + } + + 75% { + -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); + transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.wobble { + -webkit-animation-name: wobble; + animation-name: wobble; +} + +@-webkit-keyframes jello { + from, + 11.1%, + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 22.2% { + -webkit-transform: skewX(-12.5deg) skewY(-12.5deg); + transform: skewX(-12.5deg) skewY(-12.5deg); + } + + 33.3% { + -webkit-transform: skewX(6.25deg) skewY(6.25deg); + transform: skewX(6.25deg) skewY(6.25deg); + } + + 44.4% { + -webkit-transform: skewX(-3.125deg) skewY(-3.125deg); + transform: skewX(-3.125deg) skewY(-3.125deg); + } + + 55.5% { + -webkit-transform: skewX(1.5625deg) skewY(1.5625deg); + transform: skewX(1.5625deg) skewY(1.5625deg); + } + + 66.6% { + -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg); + transform: skewX(-0.78125deg) skewY(-0.78125deg); + } + + 77.7% { + -webkit-transform: skewX(0.390625deg) skewY(0.390625deg); + transform: skewX(0.390625deg) skewY(0.390625deg); + } + + 88.8% { + -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg); + transform: skewX(-0.1953125deg) skewY(-0.1953125deg); + } +} + +@keyframes jello { + from, + 11.1%, + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 22.2% { + -webkit-transform: skewX(-12.5deg) skewY(-12.5deg); + transform: skewX(-12.5deg) skewY(-12.5deg); + } + + 33.3% { + -webkit-transform: skewX(6.25deg) skewY(6.25deg); + transform: skewX(6.25deg) skewY(6.25deg); + } + + 44.4% { + -webkit-transform: skewX(-3.125deg) skewY(-3.125deg); + transform: skewX(-3.125deg) skewY(-3.125deg); + } + + 55.5% { + -webkit-transform: skewX(1.5625deg) skewY(1.5625deg); + transform: skewX(1.5625deg) skewY(1.5625deg); + } + + 66.6% { + -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg); + transform: skewX(-0.78125deg) skewY(-0.78125deg); + } + + 77.7% { + -webkit-transform: skewX(0.390625deg) skewY(0.390625deg); + transform: skewX(0.390625deg) skewY(0.390625deg); + } + + 88.8% { + -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg); + transform: skewX(-0.1953125deg) skewY(-0.1953125deg); + } +} + +.jello { + -webkit-animation-name: jello; + animation-name: jello; + -webkit-transform-origin: center; + transform-origin: center; +} + +@-webkit-keyframes bounceIn { + from, + 20%, + 40%, + 60%, + 80%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + 0% { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } + + 20% { + -webkit-transform: scale3d(1.1, 1.1, 1.1); + transform: scale3d(1.1, 1.1, 1.1); + } + + 40% { + -webkit-transform: scale3d(0.9, 0.9, 0.9); + transform: scale3d(0.9, 0.9, 0.9); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(1.03, 1.03, 1.03); + transform: scale3d(1.03, 1.03, 1.03); + } + + 80% { + -webkit-transform: scale3d(0.97, 0.97, 0.97); + transform: scale3d(0.97, 0.97, 0.97); + } + + to { + opacity: 1; + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +@keyframes bounceIn { + from, + 20%, + 40%, + 60%, + 80%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + 0% { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } + + 20% { + -webkit-transform: scale3d(1.1, 1.1, 1.1); + transform: scale3d(1.1, 1.1, 1.1); + } + + 40% { + -webkit-transform: scale3d(0.9, 0.9, 0.9); + transform: scale3d(0.9, 0.9, 0.9); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(1.03, 1.03, 1.03); + transform: scale3d(1.03, 1.03, 1.03); + } + + 80% { + -webkit-transform: scale3d(0.97, 0.97, 0.97); + transform: scale3d(0.97, 0.97, 0.97); + } + + to { + opacity: 1; + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +.bounceIn { + -webkit-animation-duration: 0.75s; + animation-duration: 0.75s; + -webkit-animation-name: bounceIn; + animation-name: bounceIn; +} + +@-webkit-keyframes bounceInDown { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + 0% { + opacity: 0; + -webkit-transform: translate3d(0, -3000px, 0); + transform: translate3d(0, -3000px, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(0, 25px, 0); + transform: translate3d(0, 25px, 0); + } + + 75% { + -webkit-transform: translate3d(0, -10px, 0); + transform: translate3d(0, -10px, 0); + } + + 90% { + -webkit-transform: translate3d(0, 5px, 0); + transform: translate3d(0, 5px, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes bounceInDown { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + 0% { + opacity: 0; + -webkit-transform: translate3d(0, -3000px, 0); + transform: translate3d(0, -3000px, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(0, 25px, 0); + transform: translate3d(0, 25px, 0); + } + + 75% { + -webkit-transform: translate3d(0, -10px, 0); + transform: translate3d(0, -10px, 0); + } + + 90% { + -webkit-transform: translate3d(0, 5px, 0); + transform: translate3d(0, 5px, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.bounceInDown { + -webkit-animation-name: bounceInDown; + animation-name: bounceInDown; +} + +@-webkit-keyframes bounceInLeft { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + 0% { + opacity: 0; + -webkit-transform: translate3d(-3000px, 0, 0); + transform: translate3d(-3000px, 0, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(25px, 0, 0); + transform: translate3d(25px, 0, 0); + } + + 75% { + -webkit-transform: translate3d(-10px, 0, 0); + transform: translate3d(-10px, 0, 0); + } + + 90% { + -webkit-transform: translate3d(5px, 0, 0); + transform: translate3d(5px, 0, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes bounceInLeft { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + 0% { + opacity: 0; + -webkit-transform: translate3d(-3000px, 0, 0); + transform: translate3d(-3000px, 0, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(25px, 0, 0); + transform: translate3d(25px, 0, 0); + } + + 75% { + -webkit-transform: translate3d(-10px, 0, 0); + transform: translate3d(-10px, 0, 0); + } + + 90% { + -webkit-transform: translate3d(5px, 0, 0); + transform: translate3d(5px, 0, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.bounceInLeft { + -webkit-animation-name: bounceInLeft; + animation-name: bounceInLeft; +} + +@-webkit-keyframes bounceInRight { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + from { + opacity: 0; + -webkit-transform: translate3d(3000px, 0, 0); + transform: translate3d(3000px, 0, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(-25px, 0, 0); + transform: translate3d(-25px, 0, 0); + } + + 75% { + -webkit-transform: translate3d(10px, 0, 0); + transform: translate3d(10px, 0, 0); + } + + 90% { + -webkit-transform: translate3d(-5px, 0, 0); + transform: translate3d(-5px, 0, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes bounceInRight { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + from { + opacity: 0; + -webkit-transform: translate3d(3000px, 0, 0); + transform: translate3d(3000px, 0, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(-25px, 0, 0); + transform: translate3d(-25px, 0, 0); + } + + 75% { + -webkit-transform: translate3d(10px, 0, 0); + transform: translate3d(10px, 0, 0); + } + + 90% { + -webkit-transform: translate3d(-5px, 0, 0); + transform: translate3d(-5px, 0, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.bounceInRight { + -webkit-animation-name: bounceInRight; + animation-name: bounceInRight; +} + +@-webkit-keyframes bounceInUp { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + from { + opacity: 0; + -webkit-transform: translate3d(0, 3000px, 0); + transform: translate3d(0, 3000px, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(0, -20px, 0); + transform: translate3d(0, -20px, 0); + } + + 75% { + -webkit-transform: translate3d(0, 10px, 0); + transform: translate3d(0, 10px, 0); + } + + 90% { + -webkit-transform: translate3d(0, -5px, 0); + transform: translate3d(0, -5px, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes bounceInUp { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + from { + opacity: 0; + -webkit-transform: translate3d(0, 3000px, 0); + transform: translate3d(0, 3000px, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(0, -20px, 0); + transform: translate3d(0, -20px, 0); + } + + 75% { + -webkit-transform: translate3d(0, 10px, 0); + transform: translate3d(0, 10px, 0); + } + + 90% { + -webkit-transform: translate3d(0, -5px, 0); + transform: translate3d(0, -5px, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.bounceInUp { + -webkit-animation-name: bounceInUp; + animation-name: bounceInUp; +} + +@-webkit-keyframes bounceOut { + 20% { + -webkit-transform: scale3d(0.9, 0.9, 0.9); + transform: scale3d(0.9, 0.9, 0.9); + } + + 50%, + 55% { + opacity: 1; + -webkit-transform: scale3d(1.1, 1.1, 1.1); + transform: scale3d(1.1, 1.1, 1.1); + } + + to { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } +} + +@keyframes bounceOut { + 20% { + -webkit-transform: scale3d(0.9, 0.9, 0.9); + transform: scale3d(0.9, 0.9, 0.9); + } + + 50%, + 55% { + opacity: 1; + -webkit-transform: scale3d(1.1, 1.1, 1.1); + transform: scale3d(1.1, 1.1, 1.1); + } + + to { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } +} + +.bounceOut { + -webkit-animation-duration: 0.75s; + animation-duration: 0.75s; + -webkit-animation-name: bounceOut; + animation-name: bounceOut; +} + +@-webkit-keyframes bounceOutDown { + 20% { + -webkit-transform: translate3d(0, 10px, 0); + transform: translate3d(0, 10px, 0); + } + + 40%, + 45% { + opacity: 1; + -webkit-transform: translate3d(0, -20px, 0); + transform: translate3d(0, -20px, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, 2000px, 0); + transform: translate3d(0, 2000px, 0); + } +} + +@keyframes bounceOutDown { + 20% { + -webkit-transform: translate3d(0, 10px, 0); + transform: translate3d(0, 10px, 0); + } + + 40%, + 45% { + opacity: 1; + -webkit-transform: translate3d(0, -20px, 0); + transform: translate3d(0, -20px, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, 2000px, 0); + transform: translate3d(0, 2000px, 0); + } +} + +.bounceOutDown { + -webkit-animation-name: bounceOutDown; + animation-name: bounceOutDown; +} + +@-webkit-keyframes bounceOutLeft { + 20% { + opacity: 1; + -webkit-transform: translate3d(20px, 0, 0); + transform: translate3d(20px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(-2000px, 0, 0); + transform: translate3d(-2000px, 0, 0); + } +} + +@keyframes bounceOutLeft { + 20% { + opacity: 1; + -webkit-transform: translate3d(20px, 0, 0); + transform: translate3d(20px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(-2000px, 0, 0); + transform: translate3d(-2000px, 0, 0); + } +} + +.bounceOutLeft { + -webkit-animation-name: bounceOutLeft; + animation-name: bounceOutLeft; +} + +@-webkit-keyframes bounceOutRight { + 20% { + opacity: 1; + -webkit-transform: translate3d(-20px, 0, 0); + transform: translate3d(-20px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(2000px, 0, 0); + transform: translate3d(2000px, 0, 0); + } +} + +@keyframes bounceOutRight { + 20% { + opacity: 1; + -webkit-transform: translate3d(-20px, 0, 0); + transform: translate3d(-20px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(2000px, 0, 0); + transform: translate3d(2000px, 0, 0); + } +} + +.bounceOutRight { + -webkit-animation-name: bounceOutRight; + animation-name: bounceOutRight; +} + +@-webkit-keyframes bounceOutUp { + 20% { + -webkit-transform: translate3d(0, -10px, 0); + transform: translate3d(0, -10px, 0); + } + + 40%, + 45% { + opacity: 1; + -webkit-transform: translate3d(0, 20px, 0); + transform: translate3d(0, 20px, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, -2000px, 0); + transform: translate3d(0, -2000px, 0); + } +} + +@keyframes bounceOutUp { + 20% { + -webkit-transform: translate3d(0, -10px, 0); + transform: translate3d(0, -10px, 0); + } + + 40%, + 45% { + opacity: 1; + -webkit-transform: translate3d(0, 20px, 0); + transform: translate3d(0, 20px, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, -2000px, 0); + transform: translate3d(0, -2000px, 0); + } +} + +.bounceOutUp { + -webkit-animation-name: bounceOutUp; + animation-name: bounceOutUp; +} + +@-webkit-keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +.fadeIn { + -webkit-animation-name: fadeIn; + animation-name: fadeIn; +} + +@-webkit-keyframes fadeInDown { + from { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInDown { + from { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInDown { + -webkit-animation-name: fadeInDown; + animation-name: fadeInDown; +} + +@-webkit-keyframes fadeInDownBig { + from { + opacity: 0; + -webkit-transform: translate3d(0, -2000px, 0); + transform: translate3d(0, -2000px, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInDownBig { + from { + opacity: 0; + -webkit-transform: translate3d(0, -2000px, 0); + transform: translate3d(0, -2000px, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInDownBig { + -webkit-animation-name: fadeInDownBig; + animation-name: fadeInDownBig; +} + +@-webkit-keyframes fadeInLeft { + from { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInLeft { + from { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInLeft { + -webkit-animation-name: fadeInLeft; + animation-name: fadeInLeft; +} + +@-webkit-keyframes fadeInLeftBig { + from { + opacity: 0; + -webkit-transform: translate3d(-2000px, 0, 0); + transform: translate3d(-2000px, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInLeftBig { + from { + opacity: 0; + -webkit-transform: translate3d(-2000px, 0, 0); + transform: translate3d(-2000px, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInLeftBig { + -webkit-animation-name: fadeInLeftBig; + animation-name: fadeInLeftBig; +} + +@-webkit-keyframes fadeInRight { + from { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInRight { + from { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInRight { + -webkit-animation-name: fadeInRight; + animation-name: fadeInRight; +} + +@-webkit-keyframes fadeInRightBig { + from { + opacity: 0; + -webkit-transform: translate3d(2000px, 0, 0); + transform: translate3d(2000px, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInRightBig { + from { + opacity: 0; + -webkit-transform: translate3d(2000px, 0, 0); + transform: translate3d(2000px, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInRightBig { + -webkit-animation-name: fadeInRightBig; + animation-name: fadeInRightBig; +} + +@-webkit-keyframes fadeInUp { + from { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInUp { + from { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInUp { + -webkit-animation-name: fadeInUp; + animation-name: fadeInUp; +} + +@-webkit-keyframes fadeInUpBig { + from { + opacity: 0; + -webkit-transform: translate3d(0, 2000px, 0); + transform: translate3d(0, 2000px, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInUpBig { + from { + opacity: 0; + -webkit-transform: translate3d(0, 2000px, 0); + transform: translate3d(0, 2000px, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInUpBig { + -webkit-animation-name: fadeInUpBig; + animation-name: fadeInUpBig; +} + +@-webkit-keyframes fadeOut { + from { + opacity: 1; + } + + to { + opacity: 0; + } +} + +@keyframes fadeOut { + from { + opacity: 1; + } + + to { + opacity: 0; + } +} + +.fadeOut { + -webkit-animation-name: fadeOut; + animation-name: fadeOut; +} + +@-webkit-keyframes fadeOutDown { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } +} + +@keyframes fadeOutDown { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } +} + +.fadeOutDown { + -webkit-animation-name: fadeOutDown; + animation-name: fadeOutDown; +} + +@-webkit-keyframes fadeOutDownBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, 2000px, 0); + transform: translate3d(0, 2000px, 0); + } +} + +@keyframes fadeOutDownBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, 2000px, 0); + transform: translate3d(0, 2000px, 0); + } +} + +.fadeOutDownBig { + -webkit-animation-name: fadeOutDownBig; + animation-name: fadeOutDownBig; +} + +@-webkit-keyframes fadeOutLeft { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } +} + +@keyframes fadeOutLeft { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } +} + +.fadeOutLeft { + -webkit-animation-name: fadeOutLeft; + animation-name: fadeOutLeft; +} + +@-webkit-keyframes fadeOutLeftBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(-2000px, 0, 0); + transform: translate3d(-2000px, 0, 0); + } +} + +@keyframes fadeOutLeftBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(-2000px, 0, 0); + transform: translate3d(-2000px, 0, 0); + } +} + +.fadeOutLeftBig { + -webkit-animation-name: fadeOutLeftBig; + animation-name: fadeOutLeftBig; +} + +@-webkit-keyframes fadeOutRight { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } +} + +@keyframes fadeOutRight { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } +} + +.fadeOutRight { + -webkit-animation-name: fadeOutRight; + animation-name: fadeOutRight; +} + +@-webkit-keyframes fadeOutRightBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(2000px, 0, 0); + transform: translate3d(2000px, 0, 0); + } +} + +@keyframes fadeOutRightBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(2000px, 0, 0); + transform: translate3d(2000px, 0, 0); + } +} + +.fadeOutRightBig { + -webkit-animation-name: fadeOutRightBig; + animation-name: fadeOutRightBig; +} + +@-webkit-keyframes fadeOutUp { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } +} + +@keyframes fadeOutUp { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } +} + +.fadeOutUp { + -webkit-animation-name: fadeOutUp; + animation-name: fadeOutUp; +} + +@-webkit-keyframes fadeOutUpBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, -2000px, 0); + transform: translate3d(0, -2000px, 0); + } +} + +@keyframes fadeOutUpBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, -2000px, 0); + transform: translate3d(0, -2000px, 0); + } +} + +.fadeOutUpBig { + -webkit-animation-name: fadeOutUpBig; + animation-name: fadeOutUpBig; +} + +@-webkit-keyframes flip { + from { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg); + transform: perspective(400px) rotate3d(0, 1, 0, -360deg); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 40% { + -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); + transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 50% { + -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); + transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 80% { + -webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95); + transform: perspective(400px) scale3d(0.95, 0.95, 0.95); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + to { + -webkit-transform: perspective(400px); + transform: perspective(400px); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } +} + +@keyframes flip { + from { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg); + transform: perspective(400px) rotate3d(0, 1, 0, -360deg); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 40% { + -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); + transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 50% { + -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); + transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 80% { + -webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95); + transform: perspective(400px) scale3d(0.95, 0.95, 0.95); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + to { + -webkit-transform: perspective(400px); + transform: perspective(400px); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } +} + +.animated.flip { + -webkit-backface-visibility: visible; + backface-visibility: visible; + -webkit-animation-name: flip; + animation-name: flip; +} + +@-webkit-keyframes flipInX { + from { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + opacity: 0; + } + + 40% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 60% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg); + transform: perspective(400px) rotate3d(1, 0, 0, 10deg); + opacity: 1; + } + + 80% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg); + transform: perspective(400px) rotate3d(1, 0, 0, -5deg); + } + + to { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } +} + +@keyframes flipInX { + from { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + opacity: 0; + } + + 40% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 60% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg); + transform: perspective(400px) rotate3d(1, 0, 0, 10deg); + opacity: 1; + } + + 80% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg); + transform: perspective(400px) rotate3d(1, 0, 0, -5deg); + } + + to { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } +} + +.flipInX { + -webkit-backface-visibility: visible !important; + backface-visibility: visible !important; + -webkit-animation-name: flipInX; + animation-name: flipInX; +} + +@-webkit-keyframes flipInY { + from { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + opacity: 0; + } + + 40% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg); + transform: perspective(400px) rotate3d(0, 1, 0, -20deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 60% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg); + transform: perspective(400px) rotate3d(0, 1, 0, 10deg); + opacity: 1; + } + + 80% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg); + transform: perspective(400px) rotate3d(0, 1, 0, -5deg); + } + + to { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } +} + +@keyframes flipInY { + from { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + opacity: 0; + } + + 40% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg); + transform: perspective(400px) rotate3d(0, 1, 0, -20deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 60% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg); + transform: perspective(400px) rotate3d(0, 1, 0, 10deg); + opacity: 1; + } + + 80% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg); + transform: perspective(400px) rotate3d(0, 1, 0, -5deg); + } + + to { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } +} + +.flipInY { + -webkit-backface-visibility: visible !important; + backface-visibility: visible !important; + -webkit-animation-name: flipInY; + animation-name: flipInY; +} + +@-webkit-keyframes flipOutX { + from { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } + + 30% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + opacity: 1; + } + + to { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + opacity: 0; + } +} + +@keyframes flipOutX { + from { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } + + 30% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + opacity: 1; + } + + to { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + opacity: 0; + } +} + +.flipOutX { + -webkit-animation-duration: 0.75s; + animation-duration: 0.75s; + -webkit-animation-name: flipOutX; + animation-name: flipOutX; + -webkit-backface-visibility: visible !important; + backface-visibility: visible !important; +} + +@-webkit-keyframes flipOutY { + from { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } + + 30% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg); + transform: perspective(400px) rotate3d(0, 1, 0, -15deg); + opacity: 1; + } + + to { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + opacity: 0; + } +} + +@keyframes flipOutY { + from { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } + + 30% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg); + transform: perspective(400px) rotate3d(0, 1, 0, -15deg); + opacity: 1; + } + + to { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + opacity: 0; + } +} + +.flipOutY { + -webkit-animation-duration: 0.75s; + animation-duration: 0.75s; + -webkit-backface-visibility: visible !important; + backface-visibility: visible !important; + -webkit-animation-name: flipOutY; + animation-name: flipOutY; +} + +@-webkit-keyframes lightSpeedIn { + from { + -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); + transform: translate3d(100%, 0, 0) skewX(-30deg); + opacity: 0; + } + + 60% { + -webkit-transform: skewX(20deg); + transform: skewX(20deg); + opacity: 1; + } + + 80% { + -webkit-transform: skewX(-5deg); + transform: skewX(-5deg); + opacity: 1; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +@keyframes lightSpeedIn { + from { + -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); + transform: translate3d(100%, 0, 0) skewX(-30deg); + opacity: 0; + } + + 60% { + -webkit-transform: skewX(20deg); + transform: skewX(20deg); + opacity: 1; + } + + 80% { + -webkit-transform: skewX(-5deg); + transform: skewX(-5deg); + opacity: 1; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +.lightSpeedIn { + -webkit-animation-name: lightSpeedIn; + animation-name: lightSpeedIn; + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; +} + +@-webkit-keyframes lightSpeedOut { + from { + opacity: 1; + } + + to { + -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); + transform: translate3d(100%, 0, 0) skewX(30deg); + opacity: 0; + } +} + +@keyframes lightSpeedOut { + from { + opacity: 1; + } + + to { + -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); + transform: translate3d(100%, 0, 0) skewX(30deg); + opacity: 0; + } +} + +.lightSpeedOut { + -webkit-animation-name: lightSpeedOut; + animation-name: lightSpeedOut; + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; +} + +@-webkit-keyframes rotateIn { + from { + -webkit-transform-origin: center; + transform-origin: center; + -webkit-transform: rotate3d(0, 0, 1, -200deg); + transform: rotate3d(0, 0, 1, -200deg); + opacity: 0; + } + + to { + -webkit-transform-origin: center; + transform-origin: center; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +@keyframes rotateIn { + from { + -webkit-transform-origin: center; + transform-origin: center; + -webkit-transform: rotate3d(0, 0, 1, -200deg); + transform: rotate3d(0, 0, 1, -200deg); + opacity: 0; + } + + to { + -webkit-transform-origin: center; + transform-origin: center; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +.rotateIn { + -webkit-animation-name: rotateIn; + animation-name: rotateIn; +} + +@-webkit-keyframes rotateInDownLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, -45deg); + transform: rotate3d(0, 0, 1, -45deg); + opacity: 0; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +@keyframes rotateInDownLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, -45deg); + transform: rotate3d(0, 0, 1, -45deg); + opacity: 0; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +.rotateInDownLeft { + -webkit-animation-name: rotateInDownLeft; + animation-name: rotateInDownLeft; +} + +@-webkit-keyframes rotateInDownRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, 45deg); + transform: rotate3d(0, 0, 1, 45deg); + opacity: 0; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +@keyframes rotateInDownRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, 45deg); + transform: rotate3d(0, 0, 1, 45deg); + opacity: 0; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +.rotateInDownRight { + -webkit-animation-name: rotateInDownRight; + animation-name: rotateInDownRight; +} + +@-webkit-keyframes rotateInUpLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, 45deg); + transform: rotate3d(0, 0, 1, 45deg); + opacity: 0; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +@keyframes rotateInUpLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, 45deg); + transform: rotate3d(0, 0, 1, 45deg); + opacity: 0; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +.rotateInUpLeft { + -webkit-animation-name: rotateInUpLeft; + animation-name: rotateInUpLeft; +} + +@-webkit-keyframes rotateInUpRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, -90deg); + transform: rotate3d(0, 0, 1, -90deg); + opacity: 0; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +@keyframes rotateInUpRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, -90deg); + transform: rotate3d(0, 0, 1, -90deg); + opacity: 0; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +.rotateInUpRight { + -webkit-animation-name: rotateInUpRight; + animation-name: rotateInUpRight; +} + +@-webkit-keyframes rotateOut { + from { + -webkit-transform-origin: center; + transform-origin: center; + opacity: 1; + } + + to { + -webkit-transform-origin: center; + transform-origin: center; + -webkit-transform: rotate3d(0, 0, 1, 200deg); + transform: rotate3d(0, 0, 1, 200deg); + opacity: 0; + } +} + +@keyframes rotateOut { + from { + -webkit-transform-origin: center; + transform-origin: center; + opacity: 1; + } + + to { + -webkit-transform-origin: center; + transform-origin: center; + -webkit-transform: rotate3d(0, 0, 1, 200deg); + transform: rotate3d(0, 0, 1, 200deg); + opacity: 0; + } +} + +.rotateOut { + -webkit-animation-name: rotateOut; + animation-name: rotateOut; +} + +@-webkit-keyframes rotateOutDownLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, 45deg); + transform: rotate3d(0, 0, 1, 45deg); + opacity: 0; + } +} + +@keyframes rotateOutDownLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, 45deg); + transform: rotate3d(0, 0, 1, 45deg); + opacity: 0; + } +} + +.rotateOutDownLeft { + -webkit-animation-name: rotateOutDownLeft; + animation-name: rotateOutDownLeft; +} + +@-webkit-keyframes rotateOutDownRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, -45deg); + transform: rotate3d(0, 0, 1, -45deg); + opacity: 0; + } +} + +@keyframes rotateOutDownRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, -45deg); + transform: rotate3d(0, 0, 1, -45deg); + opacity: 0; + } +} + +.rotateOutDownRight { + -webkit-animation-name: rotateOutDownRight; + animation-name: rotateOutDownRight; +} + +@-webkit-keyframes rotateOutUpLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, -45deg); + transform: rotate3d(0, 0, 1, -45deg); + opacity: 0; + } +} + +@keyframes rotateOutUpLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, -45deg); + transform: rotate3d(0, 0, 1, -45deg); + opacity: 0; + } +} + +.rotateOutUpLeft { + -webkit-animation-name: rotateOutUpLeft; + animation-name: rotateOutUpLeft; +} + +@-webkit-keyframes rotateOutUpRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, 90deg); + transform: rotate3d(0, 0, 1, 90deg); + opacity: 0; + } +} + +@keyframes rotateOutUpRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, 90deg); + transform: rotate3d(0, 0, 1, 90deg); + opacity: 0; + } +} + +.rotateOutUpRight { + -webkit-animation-name: rotateOutUpRight; + animation-name: rotateOutUpRight; +} + +@-webkit-keyframes hinge { + 0% { + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + + 20%, + 60% { + -webkit-transform: rotate3d(0, 0, 1, 80deg); + transform: rotate3d(0, 0, 1, 80deg); + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + + 40%, + 80% { + -webkit-transform: rotate3d(0, 0, 1, 60deg); + transform: rotate3d(0, 0, 1, 60deg); + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + opacity: 1; + } + + to { + -webkit-transform: translate3d(0, 700px, 0); + transform: translate3d(0, 700px, 0); + opacity: 0; + } +} + +@keyframes hinge { + 0% { + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + + 20%, + 60% { + -webkit-transform: rotate3d(0, 0, 1, 80deg); + transform: rotate3d(0, 0, 1, 80deg); + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + + 40%, + 80% { + -webkit-transform: rotate3d(0, 0, 1, 60deg); + transform: rotate3d(0, 0, 1, 60deg); + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + opacity: 1; + } + + to { + -webkit-transform: translate3d(0, 700px, 0); + transform: translate3d(0, 700px, 0); + opacity: 0; + } +} + +.hinge { + -webkit-animation-duration: 2s; + animation-duration: 2s; + -webkit-animation-name: hinge; + animation-name: hinge; +} + +@-webkit-keyframes jackInTheBox { + from { + opacity: 0; + -webkit-transform: scale(0.1) rotate(30deg); + transform: scale(0.1) rotate(30deg); + -webkit-transform-origin: center bottom; + transform-origin: center bottom; + } + + 50% { + -webkit-transform: rotate(-10deg); + transform: rotate(-10deg); + } + + 70% { + -webkit-transform: rotate(3deg); + transform: rotate(3deg); + } + + to { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@keyframes jackInTheBox { + from { + opacity: 0; + -webkit-transform: scale(0.1) rotate(30deg); + transform: scale(0.1) rotate(30deg); + -webkit-transform-origin: center bottom; + transform-origin: center bottom; + } + + 50% { + -webkit-transform: rotate(-10deg); + transform: rotate(-10deg); + } + + 70% { + -webkit-transform: rotate(3deg); + transform: rotate(3deg); + } + + to { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} + +.jackInTheBox { + -webkit-animation-name: jackInTheBox; + animation-name: jackInTheBox; +} + +/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ + +@-webkit-keyframes rollIn { + from { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); + transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes rollIn { + from { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); + transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.rollIn { + -webkit-animation-name: rollIn; + animation-name: rollIn; +} + +/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ + +@-webkit-keyframes rollOut { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); + transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); + } +} + +@keyframes rollOut { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); + transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); + } +} + +.rollOut { + -webkit-animation-name: rollOut; + animation-name: rollOut; +} + +@-webkit-keyframes zoomIn { + from { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } + + 50% { + opacity: 1; + } +} + +@keyframes zoomIn { + from { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } + + 50% { + opacity: 1; + } +} + +.zoomIn { + -webkit-animation-name: zoomIn; + animation-name: zoomIn; +} + +@-webkit-keyframes zoomInDown { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +@keyframes zoomInDown { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +.zoomInDown { + -webkit-animation-name: zoomInDown; + animation-name: zoomInDown; +} + +@-webkit-keyframes zoomInLeft { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +@keyframes zoomInLeft { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +.zoomInLeft { + -webkit-animation-name: zoomInLeft; + animation-name: zoomInLeft; +} + +@-webkit-keyframes zoomInRight { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +@keyframes zoomInRight { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +.zoomInRight { + -webkit-animation-name: zoomInRight; + animation-name: zoomInRight; +} + +@-webkit-keyframes zoomInUp { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +@keyframes zoomInUp { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +.zoomInUp { + -webkit-animation-name: zoomInUp; + animation-name: zoomInUp; +} + +@-webkit-keyframes zoomOut { + from { + opacity: 1; + } + + 50% { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } + + to { + opacity: 0; + } +} + +@keyframes zoomOut { + from { + opacity: 1; + } + + 50% { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } + + to { + opacity: 0; + } +} + +.zoomOut { + -webkit-animation-name: zoomOut; + animation-name: zoomOut; +} + +@-webkit-keyframes zoomOutDown { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + to { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); + -webkit-transform-origin: center bottom; + transform-origin: center bottom; + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +@keyframes zoomOutDown { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + to { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); + -webkit-transform-origin: center bottom; + transform-origin: center bottom; + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +.zoomOutDown { + -webkit-animation-name: zoomOutDown; + animation-name: zoomOutDown; +} + +@-webkit-keyframes zoomOutLeft { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: scale(0.1) translate3d(-2000px, 0, 0); + transform: scale(0.1) translate3d(-2000px, 0, 0); + -webkit-transform-origin: left center; + transform-origin: left center; + } +} + +@keyframes zoomOutLeft { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: scale(0.1) translate3d(-2000px, 0, 0); + transform: scale(0.1) translate3d(-2000px, 0, 0); + -webkit-transform-origin: left center; + transform-origin: left center; + } +} + +.zoomOutLeft { + -webkit-animation-name: zoomOutLeft; + animation-name: zoomOutLeft; +} + +@-webkit-keyframes zoomOutRight { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: scale(0.1) translate3d(2000px, 0, 0); + transform: scale(0.1) translate3d(2000px, 0, 0); + -webkit-transform-origin: right center; + transform-origin: right center; + } +} + +@keyframes zoomOutRight { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: scale(0.1) translate3d(2000px, 0, 0); + transform: scale(0.1) translate3d(2000px, 0, 0); + -webkit-transform-origin: right center; + transform-origin: right center; + } +} + +.zoomOutRight { + -webkit-animation-name: zoomOutRight; + animation-name: zoomOutRight; +} + +@-webkit-keyframes zoomOutUp { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + to { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); + -webkit-transform-origin: center bottom; + transform-origin: center bottom; + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +@keyframes zoomOutUp { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + to { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); + -webkit-transform-origin: center bottom; + transform-origin: center bottom; + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +.zoomOutUp { + -webkit-animation-name: zoomOutUp; + animation-name: zoomOutUp; +} + +@-webkit-keyframes slideInDown { + from { + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes slideInDown { + from { + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.slideInDown { + -webkit-animation-name: slideInDown; + animation-name: slideInDown; +} + +@-webkit-keyframes slideInLeft { + from { + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes slideInLeft { + from { + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.slideInLeft { + -webkit-animation-name: slideInLeft; + animation-name: slideInLeft; +} + +@-webkit-keyframes slideInRight { + from { + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes slideInRight { + from { + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.slideInRight { + -webkit-animation-name: slideInRight; + animation-name: slideInRight; +} + +@-webkit-keyframes slideInUp { + from { + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes slideInUp { + from { + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.slideInUp { + -webkit-animation-name: slideInUp; + animation-name: slideInUp; +} + +@-webkit-keyframes slideOutDown { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } +} + +@keyframes slideOutDown { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } +} + +.slideOutDown { + -webkit-animation-name: slideOutDown; + animation-name: slideOutDown; +} + +@-webkit-keyframes slideOutLeft { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } +} + +@keyframes slideOutLeft { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } +} + +.slideOutLeft { + -webkit-animation-name: slideOutLeft; + animation-name: slideOutLeft; +} + +@-webkit-keyframes slideOutRight { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } +} + +@keyframes slideOutRight { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } +} + +.slideOutRight { + -webkit-animation-name: slideOutRight; + animation-name: slideOutRight; +} + +@-webkit-keyframes slideOutUp { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } +} + +@keyframes slideOutUp { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } +} + +.slideOutUp { + -webkit-animation-name: slideOutUp; + animation-name: slideOutUp; +} + +/* The typing effect */ +@keyframes typing { + from { + width: 0 + } + to { + width: 100% + } +} + +/* The typewriter cursor effect */ +@keyframes blink-caret { + from, to { + border-color: transparent + } + 50% { + border-color: orange + } } \ No newline at end of file diff --git a/main/app/sprinkles/core/assets/SiteAssets/css/main.css b/main/app/sprinkles/core/assets/SiteAssets/css/main.css index b308f8e..f68fab7 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/css/main.css +++ b/main/app/sprinkles/core/assets/SiteAssets/css/main.css @@ -1,511 +1,508 @@ -/****** -GENERAL -******/ -@import url('https://fonts.googleapis.com/css?family=Nanum+Gothic'); - -* { - -webkit-touch-callout: none; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-overflow-scrolling: touch; - - outline: none; - ie-dummy: expression(this.hideFocus=true); -} - -::-webkit-scrollbar { - width: 0; - background: transparent; - display: none; -} - -html, body { - font-family: 'Nanum Gothic', sans-serif; - height: 100%; - width: 100%; - overflow: hidden; - margin: 0; - padding: 0; - border: 0; -} - -a { - text-decoration: none; -} - -hr { - width: 100%; - display: block; - height: 1px; - border: 0; - margin: 1em 0; - padding: 0; -} - -img { - pointer-events: none; -} - -hr.ShorterLine { - margin: 0 auto; - width: 90%; -} - -.main { - height: 100%; -} - -/******* -SWIPEABLE -*******/ -.carousel-cell { - width: 100%; - height: 100%; - counter-increment: carousel-cell; -} - -.draggable, .slick-track { - height: 100%; -} - -/****** -HEADER -******/ -.header { - display: flex; - flex-wrap: nowrap; - justify-content: space-between; - align-content: center; - margin: 20px; -} - -.LeftButtonHeader { - width: 20px; - height: 20px; -} - -.RightButtonHeader { - width: 20px; - height: 20px; -} - -/*********** -GENERAL TABS -***********/ -.MainTabWindows, .MainInTab { - height: 100%; -} - -/********** -FEED WINDOW -**********/ -.FeedTabWindow { - position: relative; - max-height: calc(100% - 155px); /* navbar + some margin*/ - max-height: -moz-calc(100% - 155px); - max-height: -webkit-calc(100% - 155px); - max-width: 100%; - margin: 15px; - overflow-y: auto; - overflow-x: hidden; -} - -.FeedImageWrapper { - -} - -.FeedImageWrapper .UploaderInfo { - display: flex; - justify-content: space-around; - align-items: center; -} - -.FeedImageWrapper .UploaderInfo .UploaderAvatar { - height: 50px; - width: 50px; - -webkit-border-radius: 100px; - -moz-border-radius: 100px; - border-radius: 100px; -} - -.FeedImage { - display: block; - margin: 0 auto; - width: calc(100vw - 30px); /* left + right margin */ - width: -moz-calc(100vw - 30px); - width: -webkit-calc(100vw - 30px); - height: calc(100vw - 30px); /* TODO: Better feed wrapper height solution with avatar */ - height: -moz-calc(100vw - 30px); - height: -webkit-calc(100vw - 30px); - object-fit: cover; - -webkit-border-radius: 15px; - -moz-border-radius: 15px; - border-radius: 15px; -} - -/************* -EXPLORE WINDOW -*************/ -.ExploreTabWindow { - position: relative; - height: 100%; - margin: 5px; -} - -.UserSearchBar { - display: table; - box-sizing: border-box; - width: 80%; - height: 40px; - margin: 0 auto; - padding-left: 15px; - padding-right: 15px; - top: 0; /* 75+15 */ - z-index: 600; - border: none; - -webkit-border-radius: 25px; - -moz-border-radius: 25px; - border-radius: 25px; -} - -.SearchResults { - display: grid; - grid-template-columns: 10% 20% auto 10%; - overflow-y: auto; - max-height: 45%; - width: 100%; -} - -.SearchResults .Avatar { - grid-column-start: 2; - justify-self: center; - align-self: center; - height: 50px; - width: 50px; - -webkit-border-radius: 100%; - -moz-border-radius: 100%; - border-radius: 100%; -} - -.SearchResults .UsersFullName { - grid-column-start: 3; - justify-self: center; /* OR start */ - align-self: center; -} - -/********** -CHAT WINDOW -**********/ -.ChatWindow { - position: relative; - height: 100%; - margin: 5px; -} - -hr.ChatHeaderDivider { - margin-bottom: 0.6em; /* cause of symmetry things */ -} - -/* receiver select window */ -.SelectReceiver .ReceiverSelector { - display: grid; - grid-template-columns: 10% 20% auto 10%; - overflow-y: auto; - max-height: 45%; - width: 100%; - z-index: 9999; -} - -.SelectReceiver .ReceiverSelector .Avatar { - grid-column-start: 2; - justify-self: center; - align-self: center; - height: 50px; - width: 50px; - -webkit-border-radius: 100%; - -moz-border-radius: 100%; - border-radius: 100%; -} - -.SelectReceiver .ReceiverSelector .UsersFullName { - grid-column-start: 3; - justify-self: center; /* OR start */ - align-self: center; -} - -/* main chat */ -.SelectedReceiver { - display: none; - height: 100%; -} - -.ChatMessages { - overflow-y: scroll; - overflow-x: hidden; - max-height: calc(100% - 215px); /* navbar + input + some margin*/ - max-height: -moz-calc(100% - 215px); - max-height: -webkit-calc(100% - 215px); - height: 100%; - width: 100%; -} - -.ServerChatMessage { - display: inline-block; - position: relative; - left: 50%; - transform: translateX(-50%); - text-align: center; - padding: 5px; - -webkit-border-radius: 25px; - -moz-border-radius: 25px; - border-radius: 25px; - font-size: x-small; - animation: fadeIn 1s; - -webkit-animation: fadeIn 1s; -} - -.ChatMessage { - display: inline-block; - position: relative; - min-width: 50px; - max-width: 50%; - width: auto; - height: auto; - word-wrap: break-word; - text-align: center; - padding: 8px; - margin-bottom: 5px; - font-size: 0.85em; - -moz-transition: all .7s; - -o-transition: all .7s; - -webkit-transition: all .7s; - transition: all .7s; -} - -.MessageWrapper { - display: inline-block; - width: 100%; -} - -.TypingIndicatorMessage { - border-radius: 25px; -} - -.MessageSent { - clear: right; - float: right; -} - -.MessageReceived { - clear: left; - float: left; -} - -.AloneMessage { - -webkit-border-radius: 25px; - -moz-border-radius: 25px; - border-radius: 25px; -} - -.TopMessage { - -webkit-border-radius: 25px 25px 10px 10px; - -moz-border-radius: 25px 25px 10px 10px; - border-radius: 25px 25px 10px 10px; -} - -.MiddleMessage { - -webkit-border-radius: 10px; - -moz-border-radius: 10px; - border-radius: 10px; -} - -.BottomMessage { - -webkit-border-radius: 10px 10px 25px 25px; - -moz-border-radius: 10px 10px 25px 25px; - border-radius: 10px 10px 25px 25px; -} - -.ChatInput { - position: absolute; - box-sizing: border-box; - width: 100%; - height: 40px; - padding-left: 15px; - padding-right: 15px; - bottom: 165px; /* 75+15 MATH GENIUS */ - z-index: 600; - border: none; - -webkit-border-radius: 25px; - -moz-border-radius: 25px; - border-radius: 25px; -} - -/* TYPING INDICATOR ANIMATION */ -.spinner { - width: 70px; - text-align: center; -} - -.spinner > div { - width: 10px; - height: 10px; - - border-radius: 100%; - display: inline-block; - -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both; - animation: sk-bouncedelay 1.4s infinite ease-in-out both; -} - -.spinner .bounce1 { - -webkit-animation-delay: -0.32s; - animation-delay: -0.32s; -} - -.spinner .bounce2 { - -webkit-animation-delay: -0.16s; - animation-delay: -0.16s; -} - -@-webkit-keyframes sk-bouncedelay { - 0%, 80%, 100% { - -webkit-transform: scale(0) - } - 40% { - -webkit-transform: scale(1.0) - } -} - -@keyframes sk-bouncedelay { - 0%, 80%, 100% { - -webkit-transform: scale(0); - transform: scale(0); - } - 40% { - -webkit-transform: scale(1.0); - transform: scale(1.0); - } -} - -/********* -FRIEND TAB -*********/ -.FriendsTabWindow { - position: relative; - height: 100%; - margin: 5px; -} - -.FriendList { - display: grid; - grid-template-columns: 10% 20% auto 10%; - overflow-y: auto; - max-height: 45%; - width: 100%; -} - -.FriendList .Avatar { - grid-column-start: 2; - justify-self: center; - align-self: center; - height: 50px; - width: 50px; - -webkit-border-radius: 100%; - -moz-border-radius: 100%; - border-radius: 100%; -} - -.FriendList .FriendName { - grid-column-start: 3; - justify-self: center; /* OR start */ - align-self: center; -} - -/*********** -PERSONAL TAB -***********/ -.PersonalTabWindow { - position: relative; - height: 100%; - margin: 5px; -} - -.PersonalOverviewHeader { - display: flex; - justify-content: space-evenly; - align-items: flex-end; - width: 100%; -} - -.GenderFab { - height: 50px; - width: 50px; - -webkit-border-radius: 100%; - -moz-border-radius: 100%; - border-radius: 100%; - font-size: 25px; - line-height: 50px; - text-align: center; -} - -.PersonalOverviewHeader .Avatar { - height: 110px; - width: 110px; - -webkit-border-radius: 100%; - -moz-border-radius: 100%; - border-radius: 100%; -} - -.DisplayNames { - text-align: center; -} - -.DisplayNames .FullName { - font-weight: bold; - font-size: 20px; -} - -/***** -NAVBAR -*****/ -.Navbar { - display: flex; - flex-wrap: nowrap; - justify-content: center; - align-content: center; - position: absolute; - bottom: 0; - left: 0; - height: 75px; - width: 100%; -} - -.NavbarIconWrap { - width: calc(100vw / 5); - width: -moz-calc(100vw / 5); - width: -webkit-calc(100vw / 5); -} - -.NavbarIconWrap { - margin: auto; -} - -.NavbarIconWrap img { - display: block; - margin: 0 auto; - height: 30px; - width: 30px; -} - -.NavbarLine { - position: absolute; - bottom: 73px; - left: 0; - width: 20% !important; - height: 2px; -} - +/****** +GENERAL +******/ +@import url('https://fonts.googleapis.com/css?family=Nanum+Gothic'); + +* { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-overflow-scrolling: touch; + + outline: none; + ie-dummy: expression(this.hideFocus=true); +} + +::-webkit-scrollbar { + width: 0; + background: transparent; + display: none; +} + +html, body { + font-family: 'Nanum Gothic', sans-serif; + height: 100%; + width: 100%; + overflow: hidden; + margin: 0; + padding: 0; + border: 0; +} + +a { + text-decoration: none; +} + +hr { + width: 100%; + display: block; + height: 1px; + border: 0; + margin: 1em 0; + padding: 0; +} + +img { + pointer-events: none; +} + +hr.ShorterLine { + margin: 0 auto; + width: 90%; +} + +.main { + height: 100%; +} + +/******* +SWIPEABLE +*******/ +.carousel-cell { + width: 100%; + height: 100%; + counter-increment: carousel-cell; +} + +.draggable, .slick-track { + height: 100%; +} + +/****** +HEADER +******/ +.header { + display: flex; + flex-wrap: nowrap; + justify-content: space-between; + align-content: center; + margin: 20px; +} + +.LeftButtonHeader { + width: 20px; + height: 20px; +} + +.RightButtonHeader { + width: 20px; + height: 20px; +} + +/*********** +GENERAL TABS +***********/ +.MainTabWindows, .MainInTab { + height: 100%; +} + +/********** +FEED WINDOW +**********/ +.FeedTabWindow { + position: relative; + max-height: calc(100% - 155px); /* navbar + some margin*/ + max-height: -moz-calc(100% - 155px); + max-height: -webkit-calc(100% - 155px); + max-width: 100%; + margin: 15px; + overflow-y: auto; + overflow-x: hidden; +} + +.FeedImageWrapper .UploaderInfo { + display: flex; + justify-content: space-around; + align-items: center; + margin-bottom: 5px; +} + +.FeedImageWrapper .UploaderInfo .UploaderAvatar { + height: 50px; + width: 50px; + -webkit-border-radius: 100px; + -moz-border-radius: 100px; + border-radius: 100px; +} + +.FeedImage { + display: block; + margin: 0 auto; + width: calc(100vw - 30px); /* left + right margin */ + width: -moz-calc(100vw - 30px); + width: -webkit-calc(100vw - 30px); + height: calc(100vw - 30px); /* TODO: Better feed wrapper height solution with avatar */ + height: -moz-calc(100vw - 30px); + height: -webkit-calc(100vw - 30px); + object-fit: cover; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +/************* +EXPLORE WINDOW +*************/ +.ExploreTabWindow { + position: relative; + height: 100%; + margin: 5px; +} + +.UserSearchBar { + display: table; + box-sizing: border-box; + width: 80%; + height: 40px; + margin: 0 auto; + padding-left: 15px; + padding-right: 15px; + top: 0; /* 75+15 */ + z-index: 600; + border: none; + -webkit-border-radius: 25px; + -moz-border-radius: 25px; + border-radius: 25px; +} + +.SearchResults { + display: grid; + grid-template-columns: 10% 20% auto 10%; + overflow-y: auto; + max-height: 45%; + width: 100%; +} + +.SearchResults .Avatar { + grid-column-start: 2; + justify-self: center; + align-self: center; + height: 50px; + width: 50px; + -webkit-border-radius: 100%; + -moz-border-radius: 100%; + border-radius: 100%; +} + +.SearchResults .UsersFullName { + grid-column-start: 3; + justify-self: center; /* OR start */ + align-self: center; +} + +/********** +CHAT WINDOW +**********/ +.ChatWindow { + position: relative; + height: 100%; + margin: 5px; +} + +hr.ChatHeaderDivider { + margin-bottom: 0.6em; /* cause of symmetry things */ +} + +/* receiver select window */ +.SelectReceiver .ReceiverSelector { + display: grid; + grid-template-columns: 10% 20% auto 10%; + overflow-y: auto; + max-height: 45%; + width: 100%; + z-index: 9999; +} + +.SelectReceiver .ReceiverSelector .Avatar { + grid-column-start: 2; + justify-self: center; + align-self: center; + height: 50px; + width: 50px; + -webkit-border-radius: 100%; + -moz-border-radius: 100%; + border-radius: 100%; +} + +.SelectReceiver .ReceiverSelector .UsersFullName { + grid-column-start: 3; + justify-self: center; /* OR start */ + align-self: center; +} + +/* main chat */ +.SelectedReceiver { + display: none; + height: 100%; +} + +.ChatMessages { + overflow-y: scroll; + overflow-x: hidden; + max-height: calc(100% - 215px); /* navbar + input + some margin*/ + max-height: -moz-calc(100% - 215px); + max-height: -webkit-calc(100% - 215px); + height: 100%; + width: 100%; +} + +.ServerChatMessage { + display: inline-block; + position: relative; + left: 50%; + transform: translateX(-50%); + text-align: center; + padding: 5px; + -webkit-border-radius: 25px; + -moz-border-radius: 25px; + border-radius: 25px; + font-size: x-small; + animation: fadeIn 1s; + -webkit-animation: fadeIn 1s; +} + +.ChatMessage { + display: inline-block; + position: relative; + min-width: 50px; + max-width: 50%; + width: auto; + height: auto; + word-wrap: break-word; + text-align: center; + padding: 8px; + margin-bottom: 5px; + font-size: 0.85em; + -moz-transition: all .7s; + -o-transition: all .7s; + -webkit-transition: all .7s; + transition: all .7s; +} + +.MessageWrapper { + display: inline-block; + width: 100%; +} + +.TypingIndicatorMessage { + border-radius: 25px; +} + +.MessageSent { + clear: right; + float: right; +} + +.MessageReceived { + clear: left; + float: left; +} + +.AloneMessage { + -webkit-border-radius: 25px; + -moz-border-radius: 25px; + border-radius: 25px; +} + +.TopMessage { + -webkit-border-radius: 25px 25px 10px 10px; + -moz-border-radius: 25px 25px 10px 10px; + border-radius: 25px 25px 10px 10px; +} + +.MiddleMessage { + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; +} + +.BottomMessage { + -webkit-border-radius: 10px 10px 25px 25px; + -moz-border-radius: 10px 10px 25px 25px; + border-radius: 10px 10px 25px 25px; +} + +.ChatInput { + position: absolute; + box-sizing: border-box; + width: 100%; + height: 40px; + padding-left: 15px; + padding-right: 15px; + bottom: 165px; /* 75+15 MATH GENIUS */ + z-index: 600; + border: none; + -webkit-border-radius: 25px; + -moz-border-radius: 25px; + border-radius: 25px; +} + +/* TYPING INDICATOR ANIMATION */ +.spinner { + width: 70px; + text-align: center; +} + +.spinner > div { + width: 10px; + height: 10px; + + border-radius: 100%; + display: inline-block; + -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both; + animation: sk-bouncedelay 1.4s infinite ease-in-out both; +} + +.spinner .bounce1 { + -webkit-animation-delay: -0.32s; + animation-delay: -0.32s; +} + +.spinner .bounce2 { + -webkit-animation-delay: -0.16s; + animation-delay: -0.16s; +} + +@-webkit-keyframes sk-bouncedelay { + 0%, 80%, 100% { + -webkit-transform: scale(0) + } + 40% { + -webkit-transform: scale(1.0) + } +} + +@keyframes sk-bouncedelay { + 0%, 80%, 100% { + -webkit-transform: scale(0); + transform: scale(0); + } + 40% { + -webkit-transform: scale(1.0); + transform: scale(1.0); + } +} + +/********* +FRIEND TAB +*********/ +.FriendsTabWindow { + position: relative; + height: 100%; + margin: 5px; +} + +.FriendList { + display: grid; + grid-template-columns: 10% 20% auto 10%; + overflow-y: auto; + max-height: 45%; + width: 100%; +} + +.FriendList .Avatar { + grid-column-start: 2; + justify-self: center; + align-self: center; + height: 50px; + width: 50px; + -webkit-border-radius: 100%; + -moz-border-radius: 100%; + border-radius: 100%; +} + +.FriendList .FriendName { + grid-column-start: 3; + justify-self: center; /* OR start */ + align-self: center; +} + +/*********** +PERSONAL TAB +***********/ +.PersonalTabWindow { + position: relative; + height: 100%; + margin: 5px; +} + +.PersonalOverviewHeader { + display: flex; + justify-content: space-evenly; + align-items: flex-end; + width: 100%; +} + +.GenderFab { + height: 50px; + width: 50px; + -webkit-border-radius: 100%; + -moz-border-radius: 100%; + border-radius: 100%; + font-size: 25px; + line-height: 50px; + text-align: center; +} + +.PersonalOverviewHeader .Avatar { + height: 110px; + width: 110px; + -webkit-border-radius: 100%; + -moz-border-radius: 100%; + border-radius: 100%; +} + +.DisplayNames { + text-align: center; +} + +.DisplayNames .FullName { + font-weight: bold; + font-size: 20px; +} + +/***** +NAVBAR +*****/ +.Navbar { + display: flex; + flex-wrap: nowrap; + justify-content: center; + align-content: center; + position: absolute; + bottom: 0; + left: 0; + height: 75px; + width: 100%; +} + +.NavbarIconWrap { + width: calc(100vw / 5); + width: -moz-calc(100vw / 5); + width: -webkit-calc(100vw / 5); +} + +.NavbarIconWrap { + margin: auto; +} + +.NavbarIconWrap img { + display: block; + margin: 0 auto; + height: 30px; + width: 30px; +} + +.NavbarLine { + position: absolute; + bottom: 73px; + left: 0; + width: 20% !important; + height: 2px; +} + diff --git a/main/app/sprinkles/core/assets/SiteAssets/css/normalize.css b/main/app/sprinkles/core/assets/SiteAssets/css/normalize.css index 30adf56..4d97cab 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/css/normalize.css +++ b/main/app/sprinkles/core/assets/SiteAssets/css/normalize.css @@ -1,341 +1,341 @@ -/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */ - -/* Document - ========================================================================== */ - -/** - * 1. Correct the line height in all browsers. - * 2. Prevent adjustments of font size after orientation changes in iOS. - */ - -html { - line-height: 1.15; /* 1 */ - -webkit-text-size-adjust: 100%; /* 2 */ -} - -/* Sections - ========================================================================== */ - -/** - * Remove the margin in all browsers. - */ - -body { - margin: 0; -} - -/** - * Correct the font size and margin on `h1` elements within `section` and - * `article` contexts in Chrome, Firefox, and Safari. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/* Grouping content - ========================================================================== */ - -/** - * 1. Add the correct box sizing in Firefox. - * 2. Show the overflow in Edge and IE. - */ - -hr { - box-sizing: content-box; /* 1 */ - height: 0; /* 1 */ - overflow: visible; /* 2 */ -} - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -pre { - font-family: monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/* Text-level semantics - ========================================================================== */ - -/** - * Remove the gray background on active links in IE 10. - */ - -a { - background-color: transparent; -} - -/** - * 1. Remove the bottom border in Chrome 57- - * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. - */ - -abbr[title] { - border-bottom: none; /* 1 */ - text-decoration: underline; /* 2 */ - text-decoration: underline dotted; /* 2 */ -} - -/** - * Add the correct font weight in Chrome, Edge, and Safari. - */ - -b, -strong { - font-weight: bolder; -} - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -code, -kbd, -samp { - font-family: monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/** - * Add the correct font size in all browsers. - */ - -small { - font-size: 80%; -} - -/** - * Prevent `sub` and `sup` elements from affecting the line height in - * all browsers. - */ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* Embedded content - ========================================================================== */ - -/** - * Remove the border on images inside links in IE 10. - */ - -img { - border-style: none; -} - -/* Forms - ========================================================================== */ - -/** - * 1. Change the font styles in all browsers. - * 2. Remove the margin in Firefox and Safari. - */ - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; /* 1 */ - font-size: 100%; /* 1 */ - line-height: 1.15; /* 1 */ - margin: 0; /* 2 */ -} - -/** - * Show the overflow in IE. - * 1. Show the overflow in Edge. - */ - -button, -input { /* 1 */ - overflow: visible; -} - -/** - * Remove the inheritance of text transform in Edge, Firefox, and IE. - * 1. Remove the inheritance of text transform in Firefox. - */ - -button, -select { /* 1 */ - text-transform: none; -} - -/** - * Correct the inability to style clickable types in iOS and Safari. - */ - -button, -[type="button"], -[type="reset"], -[type="submit"] { - -webkit-appearance: button; -} - -/** - * Remove the inner border and padding in Firefox. - */ - -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - border-style: none; - padding: 0; -} - -/** - * Restore the focus styles unset by the previous rule. - */ - -button:-moz-focusring, -[type="button"]:-moz-focusring, -[type="reset"]:-moz-focusring, -[type="submit"]:-moz-focusring { - outline: 1px dotted ButtonText; -} - -/** - * Correct the padding in Firefox. - */ - -fieldset { - padding: 0.35em 0.75em 0.625em; -} - -/** - * 1. Correct the text wrapping in Edge and IE. - * 2. Correct the color inheritance from `fieldset` elements in IE. - * 3. Remove the padding so developers are not caught out when they zero out - * `fieldset` elements in all browsers. - */ - -legend { - box-sizing: border-box; /* 1 */ - color: inherit; /* 2 */ - display: table; /* 1 */ - max-width: 100%; /* 1 */ - padding: 0; /* 3 */ - white-space: normal; /* 1 */ -} - -/** - * Add the correct vertical alignment in Chrome, Firefox, and Opera. - */ - -progress { - vertical-align: baseline; -} - -/** - * Remove the default vertical scrollbar in IE 10+. - */ - -textarea { - overflow: auto; -} - -/** - * 1. Add the correct box sizing in IE 10. - * 2. Remove the padding in IE 10. - */ - -[type="checkbox"], -[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Correct the cursor style of increment and decrement buttons in Chrome. - */ - -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -/** - * 1. Correct the odd appearance in Chrome and Safari. - * 2. Correct the outline style in Safari. - */ - -[type="search"] { - -webkit-appearance: textfield; /* 1 */ - outline-offset: -2px; /* 2 */ -} - -/** - * Remove the inner padding in Chrome and Safari on macOS. - */ - -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -/** - * 1. Correct the inability to style clickable types in iOS and Safari. - * 2. Change font properties to `inherit` in Safari. - */ - -::-webkit-file-upload-button { - -webkit-appearance: button; /* 1 */ - font: inherit; /* 2 */ -} - -/* Interactive - ========================================================================== */ - -/* - * Add the correct display in Edge, IE 10+, and Firefox. - */ - -details { - display: block; -} - -/* - * Add the correct display in all browsers. - */ - -summary { - display: list-item; -} - -/* Misc - ========================================================================== */ - -/** - * Add the correct display in IE 10+. - */ - -template { - display: none; -} - -/** - * Add the correct display in IE 10. - */ - -[hidden] { - display: none; +/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers. + */ + +body { + margin: 0; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Remove the gray background on active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10. + */ + +img { + border-style: none; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * Correct the inability to style clickable types in iOS and Safari. + */ + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Remove the default vertical scrollbar in IE 10+. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in Edge, IE 10+, and Firefox. + */ + +details { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Misc + ========================================================================== */ + +/** + * Add the correct display in IE 10+. + */ + +template { + display: none; +} + +/** + * Add the correct display in IE 10. + */ + +[hidden] { + display: none; } \ No newline at end of file diff --git a/main/app/sprinkles/core/assets/SiteAssets/css/swiper.css b/main/app/sprinkles/core/assets/SiteAssets/css/swiper.css index 5910f93..c93582c 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/css/swiper.css +++ b/main/app/sprinkles/core/assets/SiteAssets/css/swiper.css @@ -1,104 +1,104 @@ -.slick-slider { - position: relative; - display: block; - box-sizing: border-box; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-touch-callout: none; - -khtml-user-select: none; - -ms-touch-action: pan-y; - touch-action: pan-y; - -webkit-tap-highlight-color: transparent -} - -.slick-list { - position: relative; - display: block; - overflow: hidden; - margin: 0; - padding: 0 -} - -.slick-list:focus { - outline: 0 -} - -.slick-list.dragging { - cursor: pointer; - cursor: hand -} - -.slick-slider .slick-list, .slick-slider .slick-track { - -webkit-transform: translate3d(0, 0, 0); - -moz-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - -o-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0) -} - -.slick-track { - position: relative; - top: 0; - left: 0; - display: block; - margin-left: auto; - margin-right: auto -} - -.slick-track:after, .slick-track:before { - display: table; - content: '' -} - -.slick-track:after { - clear: both -} - -.slick-loading .slick-track { - visibility: hidden -} - -.slick-slide { - display: none; - float: left; - height: 100%; - min-height: 1px -} - -[dir=rtl] .slick-slide { - float: right -} - -.slick-slide img { - display: block -} - -.slick-slide.slick-loading img { - display: none -} - -.slick-slide.dragging img { - pointer-events: none -} - -.slick-initialized .slick-slide { - display: block -} - -.slick-loading .slick-slide { - visibility: hidden -} - -.slick-vertical .slick-slide { - display: block; - height: auto; - border: 1px solid transparent -} - -.slick-arrow.slick-hidden { - display: none -} - +.slick-slider { + position: relative; + display: block; + box-sizing: border-box; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-touch-callout: none; + -khtml-user-select: none; + -ms-touch-action: pan-y; + touch-action: pan-y; + -webkit-tap-highlight-color: transparent +} + +.slick-list { + position: relative; + display: block; + overflow: hidden; + margin: 0; + padding: 0 +} + +.slick-list:focus { + outline: 0 +} + +.slick-list.dragging { + cursor: pointer; + cursor: hand +} + +.slick-slider .slick-list, .slick-slider .slick-track { + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0) +} + +.slick-track { + position: relative; + top: 0; + left: 0; + display: block; + margin-left: auto; + margin-right: auto +} + +.slick-track:after, .slick-track:before { + display: table; + content: '' +} + +.slick-track:after { + clear: both +} + +.slick-loading .slick-track { + visibility: hidden +} + +.slick-slide { + display: none; + float: left; + height: 100%; + min-height: 1px +} + +[dir=rtl] .slick-slide { + float: right +} + +.slick-slide img { + display: block +} + +.slick-slide.slick-loading img { + display: none +} + +.slick-slide.dragging img { + pointer-events: none +} + +.slick-initialized .slick-slide { + display: block +} + +.slick-loading .slick-slide { + visibility: hidden +} + +.slick-vertical .slick-slide { + display: block; + height: auto; + border: 1px solid transparent +} + +.slick-arrow.slick-hidden { + display: none +} + /*# sourceMappingURL=slick.min.css.map */ \ No newline at end of file diff --git a/main/app/sprinkles/core/assets/SiteAssets/icons/BurgerMenuShort.svg b/main/app/sprinkles/core/assets/SiteAssets/icons/BurgerMenuShort.svg index 86f3718..9e83715 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/icons/BurgerMenuShort.svg +++ b/main/app/sprinkles/core/assets/SiteAssets/icons/BurgerMenuShort.svg @@ -1,57 +1,57 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/app/sprinkles/core/assets/SiteAssets/icons/BurgerMenuShortActivated.svg b/main/app/sprinkles/core/assets/SiteAssets/icons/BurgerMenuShortActivated.svg index fa3c428..b0f70f5 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/icons/BurgerMenuShortActivated.svg +++ b/main/app/sprinkles/core/assets/SiteAssets/icons/BurgerMenuShortActivated.svg @@ -1,57 +1,57 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/app/sprinkles/core/assets/SiteAssets/icons/ExploreGlobeOutline.svg b/main/app/sprinkles/core/assets/SiteAssets/icons/ExploreGlobeOutline.svg index ebec16b..3a90499 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/icons/ExploreGlobeOutline.svg +++ b/main/app/sprinkles/core/assets/SiteAssets/icons/ExploreGlobeOutline.svg @@ -1,210 +1,210 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/app/sprinkles/core/assets/SiteAssets/icons/ExploreGlobeOutlineActivated.svg b/main/app/sprinkles/core/assets/SiteAssets/icons/ExploreGlobeOutlineActivated.svg index 193a92f..254327f 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/icons/ExploreGlobeOutlineActivated.svg +++ b/main/app/sprinkles/core/assets/SiteAssets/icons/ExploreGlobeOutlineActivated.svg @@ -1,210 +1,210 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/app/sprinkles/core/assets/SiteAssets/icons/FriendFeedOutline.svg b/main/app/sprinkles/core/assets/SiteAssets/icons/FriendFeedOutline.svg index d4fd052..cb0336b 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/icons/FriendFeedOutline.svg +++ b/main/app/sprinkles/core/assets/SiteAssets/icons/FriendFeedOutline.svg @@ -1,82 +1,82 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/app/sprinkles/core/assets/SiteAssets/icons/FriendFeedOutlineActivated.svg b/main/app/sprinkles/core/assets/SiteAssets/icons/FriendFeedOutlineActivated.svg index cfeea52..32efca8 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/icons/FriendFeedOutlineActivated.svg +++ b/main/app/sprinkles/core/assets/SiteAssets/icons/FriendFeedOutlineActivated.svg @@ -1,82 +1,82 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/app/sprinkles/core/assets/SiteAssets/icons/MessageBubbleOutline.svg b/main/app/sprinkles/core/assets/SiteAssets/icons/MessageBubbleOutline.svg index b2706bc..2d52f5b 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/icons/MessageBubbleOutline.svg +++ b/main/app/sprinkles/core/assets/SiteAssets/icons/MessageBubbleOutline.svg @@ -1,73 +1,73 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/app/sprinkles/core/assets/SiteAssets/icons/MessageBubbleOutlineActivated.svg b/main/app/sprinkles/core/assets/SiteAssets/icons/MessageBubbleOutlineActivated.svg index a638d21..7b2823a 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/icons/MessageBubbleOutlineActivated.svg +++ b/main/app/sprinkles/core/assets/SiteAssets/icons/MessageBubbleOutlineActivated.svg @@ -1,73 +1,73 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/app/sprinkles/core/assets/SiteAssets/icons/UserGroupOutline.svg b/main/app/sprinkles/core/assets/SiteAssets/icons/UserGroupOutline.svg index dd98e46..48852f8 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/icons/UserGroupOutline.svg +++ b/main/app/sprinkles/core/assets/SiteAssets/icons/UserGroupOutline.svg @@ -1,80 +1,80 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/app/sprinkles/core/assets/SiteAssets/icons/UserGroupOutlineActivated.svg b/main/app/sprinkles/core/assets/SiteAssets/icons/UserGroupOutlineActivated.svg index 3c385f9..2b7c8ad 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/icons/UserGroupOutlineActivated.svg +++ b/main/app/sprinkles/core/assets/SiteAssets/icons/UserGroupOutlineActivated.svg @@ -1,80 +1,80 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/app/sprinkles/core/assets/SiteAssets/icons/UserOutline.svg b/main/app/sprinkles/core/assets/SiteAssets/icons/UserOutline.svg index a15f174..20fd63e 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/icons/UserOutline.svg +++ b/main/app/sprinkles/core/assets/SiteAssets/icons/UserOutline.svg @@ -1,54 +1,54 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/app/sprinkles/core/assets/SiteAssets/icons/UserOutlineActivated.svg b/main/app/sprinkles/core/assets/SiteAssets/icons/UserOutlineActivated.svg index f3a2bc6..fde6caf 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/icons/UserOutlineActivated.svg +++ b/main/app/sprinkles/core/assets/SiteAssets/icons/UserOutlineActivated.svg @@ -1,54 +1,54 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/app/sprinkles/core/assets/SiteAssets/js/asemica.js b/main/app/sprinkles/core/assets/SiteAssets/js/asemica.js index 7366aaf..28183cf 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/js/asemica.js +++ b/main/app/sprinkles/core/assets/SiteAssets/js/asemica.js @@ -1,239 +1,239 @@ -function asemica(Text, CorpusUrl, Intent = "enc") { - let CorpusString, Tokens, Transitions; - - fetch(CorpusUrl) - .then(function (response) { - response.text().then(function (response) { - CorpusString = response; - Tokens = TokenizeCorpus(CorpusString); - Transitions = GenerateTransitions(Tokens); - if (!VerifyExists(Transitions)) { - throw new Error("Please choose another text."); - } else { - switch (Intent) { - case "enc": - //return Encode(Text, Transitions, Tokens); - console.log(Encode(Text, Transitions, Tokens)); - break; - case "dec": - //return Decode(Text, Transitions, Tokens); - console.log(Decode(Text, Transitions, Tokens)); - break; - } - } - }); - }); - - - /** - * Encodes an input string using the transition matrix calculated from the corpus - * - * @return {string} - */ - function Encode(Input, Transitions, Tokens) { - var Nibbles = str2nibble(Input); - var Token = Tokens[Math.round(Math.random() * (Tokens.length - 1) + 1)]; - var EncodedText = ""; - - while (Nibbles.length) { - if ("meaningful" in Transitions[Token.toLowerCase()]) { // Token is meaningful - EncodedText += Token + " "; - - var Nibble = Nibbles.shift(); - Token = Transitions[Token.toLowerCase()]["door"][Nibble]; - } else { // Token is irrelevant -> go through random door - EncodedText += Token + " "; - - var RandomDoorNumber = Math.round(Math.random() * (Transitions[Token.toLowerCase()]["doors"] - 1) + 1); // Fix for a annoying bug (count from 1 but array is 0) - if (RandomDoorNumber === 1 || RandomDoorNumber === Transitions[Token.toLowerCase()]["doors"]) RandomDoorNumber--; - Token = Transitions[Token.toLowerCase()]["door"][RandomDoorNumber]; - } - - if (Token === undefined) throw new Error("Token is undefined, please report this error to the developer."); - } - - EncodedText += Token + ""; - return EncodedText; - } - - /** - * Pieces an arbitrary binary sequence back together from ASCII input - */ - function Decode(Input, Transitions, Tokens) { - Input = CleanInput(Input); - var DecodedText = ""; - var Words = Input.split(/\s+/); - - Words.slice(0, -1).forEach(function (Word, i) { - if ("meaningful" in Transitions[Words[i].toLowerCase()]) { - var NumDoors = Transitions[Words[i].toLowerCase()]["door"]; - NumDoors.forEach(function (NumDoor, j) { - var OnDoor = (Transitions[Words[i].toLowerCase()]["door"][j]).toLowerCase(); - if (OnDoor === Words[i + 1].toLowerCase()) { - console.log(j); - var Binary = dec2bin(j); - while (Binary.length < 4) { - Binary = "0" + Binary; - } - DecodedText += Binary; - } - }) - } - }); - - console.log(DecodedText); - } - - - function CleanInput(Input) { - Input - .replace(/\n/g, " ") // newlines - .replace(/<\/?[^>]+(>|$)/g, "") // html - .replace(/[^\w']/g, " ") // non-word characters - .replace(/[0-9]/g, " ") // numbers - .replace(/\s\s+/g, " ") // sequences of spaces - .replace(/^\s+/, "") // leading whitespace - .replace(/\s+$/, ""); // trailing whitespace - - return Input; - } - - - /* - * Breaks the input corpus into a series of processable "tokens" - * - * Example output: ['The','Project','Gutenberg', ... ,'about','new','eBooks'] - */ - function TokenizeCorpus(CorpusString) { - // Clean up things - const StrippedCorpus = CleanInput(CorpusString); - - Tokens = StrippedCorpus.split(/\s/); - - return Tokens; - } - - /* - * Creates the primary transition matrix - * - * Example output: - * - * 'atlantic' => { // Lowercase form - * 'seen' => 2, // How many times seen in corpus - * 'exits' => { // Which words follow it? - * 'City' => 1, // One instance of this - * 'and' => 1 // One instance of that - * }, // Exits not guaranteed unique - * 'door' => [ // Doors are guaranteed unique exits - * 'City', // Following door number 1 - * 'and' // Following door number 2 - * ], - * 'doors' => 2, // Cached count of doors - * 'token' => 'Atlantic' // Original form of the token - * } - * ... - */ - function GenerateTransitions(Tokens) { - Transitions = {}; - - Tokens.forEach(function (Token, Index) { - var ObjectKey = Token.toLowerCase(); - if (!(ObjectKey in Transitions)) Transitions[ObjectKey] = {}; - if (!("exits" in Transitions[ObjectKey])) Transitions[ObjectKey]["exits"] = {}; - - Transitions[ObjectKey]["seen"] += 1; - Transitions[ObjectKey]["token"] = ObjectKey; - if (Tokens[Index + 1] !== undefined) { - Transitions[ObjectKey]["exits"][Tokens[Index + 1]]++; - } - }); - - // Calculate the exits and doors - for (var Transition in Transitions) { - var Exits = Transitions[Transition]["exits"]; - var Found = {}; - Transitions[Transition]["door"] = []; - - for (var Exit in Exits) { - if (!(Exit.toLowerCase() in Found)) Transitions[Transition]["door"].push(Exit.toLowerCase()); - Found[Exit.toLowerCase()] = 1; - } - - Transitions[Transition]["doors"] = Transitions[Transition]["door"].length; - if (Transitions[Transition]["doors"] > 15) Transitions[Transition]["meaningful"] = 1; - } - - return Transitions; - } - - /** - * Returns whether this corpus will work well as an encoding or decoding medium - * - * @return {boolean} - */ - function VerifyExists(Transitions) { - var Count = 0; - - for (var Key in Transitions) { - if (Transitions[Key]["doors"] > 15) { - Count++; - } - } - return Count >= 7; - } - - /** - * Converts a string to several 4bit binary (nibbles) and then to dec - */ - function str2nibble(str) { - str = str + " \n"; - - var DecBytes = []; - var Nibbles = []; - - for (var i = 0, n = str.length; i < n; i++) { // str to dec - var char = str.charCodeAt(i); - DecBytes.push(char & 0xFF); - } - - DecBytes.forEach(function (Byte, Index) { - Byte = dec2bin(Byte); // dec to bin - var FistByteNibble = Byte.slice(-4); - var SecondByteNibble = Byte.slice(0, -4).length === 4 ? Byte.slice(0, -4) : 0 + Byte.slice(0, -4); - Nibbles.push(bin2dec((FistByteNibble).split("").reverse().join(""))); // formatted bin to dec - Nibbles.push(bin2dec((SecondByteNibble).split("").reverse().join(""))); // formatted bin to dec - }); - - Nibbles = Nibbles.concat([0, 4, 5, 0]); - - console.log(Nibbles.join(", ")); - - return Nibbles; - } - - /** - * Converts several dec converted 4bit binary (nibbles) to a string - */ - function nibble2str(DecNibbles) { - var BinNibbles = ""; - - DecNibbles.forEach(function(DecNibble) { - BinNibbles += dec2bin(DecNibble); - }) - } - - /** - * Converts a decimal value to binary - */ - function dec2bin(dec) { - return (dec >>> 0).toString(2); - } - - /** - * Converts a binary value to decimal - */ - function bin2dec(bin) { - return parseInt(bin, 2); - } - -} +function asemica(Text, CorpusUrl, Intent = "enc") { + let CorpusString, Tokens, Transitions; + + fetch(CorpusUrl) + .then(function (response) { + response.text().then(function (response) { + CorpusString = response; + Tokens = TokenizeCorpus(CorpusString); + Transitions = GenerateTransitions(Tokens); + if (!VerifyExists(Transitions)) { + throw new Error("Please choose another text."); + } else { + switch (Intent) { + case "enc": + //return Encode(Text, Transitions, Tokens); + console.log(Encode(Text, Transitions, Tokens)); + break; + case "dec": + //return Decode(Text, Transitions, Tokens); + console.log(Decode(Text, Transitions, Tokens)); + break; + } + } + }); + }); + + + /** + * Encodes an input string using the transition matrix calculated from the corpus + * + * @return {string} + */ + function Encode(Input, Transitions, Tokens) { + var Nibbles = str2nibble(Input); + var Token = Tokens[Math.round(Math.random() * (Tokens.length - 1) + 1)]; + var EncodedText = ""; + + while (Nibbles.length) { + if ("meaningful" in Transitions[Token.toLowerCase()]) { // Token is meaningful + EncodedText += Token + " "; + + var Nibble = Nibbles.shift(); + Token = Transitions[Token.toLowerCase()]["door"][Nibble]; + } else { // Token is irrelevant -> go through random door + EncodedText += Token + " "; + + var RandomDoorNumber = Math.round(Math.random() * (Transitions[Token.toLowerCase()]["doors"] - 1) + 1); // Fix for a annoying bug (count from 1 but array is 0) + if (RandomDoorNumber === 1 || RandomDoorNumber === Transitions[Token.toLowerCase()]["doors"]) RandomDoorNumber--; + Token = Transitions[Token.toLowerCase()]["door"][RandomDoorNumber]; + } + + if (Token === undefined) throw new Error("Token is undefined, please report this error to the developer."); + } + + EncodedText += Token + ""; + return EncodedText; + } + + /** + * Pieces an arbitrary binary sequence back together from ASCII input + */ + function Decode(Input, Transitions, Tokens) { + Input = CleanInput(Input); + var DecodedText = ""; + var Words = Input.split(/\s+/); + + Words.slice(0, -1).forEach(function (Word, i) { + if ("meaningful" in Transitions[Words[i].toLowerCase()]) { + var NumDoors = Transitions[Words[i].toLowerCase()]["door"]; + NumDoors.forEach(function (NumDoor, j) { + var OnDoor = (Transitions[Words[i].toLowerCase()]["door"][j]).toLowerCase(); + if (OnDoor === Words[i + 1].toLowerCase()) { + console.log(j); + var Binary = dec2bin(j); + while (Binary.length < 4) { + Binary = "0" + Binary; + } + DecodedText += Binary; + } + }) + } + }); + + console.log(DecodedText); + } + + + function CleanInput(Input) { + Input + .replace(/\n/g, " ") // newlines + .replace(/<\/?[^>]+(>|$)/g, "") // html + .replace(/[^\w']/g, " ") // non-word characters + .replace(/[0-9]/g, " ") // numbers + .replace(/\s\s+/g, " ") // sequences of spaces + .replace(/^\s+/, "") // leading whitespace + .replace(/\s+$/, ""); // trailing whitespace + + return Input; + } + + + /* + * Breaks the input corpus into a series of processable "tokens" + * + * Example output: ['The','Project','Gutenberg', ... ,'about','new','eBooks'] + */ + function TokenizeCorpus(CorpusString) { + // Clean up things + const StrippedCorpus = CleanInput(CorpusString); + + Tokens = StrippedCorpus.split(/\s/); + + return Tokens; + } + + /* + * Creates the primary transition matrix + * + * Example output: + * + * 'atlantic' => { // Lowercase form + * 'seen' => 2, // How many times seen in corpus + * 'exits' => { // Which words follow it? + * 'City' => 1, // One instance of this + * 'and' => 1 // One instance of that + * }, // Exits not guaranteed unique + * 'door' => [ // Doors are guaranteed unique exits + * 'City', // Following door number 1 + * 'and' // Following door number 2 + * ], + * 'doors' => 2, // Cached count of doors + * 'token' => 'Atlantic' // Original form of the token + * } + * ... + */ + function GenerateTransitions(Tokens) { + Transitions = {}; + + Tokens.forEach(function (Token, Index) { + var ObjectKey = Token.toLowerCase(); + if (!(ObjectKey in Transitions)) Transitions[ObjectKey] = {}; + if (!("exits" in Transitions[ObjectKey])) Transitions[ObjectKey]["exits"] = {}; + + Transitions[ObjectKey]["seen"] += 1; + Transitions[ObjectKey]["token"] = ObjectKey; + if (Tokens[Index + 1] !== undefined) { + Transitions[ObjectKey]["exits"][Tokens[Index + 1]]++; + } + }); + + // Calculate the exits and doors + for (var Transition in Transitions) { + var Exits = Transitions[Transition]["exits"]; + var Found = {}; + Transitions[Transition]["door"] = []; + + for (var Exit in Exits) { + if (!(Exit.toLowerCase() in Found)) Transitions[Transition]["door"].push(Exit.toLowerCase()); + Found[Exit.toLowerCase()] = 1; + } + + Transitions[Transition]["doors"] = Transitions[Transition]["door"].length; + if (Transitions[Transition]["doors"] > 15) Transitions[Transition]["meaningful"] = 1; + } + + return Transitions; + } + + /** + * Returns whether this corpus will work well as an encoding or decoding medium + * + * @return {boolean} + */ + function VerifyExists(Transitions) { + var Count = 0; + + for (var Key in Transitions) { + if (Transitions[Key]["doors"] > 15) { + Count++; + } + } + return Count >= 7; + } + + /** + * Converts a string to several 4bit binary (nibbles) and then to dec + */ + function str2nibble(str) { + str = str + " \n"; + + var DecBytes = []; + var Nibbles = []; + + for (var i = 0, n = str.length; i < n; i++) { // str to dec + var char = str.charCodeAt(i); + DecBytes.push(char & 0xFF); + } + + DecBytes.forEach(function (Byte, Index) { + Byte = dec2bin(Byte); // dec to bin + var FistByteNibble = Byte.slice(-4); + var SecondByteNibble = Byte.slice(0, -4).length === 4 ? Byte.slice(0, -4) : 0 + Byte.slice(0, -4); + Nibbles.push(bin2dec((FistByteNibble).split("").reverse().join(""))); // formatted bin to dec + Nibbles.push(bin2dec((SecondByteNibble).split("").reverse().join(""))); // formatted bin to dec + }); + + Nibbles = Nibbles.concat([0, 4, 5, 0]); + + console.log(Nibbles.join(", ")); + + return Nibbles; + } + + /** + * Converts several dec converted 4bit binary (nibbles) to a string + */ + function nibble2str(DecNibbles) { + var BinNibbles = ""; + + DecNibbles.forEach(function(DecNibble) { + BinNibbles += dec2bin(DecNibble); + }) + } + + /** + * Converts a decimal value to binary + */ + function dec2bin(dec) { + return (dec >>> 0).toString(2); + } + + /** + * Converts a binary value to decimal + */ + function bin2dec(bin) { + return parseInt(bin, 2); + } + +} diff --git a/main/app/sprinkles/core/assets/SiteAssets/js/asemica.pl b/main/app/sprinkles/core/assets/SiteAssets/js/asemica.pl index a9fc266..05bcac0 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/js/asemica.pl +++ b/main/app/sprinkles/core/assets/SiteAssets/js/asemica.pl @@ -1,625 +1,625 @@ -#!/usr/bin/perl -w -use strict; -use warnings; - - -### -# Asemica -- An asemic Markov-chained cipher -# Copyright (c) 2011 by Danne Stayskal -### - -### -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -### - -our $VERSION = '1.0'; - -use Getopt::Long; - -my $corpus_file = ''; -my $input_file = ''; -my $output_file = ''; -my $verbose = 0; -my $format = ''; -my $force = 0; -my $get_help = !scalar(@ARGV); -GetOptions( - "c|corpus=s" => \$corpus_file, - "i|input=s" => \$input_file, - "o|output=s" => \$output_file, - "v|verbose+" => \$verbose, - "f|format=s" => \$format, - "force+" => \$force, - "h|help+" => \$get_help, -); -my $operation = shift @ARGV; - -if ($verbose) { - print STDERR "Asemica version $VERSION running\n"; - print STDERR " Corpus file: $corpus_file\n" if $corpus_file; - print STDERR " Input file: $input_file\n" if $input_file; - print STDERR " Output file: $output_file\n" if $output_file; - print STDERR " Operation: $operation\n" if $operation; - print STDERR " Force: $force\n" if $force; - print STDERR " Help: $get_help\n" if $get_help; - print STDERR "\n"; -} - -my $usage = "Usage: $0 (enc|dec) -c [-i ] " . - "[-o ] [-f ] [--force] [--help]\n"; - -### -# If all they want is help (or they ran this with no args), give them help -### -if ($get_help) { - print STDERR <<__END_HELP__ -Asemica: an asemic Markov-chained cipher, v. $VERSION -$usage -OPTIONS: - -c/--corpus: specify corpus filename or URL - -i/--input: specify input filename (defaults to STDIN) - -o/--output: specify output filename (defaults to STDOUT) - -f/--format: specify output format (defaults to none) - --force: forces runtime on an insufficiently complex corpus - --help: displays this message - -v/--verbost: increments verbosity setting (used for debugging) -AVAILABLE FORMATS: - none: doesn't format output; returns only word list - email: formats output to look like an informal email - poem: if you want your output to look like poetry -EXAMPLES - echo "message" | $0 enc -c corpus.txt -o asemic.txt - $0 dec -c corpus.txt -i asemic.txt -__END_HELP__ - ; - exit 1; -} - - -### -# Make sure we have necessary and sufficient inputs (command line or STDIN) -### - -unless ($operation) { - print "No operation (encode or decode) specified.\n"; - print STDERR $usage; - exit 1; -} - -unless ($operation eq 'enc' || $operation eq 'dec') { - print "Invalid operation specified: $operation\n"; - print STDERR $usage; - exit 1; -} - -my $input = ''; -unless ($input_file) { - if ($verbose) { - print STDERR "No input file specified. Reading from STDIN...\n"; - } - $input = join('', ); -} -else { - open('INPUT', '<', $input_file) || die "Can't read $input_file"; - $input = join('', ); - close('INPUT'); -} - - -### -# Load and verify corpus -### - -my $corpus = ''; -unless ($corpus_file) { - print STDERR "No corpus specified. Can't operate without a corpus.\n"; - print STDERR $usage; - exit 1; -} -if (-f $corpus_file) { - ### It's a flat file. Load and move on. - open('CORPUS', '<', $corpus_file) || die "Can't read $corpus_file"; - $corpus = join('', ); - close('CORPUS'); - -} -elsif ($corpus_file =~ m/^https?/) { - ### It's a URI. Try to download it. - $corpus = `curl -s $corpus_file`; - - unless ($corpus) { - print STDERR "Unable to load corpus from $corpus_file\nExiting.\n"; - exit 1; - } - -} -else { - print STDERR "Couldn't read corpus at $corpus_file\nExiting.\n"; - exit 1; -} - - -### -# Calculate and verify corpus tokens and transition matrix -### -my $tokens = tokenize_corpus($corpus); -my $transitions = generate_transitions(@$tokens); -unless (verify_exits($transitions)) { - if ($force) { - if ($verbose) { - print STDERR "Insufficient number of nodes with sufficient exits " . - "to perform quality coding using the specified corpus file." . - "Proceeding due to use of --force.\n"; - } - } - else { - print STDERR "Insufficient number of nodes with sufficient exits to " . - "perform quality coding using the specified corpus file. " . - "Use --force to override (which would likely generate an " . - "absurdly long output text).\n" . - "Exiting.\n"; - exit 1; - } -} -else { - if ($verbose) { - print STDERR "Sufficient number of nodes with sufficient exits to " . - "perform quality coding using the specified corpus file.\n"; - } -} - - -### -# Run the actual encoding or decoding procedure -### -my $output_text = ''; -if ($operation eq 'enc') { - - $output_text = encode($input, $transitions, $tokens); - - if ($format) { - $output_text = format_text($output_text, $format); - } - -} -elsif ($operation eq 'dec') { - - $output_text = decode($input, $transitions, $tokens); - -} - - -### -# Output the results -### -if ($output_file) { - open('OUTPUT', '>', $output_file) || die "Can't write to $output_file.\n"; - print OUTPUT $output_text; - close('OUTPUT'); -} -else { - print $output_text; -} - - -### -# clean_input -# Removes all nonwords and HTML from input text -# -# Takes: -# - $input, a scalar containing the input to be cleaned -# Returns: -# - $output, a scalar containing the cleaned data -# Note: -# Yes, this is a silly thing to have isolated like this, but I'm doing so -# because the cleaning procedures need to be identical for encoding and -# decoding to work properly. This approach saves time and repetition. -### -sub clean_input { - my ($input) = @_; - - $input =~ s/\n/ /g; ### Change newlines to spaces - $input =~ s/\<[^>]*//g; ### Strip out HTML (poorly -- we can't assume any - ### modules other than perl's core will be around) - $input =~ s/[^\w\']/ /g; ### Change non-word characters to spaces - $input =~ s/\d/ /g; ### Change numbers to spaces - $input =~ s/\s+/ /g; ### Change sequences of spaces to a single space - $input =~ s/^\s+//; ### Trim leading whitespace - $input =~ s/\s+$//; ### Trim trailing whitespace - - return $input; -} - - -### -# tokenize_corpus -# Breaks the input corpus into a series of processable "tokens" -# -# Takes: -# - $corpus, a scalar containing the complete input corpus -# Returns: -# - $tokens, an array reference of tokens (most likely "words") present -# Output looks like: -# ['The','Project','Gutenberg', ... ,'about','new','eBooks'] -### -sub tokenize_corpus { - my ($corpus) = @_; - - $corpus = clean_input($corpus); - my @tokens = split(/\s/, $corpus); - - return \@tokens; -} - - -### -# generate_transitions -# Creates the primary transition matrix for use in coding -# -# Takes: -# - @tokens, an array of tokens present, sequentially, in the corpus -# Returns: -# - $transitions, the transition matrix -# Output looks like: -# { -# 'atlantic' => { ### Lowercase form -# 'seen' => 2, ### How many fimes seen in corpus -# 'exits' => { ### Which words follow it? -# 'City' => 1, ### One instance of this -# 'and' => 1 ### One instance of that -# }, ### Exits not guaranteed unique -# 'door' => [ ### Doors are guaranteed unique -# 'City', ### Following door number 1 -# 'and' ### Following door number 2 -# ], -# 'doors' => 2, ### Cached count of doors -# 'token' => 'Atlantic' ### Original form of the token -# }, -# ... -# } -### -sub generate_transitions { - my @tokens = @_; - my $transitions = {}; - - ### Generate the initial transitions table - foreach my $index (0 .. scalar(@tokens)) { - my $token = $tokens[$index - 1]; - my $key = lc($token); - - $transitions->{$key}->{seen}++; - $transitions->{$key}->{token} = $token; - - if ($tokens[$index + 1]) { - $transitions->{$key}->{exits}->{$tokens[$index + 1]}++; - } - } - - ### Calculate the exits and doors - foreach my $transition (keys(%$transitions)) { - my @exits = keys(%{$transitions->{$transition}->{exits}}); - $transitions->{$transition}->{door} = []; - my $found = {}; - foreach my $exit (sort (keys(%{$transitions->{$transition}->{exits}}))) { - unless ($found->{lc($exit)}) { - push @{$transitions->{$transition}->{door}}, $exit; - } - $found->{lc($exit)} = 1; - } - $transitions->{$transition}->{doors} = scalar( - @{$transitions->{$transition}->{door}} - ); - if ($transitions->{$transition}->{doors} > 15) { - $transitions->{$transition}->{meaningful} = 1; - } - } - - return $transitions; -} - - -### -# verify_exits -# Returns whether this corpus will work well as an encoding or decoding medium -# -# Takes: -# - $transitions, the calculated transition matrix -# Returns: -# - 1 if it will suffice, 0 if it probably won't. -# Note: -# We are looking for how many nodes in the transition matrix have more than -# 15 doors (as they'll need minimally 16 in order for the relationship -# between any node and its successor to be able to encode a binary nibble) -# If there are fewer than 10 of these, chances are the encoding / decoding -# is going to be of very low quality. -### -sub verify_exits { - my ($transitions) = @_; - my $count = 0; - my @meaningful = (); - foreach my $key (keys(%$transitions)) { - if ($transitions->{$key}->{doors} > 15) { - $count++; - push @meaningful, $key; - } - } - if ($verbose) { - print STDERR "$count meaningful transitions (" . - join(', ', @meaningful) . ")\n\n"; - } - if ($count >= 7) { - return 1; - } - else { - return; - } -} - - -### -# encode -# Encodes an input file using the transition matrix calculated from the corpus -# Takes: -# - $input, a scalar containing the input to be encoded -# - $transitions, the transition matrix calculated from the corpus -# - $tokens, an array reference of the token sequence from the key corpus -# Returns: -# - $encoded_text, the encoded text -### -sub encode { - my ($input, $transitions, $tokens) = @_; - - use Data::Dumper; - print Dumper($input); - - my $bits = unpack("b*", $input); - print $bits; - - my $nibbles; - while (my $nibble = substr($bits, 0, 4, '')) { - push @$nibbles, bin2dec($nibble); - } - - use Data::Dumper; - print Dumper($nibbles); - - my $token = $tokens->[int(rand(scalar(@$tokens)))]; - my $encoded_text = ''; - my $last_token = $token; ### for debugging - - while (scalar(@$nibbles)) { - - if ($transitions->{lc($token)}->{meaningful}) { - $encoded_text .= $token . ' '; - - ### This token means something. Walk through the nibblth door. - my $nibble = shift(@$nibbles); - $token = $transitions->{lc($token)}->{door}->[$nibble]; - - } - else { - $encoded_text .= $token . ' '; - - ### This token is irrelevant. Stumble drunkenly through any door. - $token = $transitions->{lc($token)}->{door}->[ - int(rand($transitions->{lc($token)}->{doors})) - ]; - } - - unless ($token) { - use Data::Dumper; - print "DEBUG:\ntoken = $token\n" . - "Transitions:" . Dumper($transitions->{lc($token)}) . - "\nlast_token = $last_token\n" . - "Transitions:" . Dumper($transitions->{lc($last_token)}); - exit 1; - } - - $last_token = $token; - } - $encoded_text .= $token . ' '; - - return $encoded_text; -} - - -### -# decode -# Pieces an arbitrary binary sequence back together from ASCII input file -# -# Takes: -# - $output_text, text originally output by an encoding pass of this script -# - $transitions, the transition matrix generated from the key corpus -# - $tokens, an array reference of the token sequence from the key corpus -# Returns: -# - $reconstituted, the decoded text -### -sub decode { - my ($input, $transitions, $tokens) = @_; - - my $decoded = ''; - - $input = clean_input($input); - - my @words = split(/\s+/, $input); - - foreach my $i (0 .. scalar(@words) - 2) { - if ($transitions->{lc($words[$i])}->{meaningful}) { - ### We walked through a specific door. Figure out which it was. - my $num_doors = scalar(@{$transitions->{lc($words[$i])}->{door}}); - foreach my $j (0 .. $num_doors - 1) { - my $on_door = lc($transitions->{lc($words[$i])}->{door}->[$j]); - if ($on_door eq lc($words[$i + 1])) { - my $binary = dec2bin($j); - while (length($binary) < 4) { - $binary = '0' . $binary; - } - $decoded .= $binary; - } - } - } - ### TODO: a later version of this should use the less meaningful - ### nodes to encode information as well. Really, any node with more - ### than one exit can be used to encode something (minimally, a single - ### bit), so in that sense any node with more than 2 exits /could/ be - ### a door. We'd just have to modify the coders for variable lengths. - ### For right now, we're just using nodes with 16 or more exits (so - ### they can encode minimally a nibble), then only making use of the - ### first 16 doors from that node. This can be improved with variable- - ### length encoding. - } - - my $decoded_text = pack('b*', $decoded); - return $decoded_text; -} - - -### -# format_text -# Formats the output text to look like something human-created -# -# Takes: -# - $input_text, a scalar containing the text to be formatted -# - $format, a scalar specifying the desired format -# Returns: -# - $output_text, a scalar containing the formatted text -# Supported formats: none, essay, poem, scripture, email -### -sub format_text { - my ($input_text, $format) = @_; - - my $formats = { - 'none' => sub {return join(' ', @_);}, - - 'essay' => sub { - my @words = @_; - return join(' ', @words); - }, - - 'textile' => sub { - my @words = @_; - return join(' ', @words); - }, - - ### - # Poem format - ### - 'poem' => sub { - my @words = @_; - - ### Form the words into sentences - my @puncts = ('.', ' ', ' ', ' ', ',', ',', ',', '!', '?'); - my @sentences = (); - while (scalar(@words)) { - my $sentence_length = 6 + int(rand(3)); - if (scalar(@words) < $sentence_length) { - $sentence_length = scalar(@words); - } - my $sentence = join(' ', splice(@words, 0, $sentence_length, ())); - $sentence = ucfirst($sentence) . $puncts[int(rand(@puncts))]; - push @sentences, $sentence; - } - - ### Form the sentences into stanzas - my @stanzas = (); - while (scalar(@sentences)) { - my $stanza_length = 4 + int(rand(7)); - if (scalar(@sentences) < $stanza_length) { - $stanza_length = scalar(@sentences); - } - my $stanza = join("\n", splice(@sentences, 0, $stanza_length, ())); - push @stanzas, $stanza; - } - return join("\n\n", @stanzas); - }, - - ### - # Email format - ### - 'email' => sub { - my @words = @_; - - my $greeting = ucfirst(shift(@words)); - my $name = ucfirst(pop(@words)); - my $thanks = pop(@words); - - ### Form the words into sentences - my @puncts = qw/? . . . . . !/; - my @sentences = (); - while (scalar(@words)) { - my $sentence_length = 7 + int(rand(10)); - if (scalar(@words) < $sentence_length) { - $sentence_length = scalar(@words); - } - my $sentence = join(' ', splice(@words, 0, $sentence_length, ())); - $sentence = ucfirst($sentence) . $puncts[int(rand(@puncts))]; - push @sentences, $sentence; - } - - ### Form the sentences into paragraphs - my @paragraphs = (); - while (scalar(@sentences)) { - my $paragraph_length = 4 + int(rand(7)); - if (scalar(@sentences) < $paragraph_length) { - $paragraph_length = scalar(@sentences); - } - my $paragraph = join(' ', splice(@sentences, 0, $paragraph_length, ())); - push @paragraphs, $paragraph; - } - my $body = join("\n\n ", @paragraphs); - return "$greeting,\n\n $body\n\n$thanks,\n$name"; - }, - }; - if ($formats->{$format}) { - return $formats->{$format}->(split(' ', $input_text)); - } - else { - print STDERR "Unsupported format: $format\nExiting\n"; - exit 1; - } -} - - -### -# dec2bin -# Converts a decimal numeric expression to binary -# -# Takes: -# - $decimal, a decimal expression of a number (e.g. '54') -# Returns: -# - $binary, a binary expression of the same number (e.g. '110110') -# Note: -# Sourced from Perl Cookbook (Christiansen & Torkington 1998), sec. 2.4 -### -sub dec2bin { - my $str = unpack("B32", pack("N", shift)); - $str =~ s/^0+(?=\d)//; - return $str; -} - - -### -# bin2dec -# Converts a binary numeric expression to decimal -# -# Takes: -# - $binary, a binary expression of the same number (e.g. '110110') -# Returns: -# - $decimal, a decimal expression of a number (e.g. '54') -# Note: -# Sourced from Perl Cookbook (Christiansen & Torkington 1998), sec. 2.4 -### -sub bin2dec { - return unpack("N", pack("B32", substr("0" x 32 . shift, -32))); -} +#!/usr/bin/perl -w +use strict; +use warnings; + + +### +# Asemica -- An asemic Markov-chained cipher +# Copyright (c) 2011 by Danne Stayskal +### + +### +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +### + +our $VERSION = '1.0'; + +use Getopt::Long; + +my $corpus_file = ''; +my $input_file = ''; +my $output_file = ''; +my $verbose = 0; +my $format = ''; +my $force = 0; +my $get_help = !scalar(@ARGV); +GetOptions( + "c|corpus=s" => \$corpus_file, + "i|input=s" => \$input_file, + "o|output=s" => \$output_file, + "v|verbose+" => \$verbose, + "f|format=s" => \$format, + "force+" => \$force, + "h|help+" => \$get_help, +); +my $operation = shift @ARGV; + +if ($verbose) { + print STDERR "Asemica version $VERSION running\n"; + print STDERR " Corpus file: $corpus_file\n" if $corpus_file; + print STDERR " Input file: $input_file\n" if $input_file; + print STDERR " Output file: $output_file\n" if $output_file; + print STDERR " Operation: $operation\n" if $operation; + print STDERR " Force: $force\n" if $force; + print STDERR " Help: $get_help\n" if $get_help; + print STDERR "\n"; +} + +my $usage = "Usage: $0 (enc|dec) -c [-i ] " . + "[-o ] [-f ] [--force] [--help]\n"; + +### +# If all they want is help (or they ran this with no args), give them help +### +if ($get_help) { + print STDERR <<__END_HELP__ +Asemica: an asemic Markov-chained cipher, v. $VERSION +$usage +OPTIONS: + -c/--corpus: specify corpus filename or URL + -i/--input: specify input filename (defaults to STDIN) + -o/--output: specify output filename (defaults to STDOUT) + -f/--format: specify output format (defaults to none) + --force: forces runtime on an insufficiently complex corpus + --help: displays this message + -v/--verbost: increments verbosity setting (used for debugging) +AVAILABLE FORMATS: + none: doesn't format output; returns only word list + email: formats output to look like an informal email + poem: if you want your output to look like poetry +EXAMPLES + echo "message" | $0 enc -c corpus.txt -o asemic.txt + $0 dec -c corpus.txt -i asemic.txt +__END_HELP__ + ; + exit 1; +} + + +### +# Make sure we have necessary and sufficient inputs (command line or STDIN) +### + +unless ($operation) { + print "No operation (encode or decode) specified.\n"; + print STDERR $usage; + exit 1; +} + +unless ($operation eq 'enc' || $operation eq 'dec') { + print "Invalid operation specified: $operation\n"; + print STDERR $usage; + exit 1; +} + +my $input = ''; +unless ($input_file) { + if ($verbose) { + print STDERR "No input file specified. Reading from STDIN...\n"; + } + $input = join('', ); +} +else { + open('INPUT', '<', $input_file) || die "Can't read $input_file"; + $input = join('', ); + close('INPUT'); +} + + +### +# Load and verify corpus +### + +my $corpus = ''; +unless ($corpus_file) { + print STDERR "No corpus specified. Can't operate without a corpus.\n"; + print STDERR $usage; + exit 1; +} +if (-f $corpus_file) { + ### It's a flat file. Load and move on. + open('CORPUS', '<', $corpus_file) || die "Can't read $corpus_file"; + $corpus = join('', ); + close('CORPUS'); + +} +elsif ($corpus_file =~ m/^https?/) { + ### It's a URI. Try to download it. + $corpus = `curl -s $corpus_file`; + + unless ($corpus) { + print STDERR "Unable to load corpus from $corpus_file\nExiting.\n"; + exit 1; + } + +} +else { + print STDERR "Couldn't read corpus at $corpus_file\nExiting.\n"; + exit 1; +} + + +### +# Calculate and verify corpus tokens and transition matrix +### +my $tokens = tokenize_corpus($corpus); +my $transitions = generate_transitions(@$tokens); +unless (verify_exits($transitions)) { + if ($force) { + if ($verbose) { + print STDERR "Insufficient number of nodes with sufficient exits " . + "to perform quality coding using the specified corpus file." . + "Proceeding due to use of --force.\n"; + } + } + else { + print STDERR "Insufficient number of nodes with sufficient exits to " . + "perform quality coding using the specified corpus file. " . + "Use --force to override (which would likely generate an " . + "absurdly long output text).\n" . + "Exiting.\n"; + exit 1; + } +} +else { + if ($verbose) { + print STDERR "Sufficient number of nodes with sufficient exits to " . + "perform quality coding using the specified corpus file.\n"; + } +} + + +### +# Run the actual encoding or decoding procedure +### +my $output_text = ''; +if ($operation eq 'enc') { + + $output_text = encode($input, $transitions, $tokens); + + if ($format) { + $output_text = format_text($output_text, $format); + } + +} +elsif ($operation eq 'dec') { + + $output_text = decode($input, $transitions, $tokens); + +} + + +### +# Output the results +### +if ($output_file) { + open('OUTPUT', '>', $output_file) || die "Can't write to $output_file.\n"; + print OUTPUT $output_text; + close('OUTPUT'); +} +else { + print $output_text; +} + + +### +# clean_input +# Removes all nonwords and HTML from input text +# +# Takes: +# - $input, a scalar containing the input to be cleaned +# Returns: +# - $output, a scalar containing the cleaned data +# Note: +# Yes, this is a silly thing to have isolated like this, but I'm doing so +# because the cleaning procedures need to be identical for encoding and +# decoding to work properly. This approach saves time and repetition. +### +sub clean_input { + my ($input) = @_; + + $input =~ s/\n/ /g; ### Change newlines to spaces + $input =~ s/\<[^>]*//g; ### Strip out HTML (poorly -- we can't assume any + ### modules other than perl's core will be around) + $input =~ s/[^\w\']/ /g; ### Change non-word characters to spaces + $input =~ s/\d/ /g; ### Change numbers to spaces + $input =~ s/\s+/ /g; ### Change sequences of spaces to a single space + $input =~ s/^\s+//; ### Trim leading whitespace + $input =~ s/\s+$//; ### Trim trailing whitespace + + return $input; +} + + +### +# tokenize_corpus +# Breaks the input corpus into a series of processable "tokens" +# +# Takes: +# - $corpus, a scalar containing the complete input corpus +# Returns: +# - $tokens, an array reference of tokens (most likely "words") present +# Output looks like: +# ['The','Project','Gutenberg', ... ,'about','new','eBooks'] +### +sub tokenize_corpus { + my ($corpus) = @_; + + $corpus = clean_input($corpus); + my @tokens = split(/\s/, $corpus); + + return \@tokens; +} + + +### +# generate_transitions +# Creates the primary transition matrix for use in coding +# +# Takes: +# - @tokens, an array of tokens present, sequentially, in the corpus +# Returns: +# - $transitions, the transition matrix +# Output looks like: +# { +# 'atlantic' => { ### Lowercase form +# 'seen' => 2, ### How many fimes seen in corpus +# 'exits' => { ### Which words follow it? +# 'City' => 1, ### One instance of this +# 'and' => 1 ### One instance of that +# }, ### Exits not guaranteed unique +# 'door' => [ ### Doors are guaranteed unique +# 'City', ### Following door number 1 +# 'and' ### Following door number 2 +# ], +# 'doors' => 2, ### Cached count of doors +# 'token' => 'Atlantic' ### Original form of the token +# }, +# ... +# } +### +sub generate_transitions { + my @tokens = @_; + my $transitions = {}; + + ### Generate the initial transitions table + foreach my $index (0 .. scalar(@tokens)) { + my $token = $tokens[$index - 1]; + my $key = lc($token); + + $transitions->{$key}->{seen}++; + $transitions->{$key}->{token} = $token; + + if ($tokens[$index + 1]) { + $transitions->{$key}->{exits}->{$tokens[$index + 1]}++; + } + } + + ### Calculate the exits and doors + foreach my $transition (keys(%$transitions)) { + my @exits = keys(%{$transitions->{$transition}->{exits}}); + $transitions->{$transition}->{door} = []; + my $found = {}; + foreach my $exit (sort (keys(%{$transitions->{$transition}->{exits}}))) { + unless ($found->{lc($exit)}) { + push @{$transitions->{$transition}->{door}}, $exit; + } + $found->{lc($exit)} = 1; + } + $transitions->{$transition}->{doors} = scalar( + @{$transitions->{$transition}->{door}} + ); + if ($transitions->{$transition}->{doors} > 15) { + $transitions->{$transition}->{meaningful} = 1; + } + } + + return $transitions; +} + + +### +# verify_exits +# Returns whether this corpus will work well as an encoding or decoding medium +# +# Takes: +# - $transitions, the calculated transition matrix +# Returns: +# - 1 if it will suffice, 0 if it probably won't. +# Note: +# We are looking for how many nodes in the transition matrix have more than +# 15 doors (as they'll need minimally 16 in order for the relationship +# between any node and its successor to be able to encode a binary nibble) +# If there are fewer than 10 of these, chances are the encoding / decoding +# is going to be of very low quality. +### +sub verify_exits { + my ($transitions) = @_; + my $count = 0; + my @meaningful = (); + foreach my $key (keys(%$transitions)) { + if ($transitions->{$key}->{doors} > 15) { + $count++; + push @meaningful, $key; + } + } + if ($verbose) { + print STDERR "$count meaningful transitions (" . + join(', ', @meaningful) . ")\n\n"; + } + if ($count >= 7) { + return 1; + } + else { + return; + } +} + + +### +# encode +# Encodes an input file using the transition matrix calculated from the corpus +# Takes: +# - $input, a scalar containing the input to be encoded +# - $transitions, the transition matrix calculated from the corpus +# - $tokens, an array reference of the token sequence from the key corpus +# Returns: +# - $encoded_text, the encoded text +### +sub encode { + my ($input, $transitions, $tokens) = @_; + + use Data::Dumper; + print Dumper($input); + + my $bits = unpack("b*", $input); + print $bits; + + my $nibbles; + while (my $nibble = substr($bits, 0, 4, '')) { + push @$nibbles, bin2dec($nibble); + } + + use Data::Dumper; + print Dumper($nibbles); + + my $token = $tokens->[int(rand(scalar(@$tokens)))]; + my $encoded_text = ''; + my $last_token = $token; ### for debugging + + while (scalar(@$nibbles)) { + + if ($transitions->{lc($token)}->{meaningful}) { + $encoded_text .= $token . ' '; + + ### This token means something. Walk through the nibblth door. + my $nibble = shift(@$nibbles); + $token = $transitions->{lc($token)}->{door}->[$nibble]; + + } + else { + $encoded_text .= $token . ' '; + + ### This token is irrelevant. Stumble drunkenly through any door. + $token = $transitions->{lc($token)}->{door}->[ + int(rand($transitions->{lc($token)}->{doors})) + ]; + } + + unless ($token) { + use Data::Dumper; + print "DEBUG:\ntoken = $token\n" . + "Transitions:" . Dumper($transitions->{lc($token)}) . + "\nlast_token = $last_token\n" . + "Transitions:" . Dumper($transitions->{lc($last_token)}); + exit 1; + } + + $last_token = $token; + } + $encoded_text .= $token . ' '; + + return $encoded_text; +} + + +### +# decode +# Pieces an arbitrary binary sequence back together from ASCII input file +# +# Takes: +# - $output_text, text originally output by an encoding pass of this script +# - $transitions, the transition matrix generated from the key corpus +# - $tokens, an array reference of the token sequence from the key corpus +# Returns: +# - $reconstituted, the decoded text +### +sub decode { + my ($input, $transitions, $tokens) = @_; + + my $decoded = ''; + + $input = clean_input($input); + + my @words = split(/\s+/, $input); + + foreach my $i (0 .. scalar(@words) - 2) { + if ($transitions->{lc($words[$i])}->{meaningful}) { + ### We walked through a specific door. Figure out which it was. + my $num_doors = scalar(@{$transitions->{lc($words[$i])}->{door}}); + foreach my $j (0 .. $num_doors - 1) { + my $on_door = lc($transitions->{lc($words[$i])}->{door}->[$j]); + if ($on_door eq lc($words[$i + 1])) { + my $binary = dec2bin($j); + while (length($binary) < 4) { + $binary = '0' . $binary; + } + $decoded .= $binary; + } + } + } + ### TODO: a later version of this should use the less meaningful + ### nodes to encode information as well. Really, any node with more + ### than one exit can be used to encode something (minimally, a single + ### bit), so in that sense any node with more than 2 exits /could/ be + ### a door. We'd just have to modify the coders for variable lengths. + ### For right now, we're just using nodes with 16 or more exits (so + ### they can encode minimally a nibble), then only making use of the + ### first 16 doors from that node. This can be improved with variable- + ### length encoding. + } + + my $decoded_text = pack('b*', $decoded); + return $decoded_text; +} + + +### +# format_text +# Formats the output text to look like something human-created +# +# Takes: +# - $input_text, a scalar containing the text to be formatted +# - $format, a scalar specifying the desired format +# Returns: +# - $output_text, a scalar containing the formatted text +# Supported formats: none, essay, poem, scripture, email +### +sub format_text { + my ($input_text, $format) = @_; + + my $formats = { + 'none' => sub {return join(' ', @_);}, + + 'essay' => sub { + my @words = @_; + return join(' ', @words); + }, + + 'textile' => sub { + my @words = @_; + return join(' ', @words); + }, + + ### + # Poem format + ### + 'poem' => sub { + my @words = @_; + + ### Form the words into sentences + my @puncts = ('.', ' ', ' ', ' ', ',', ',', ',', '!', '?'); + my @sentences = (); + while (scalar(@words)) { + my $sentence_length = 6 + int(rand(3)); + if (scalar(@words) < $sentence_length) { + $sentence_length = scalar(@words); + } + my $sentence = join(' ', splice(@words, 0, $sentence_length, ())); + $sentence = ucfirst($sentence) . $puncts[int(rand(@puncts))]; + push @sentences, $sentence; + } + + ### Form the sentences into stanzas + my @stanzas = (); + while (scalar(@sentences)) { + my $stanza_length = 4 + int(rand(7)); + if (scalar(@sentences) < $stanza_length) { + $stanza_length = scalar(@sentences); + } + my $stanza = join("\n", splice(@sentences, 0, $stanza_length, ())); + push @stanzas, $stanza; + } + return join("\n\n", @stanzas); + }, + + ### + # Email format + ### + 'email' => sub { + my @words = @_; + + my $greeting = ucfirst(shift(@words)); + my $name = ucfirst(pop(@words)); + my $thanks = pop(@words); + + ### Form the words into sentences + my @puncts = qw/? . . . . . !/; + my @sentences = (); + while (scalar(@words)) { + my $sentence_length = 7 + int(rand(10)); + if (scalar(@words) < $sentence_length) { + $sentence_length = scalar(@words); + } + my $sentence = join(' ', splice(@words, 0, $sentence_length, ())); + $sentence = ucfirst($sentence) . $puncts[int(rand(@puncts))]; + push @sentences, $sentence; + } + + ### Form the sentences into paragraphs + my @paragraphs = (); + while (scalar(@sentences)) { + my $paragraph_length = 4 + int(rand(7)); + if (scalar(@sentences) < $paragraph_length) { + $paragraph_length = scalar(@sentences); + } + my $paragraph = join(' ', splice(@sentences, 0, $paragraph_length, ())); + push @paragraphs, $paragraph; + } + my $body = join("\n\n ", @paragraphs); + return "$greeting,\n\n $body\n\n$thanks,\n$name"; + }, + }; + if ($formats->{$format}) { + return $formats->{$format}->(split(' ', $input_text)); + } + else { + print STDERR "Unsupported format: $format\nExiting\n"; + exit 1; + } +} + + +### +# dec2bin +# Converts a decimal numeric expression to binary +# +# Takes: +# - $decimal, a decimal expression of a number (e.g. '54') +# Returns: +# - $binary, a binary expression of the same number (e.g. '110110') +# Note: +# Sourced from Perl Cookbook (Christiansen & Torkington 1998), sec. 2.4 +### +sub dec2bin { + my $str = unpack("B32", pack("N", shift)); + $str =~ s/^0+(?=\d)//; + return $str; +} + + +### +# bin2dec +# Converts a binary numeric expression to decimal +# +# Takes: +# - $binary, a binary expression of the same number (e.g. '110110') +# Returns: +# - $decimal, a decimal expression of a number (e.g. '54') +# Note: +# Sourced from Perl Cookbook (Christiansen & Torkington 1998), sec. 2.4 +### +sub bin2dec { + return unpack("N", pack("B32", substr("0" x 32 . shift, -32))); +} diff --git a/main/app/sprinkles/core/assets/SiteAssets/js/chat.js b/main/app/sprinkles/core/assets/SiteAssets/js/chat.js index ebf48b6..354120e 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/js/chat.js +++ b/main/app/sprinkles/core/assets/SiteAssets/js/chat.js @@ -1,353 +1,353 @@ -/** - * GLOBAL DECLARATIONS - */ -let LastMessage, Username, ReceiversUsername, CurrentChatMessagesWindow, ReceiversId, options, EncryptedMessage, - DecryptedMessage; - -/** - * INITIAL ENCRYPTION CONFIGURATION - */ -const openpgp = window.openpgp; -const PublicKey = []; -openpgp.initWorker({path: '/assets-raw/core/assets/SiteAssets/js/openpgp.worker.js'}); -const privKeyObj = openpgp.key.readArmored(localStorage.getItem("PrivateKey").replace(/\r/, "")).keys[0]; -privKeyObj.decrypt(localStorage.getItem("🔒")); - - -// console.log(AES_CBC.encrypt( "LOL", '0123456789' )); // For future me: TODO: Encrypt user data with symmetric encryption (AES_CBC) and like told here: https://stackoverflow.com/a/7529707/9783773 - - -/** - * GENERAL CHAT - */ -function InitializeChatServer() { - const ChatTextInput = $("#ChatTextInput"); - const SubscribeTextInput = $("#SubscribeTextInput"); - const ChatMessages = $("#ChatMessages:visible"); - const SelectReceiver = $(".SelectReceiver"); - const SelectedReceiver = $(".SelectedReceiver"); - const TypingIndicatorAnimationElement = "
"; - - const WebSocketConnectTimerStart = performance.now(); // START CONNECTION EXECUTION TIMER - const ChatSocket = new WebSocket('wss://marvinborner.ddnss.de:1337'); - ChatSocket.onerror = function () { - setTimeout(function () { - console.log("%c[CHATSOCKET LOGGER] Connection failed. Trying again...", "color: red"); - InitializeChatServer(); - }, 5000); - }; - ChatSocket.onopen = function () { - // CONNECTION SUCCESSFUL! - const WebSocketConnectTimerEnd = performance.now(); // END CONNECTION EXECUTION TIMER - console.log("%c[CHATSOCKET LOGGER] Chat connection established! (Took " + (WebSocketConnectTimerEnd - WebSocketConnectTimerStart) + " milliseconds)", "color: darkorange"); - // START VERIFICATION - ChatSocket.send(JSON.stringify({ - ClientMessageType: "Verify", - Cookie: document.cookie, - UserID: current_user_id - })); - console.log("%c[CHATSOCKET LOGGER] Started chat verification process...", "color: gray"); - // GOT MESSAGE - ChatSocket.onmessage = function (e) { - // DECLARATIONS - const TypingIndicatorMessage = $(".TypingIndicatorMessage").parent(); - const MessageObject = JSON.parse(e.data); - const Message = MessageObject.Message; // ENCRYPTED MESSAGE (NOT ENCRYPTED ON SERVER MESSAGES) - const MessageId = MessageObject.MessageId; - const Fullname = MessageObject.Fullname; - const Avatar = MessageObject.Avatar; - const GroupName = MessageObject.GroupName; - const ServerMessageType = MessageObject.ServerMessageType; - let State = MessageObject.State; - let ServerMessage = MessageObject.ServerMessage; - let WasHimself = MessageObject.WasHimself; - let Granted = MessageObject.Granted; - let Success = MessageObject.Success; - - // GLOBAL OVERWRITES - LastMessage = $(".MessageWrapper.Normal:last .ChatMessage"); - CurrentChatMessagesWindow = $("#ChatMessages[data-username=" + ReceiversUsername + "]"); - Username = MessageObject.Username; - - // GET OWN PUBLIC KEY FIRST - if (!(current_username in PublicKey)) { - $.ajax({ - type: 'GET', - url: site.uri.public + '/api/users/u/' + current_username + '/publickey', - dataType: "json", - success: function (response) { - PublicKey[current_username] = response.PublicKey; - console.log("%c[ENCRYPTION LOGGER]\nPublickey of " + current_username + ": \n\n" + PublicKey[current_username].substr(96).slice(0, -35), "font-family: monospace; white-space: pre; display: inline-block; border-radius: 10px; padding: 5px; color: #20c20e; background-color: black;") - } - }); - } - - // GET PUBLIC KEY IF NOT ALREADY DID - if (!(ReceiversUsername in PublicKey) && ReceiversUsername !== null && ReceiversUsername !== undefined) { - $.ajax({ - type: 'GET', - url: site.uri.public + '/api/users/u/' + ReceiversUsername + '/publickey', - dataType: "json", - success: function (response) { - PublicKey[ReceiversUsername] = response.PublicKey; - console.log("%c[ENCRYPTION LOGGER]\nPublickey of " + ReceiversUsername + ": \n\n" + PublicKey[ReceiversUsername].substr(96).slice(0, -35), "font-family: monospace; white-space: pre; display: inline-block; border-radius: 10px; padding: 5px; color: #20c20e; background-color: black;") - } - }); - } - - if (ServerMessage) { // SERVER MESSAGE - if (ServerMessageType === "GroupJoin") { // TYPE: USER JOINED A GROUP - if (WasHimself) { // HIMSELF JOINED A GROUP -> NOTIFY - CurrentChatMessagesWindow.empty(); // -> EMPTY MESSAGES ON NEW GROUP JOIN - CurrentChatMessagesWindow.append("
" + GroupName + "

"); - ReplaceServerMessage("YouGroupJoin"); // FOR TRANSLATION - console.log("%c[CHATSOCKET LOGGER] You joined the group " + GroupName + "!", "color: darkorange"); - } else { // OTHER USER JOINED A GROUP -> NOTIFY - CurrentChatMessagesWindow.append("
" + Username + "

"); - ReplaceServerMessage("UserGroupJoin"); // FOR TRANSLATION - console.log("%c[CHATSOCKET LOGGER] " + Username + " joined the group!", "color: darkorange"); - } - } else if (ServerMessageType === "UserDisconnect") { // TYPE: USER DISCONNECTED -> NOTIFY - CurrentChatMessagesWindow.append("
" + Username + "

"); - ReplaceServerMessage("UserDisconnect"); // FOR TRANSLATION - console.log("%c[CHATSOCKET LOGGER] " + Username + " disconnected from server!", "color: darkorange"); - } else if (ServerMessageType === "TypingState") { // TYPE: SOMEBODY'S TYPING STATE CHANGED! - if (State) { // IF 'SOMEBODY' STARTED TYPING - if (WasHimself) { // IDENTIFY 'SOMEBODY' -> WAS HIMSELF -> NOT THAT IMPORTANT (USER KNOWS WHEN HE STARTS TYPING?) - console.log("%c[CHAT TYPING LOGGER] You started typing!", "color: gray"); - } else if (!WasHimself) { // IDENTIFY 'SOMEBODY' -> WAS OTHER USER -> SHOW TYPING ANIMATION ON RECEIVER'S SIDE - CurrentChatMessagesWindow.append("
" + TypingIndicatorAnimationElement + "
"); - console.log("%c[CHAT TYPING LOGGER] " + Username + " started typing!", "color: gray"); - } - } else { // IF 'SOMEBODY' STOPPED TYPING - if (WasHimself) { // IDENTIFY 'SOMEBODY' -> WAS HIMSELF -> NOT THAT IMPORTANT (USER KNOWS WHEN HE STOPS TYPING?) - console.log("%c[CHAT TYPING LOGGER] You stopped typing!", "color: gray"); - } else { // IDENTIFY 'SOMEBODY' -> WAS OTHER USER -> REMOVE TYPING ANIMATION - //TypingIndicatorMessage.fadeOut("fast"); - TypingIndicatorMessage.remove(); - console.log("%c[CHAT TYPING LOGGER] " + Username + " stopped typing!", "color: gray"); - } - } - } else if (ServerMessageType === "Verify") { // TYPE: SERVER CHECKED ACCESS -- MOSTLY HANDLED IN BACKEND - if (Granted) { - console.log("%c[CHATSOCKET LOGGER] Chat access granted!", "color: green"); - } else { - triggerErrorPopup("ChatNotAllowed"); - console.log("%c[CHATSOCKET LOGGER] Chat access denied!", "color: red"); - } - } else if (ServerMessageType === "SetReceiver") { // TYPE: SERVER CHECKED ACCESS -- MOSTLY HANDLED IN BACKEND - if (Success) { - console.log("%c[CHATSOCKET LOGGER] Setting receiver succeeded!", "color: green"); - - // CHANGE HEADER TAB CAPTION - $(".ChatTab .headerWrap .header .HeaderCaption.TabCaption").hide(); - $(".HeaderCaption#" + ReceiversUsername).length - ? $(".HeaderCaption#" + ReceiversUsername).show() - : $(".ChatTab .headerWrap .header > .LeftButtonHeader").after("" + ReceiversUsername + ""); - $(".ChatTab .headerWrap .LeftButtonHeader").html(""); // REPLACE MENU BUTTON WITH BACK BUTTON - - SelectReceiver.hide(); - SelectedReceiver.show(); // SHOW PARENT DIV - $(".SelectedReceiver > #ChatMessages").hide(); // HIDE EVERY CHAT INSTANCE - $(".SelectedReceiver > *").addClass("animated slideInRight"); - ChatTextInput.show(); // SHOW CHAT INPUT - CurrentChatMessagesWindow.show(); // ONLY SHOW SELECTED CHAT INSTANCE - } else { - console.log("%c[CHATSOCKET LOGGER] Setting receiver failed!", "color: red"); - } - } - } else { // NO SERVER MESSAGE -> SENT BY USER - // DECRYPT MESSAGE - options = { - message: openpgp.message.readArmored("-----BEGIN PGP MESSAGE-----\r\nVersion: OpenPGP.js v3.0.9\r\nComment: https://openpgpjs.org\r\n\r\n" + Message + "\r\n\-----END PGP MESSAGE-----\r\n"), // FORMAT MESSAGE - publicKeys: openpgp.key.readArmored(PublicKey[Username]).keys, // FOR VERIFICATION - privateKeys: [privKeyObj] - }; - openpgp.decrypt(options).then(function (plaintext) { - plaintext ? console.log("%c[ENCRYPTION LOGGER] Decrypting succeeded!", "font-family: monospace; white-space: pre; display: inline-block; border-radius: 10px; padding: 2px; color: #20c20e; background-color: black;") : console.log("%c[ENCRYPTION LOGGER] Decrypting failed!", "font-family: monospace; white-space: pre; display: inline-block; border-radius: 10px; padding: 2px; color: red; background-color: black;"); - DecryptedMessage = plaintext.data; - if (WasHimself) { // -> MESSAGE WAS FROM HIMSELF -> Don't write to chat, as its done directly (on enter function at the bottom, for performance) - console.log("%c[CHATSOCKET LOGGER] Message sending succeeded!", "color: darkorange"); - } else { // -> MESSAGE WAS FROM OTHER USER -> decrypt - console.log("%c[CHATSOCKET LOGGER] You received a message!", "color: darkorange"); - NotifySound.play(); - Push.create(Fullname, { // CREATE NOTIFICATION - body: DecryptedMessage, - icon: Avatar, - timeout: 5000, - onClick: function () { - window.focus(); - this.close(); - } - }); - if (LastMessage.hasClass("MessageReceived")) { - if (LastMessage.hasClass("MessageReceived")) { // IF PREVIOUS MESSAGE WAS FROM OTHER USER TOO -> CREATE WITH CORRESPONDING CLASSES FOR DESIGN - CurrentChatMessagesWindow.append("
" + DecryptedMessage + "
"); - if (LastMessage.hasClass("AloneMessage")) { - LastMessage.removeClass("AloneMessage"); - LastMessage.addClass("TopMessage"); - } else if (LastMessage.hasClass("BottomMessage")) { - LastMessage.removeClass("BottomMessage"); - LastMessage.addClass("MiddleMessage"); - } - } - } else { // CHECK IF PREVIOUS MESSAGE WAS FROM OTHER USER TOO -> IF NOT, CREATE NEW 'ALONE' MESSAGE - CurrentChatMessagesWindow.append("
" + DecryptedMessage + "
"); - } - } - }); - - // CONVERT LINKS TO LINKS - $('.ChatMessage').linkify({ - target: "_blank" - }); - } - // SCROLL TO BOTTOM ON NEW MESSAGE OF ANY KIND - if ((CurrentChatMessagesWindow.scrollTop() + CurrentChatMessagesWindow.innerHeight() < CurrentChatMessagesWindow[0].scrollHeight)) { - CurrentChatMessagesWindow.animate({scrollTop: document.querySelector("#ChatMessages").scrollHeight}); - } - }; - - - // TYPING RECOGNITION - let typingTimer; - let isTyping = false; - - ChatTextInput.keydown(function () { - sendStartTyping(); - clearTimeout(typingTimer); - }); - - ChatTextInput.keyup(function () { - clearTimeout(typingTimer); - typingTimer = setTimeout(function () { - sendStopTyping() - }, 2500) - }); - - function sendStartTyping() { - if (!isTyping) { - sendTypingState(true); - isTyping = true; - } - } - - function sendStopTyping() { - if (isTyping) { - sendTypingState(false); - isTyping = false; - } - } - - function sendTypingState(state) { // SEND STATE TO CHAT SERVER - ChatSocket.send(JSON.stringify({ClientMessageType: "TypingState", State: state})); - } - - // SEND MESSAGE FROM INPUT FIELD - ChatTextInput.keyup(function (e) { - if (ChatSocket.readyState === 1) { - if (e.keyCode === 13 && ChatTextInput.val().length > 0) { - const ChatTextInputText = ChatTextInput.val(); - const LastMessage = $(".MessageWrapper.Normal:last .ChatMessage"); - ChatTextInput.val(""); - if (!LastMessage.hasClass("MessageSent")) { // CHECK IF PREVIOUS MESSAGE WAS FROM HIMSELF TOO -> IF NOT, CREATE NEW 'ALONE' MESSAGE - CurrentChatMessagesWindow.append("
" + ChatTextInputText + "
"); - } else if (LastMessage.hasClass("MessageSent")) { // IF PREVIOUS MESSAGE WAS FROM HIMSELF TOO -> CREATE WITH CORRESPONDING CLASSES FOR DESIGN - CurrentChatMessagesWindow.append("
" + ChatTextInputText + "
"); - if (LastMessage.hasClass("AloneMessage")) { - LastMessage.removeClass("AloneMessage"); - LastMessage.addClass("TopMessage"); - } else if (LastMessage.hasClass("BottomMessage")) { - LastMessage.removeClass("BottomMessage"); - LastMessage.addClass("MiddleMessage"); - } - } - - // USER USUALLY STOPS TYPING ON SENDING -> CHANGE STATE TO FALSE - sendTypingState(false); - isTyping = false; - clearTimeout(typingTimer); - - // ENCRYPT AND SEND MESSAGE WITH OWN PUBLIC KEY - options = { - data: ChatTextInputText, - publicKeys: openpgp.key.readArmored(PublicKey[current_username]).keys, - privateKeys: [privKeyObj] // FOR SIGNING - }; - openpgp.encrypt(options).then(function (Encrypted) { - EncryptedMessage = Encrypted.data.substr(91).slice(0, -29); // SLICING FOR DATABASE SAVING (LESS DATA) - console.log("%c[ENCRYPTION LOGGER]\nEncrypted message for sender: \n\n" + EncryptedMessage, "font-family: monospace; white-space: pre; display: inline-block; border-radius: 10px; padding: 5px; color: #20c20e; background-color: black;"); - - ChatSocket.send(JSON.stringify({ - ClientMessageType: "ChatMessage", - EncryptedWithKeyOfUsername: current_username, - Message: EncryptedMessage - })); - }); - - // ENCRYPT AND SEND MESSAGE WITH RECEIVERS PUBLIC KEY - options = { - data: ChatTextInputText, - publicKeys: openpgp.key.readArmored(PublicKey[ReceiversUsername]).keys, - privateKeys: [privKeyObj] // FOR SIGNING - }; - openpgp.encrypt(options).then(function (Encrypted) { - EncryptedMessage = Encrypted.data.substr(91).slice(0, -29); // SLICING FOR DATABASE SAVING (LESS DATA) - console.log("%c[ENCRYPTION LOGGER]\nEncrypted message for receiver: \n\n" + EncryptedMessage, "font-family: monospace; white-space: pre; display: inline-block; border-radius: 10px; padding: 5px; color: #20c20e; background-color: black;"); - - ChatSocket.send(JSON.stringify({ - ClientMessageType: "ChatMessage", - EncryptedWithKeyOfUsername: ReceiversUsername, - Message: EncryptedMessage - })); - }); - } - } else { - NotConnectedAnymore(); - } - }); - - // SET RECEIVER - $(document).on("click", ".ReceiverSelector", function () { - ReceiversUsername = $(this).attr("data-username"); - ReceiversId = $(this).attr("data-id"); - ChatSocket.send(JSON.stringify({ - ClientMessageType: "SetReceiver", - ReceiversId: ReceiversId, - ReceiversUsername: ReceiversUsername - })); - }); - - /** - * SEVERAL THINGS WHICH DON'T MATCH ANY OTHER SECTION - */ - function NotConnectedAnymore() { - ChatTextInput.off("keyup"); - console.log("%c[CHATSOCKET LOGGER] Not connected to Websocket anymore! Trying to connect again...", "color: red"); - InitializeChatServer(); - } - - // BACK BUTTON - $(document).on("click", "#BackToChatSelectorButton", function () { - $(".SelectReceiver > *").addClass("animated slideInLeft"); - $(".ChatTab .headerWrap .header .HeaderCaption").hide(); - $(".ChatTab .headerWrap .header .HeaderCaption.TabCaption").show(); - $(".ChatTab .headerWrap .LeftButtonHeader").html(""); // REPLACE BACK BUTTON WITH MENU BUTTON - SelectedReceiver.hide(); - SelectReceiver.show(); - }); - - // USER STOPS TYPING ON PAGE LEAVE - window.history.pushState({page: 1}, "", ""); - window.onpopstate = function (event) { - if (event) { - sendStopTyping(); - } - }; - $(window).unload(function () { - sendStopTyping(); - }); - }; -} - +/** + * GLOBAL DECLARATIONS + */ +let LastMessage, Username, ReceiversUsername, CurrentChatMessagesWindow, ReceiversId, options, EncryptedMessage, + DecryptedMessage; + +/** + * INITIAL ENCRYPTION CONFIGURATION + */ +const openpgp = window.openpgp; +const PublicKey = []; +openpgp.initWorker({path: '/assets-raw/core/assets/SiteAssets/js/openpgp.worker.js'}); +const privKeyObj = openpgp.key.readArmored(localStorage.getItem("PrivateKey").replace(/\r/, "")).keys[0]; +privKeyObj.decrypt(localStorage.getItem("🔒")); + + +// console.log(AES_CBC.encrypt( "LOL", '0123456789' )); // For future me: TODO: Encrypt user data with symmetric encryption (AES_CBC) and like told here: https://stackoverflow.com/a/7529707/9783773 + + +/** + * GENERAL CHAT + */ +function InitializeChatServer() { + const ChatTextInput = $("#ChatTextInput"); + const SubscribeTextInput = $("#SubscribeTextInput"); + const ChatMessages = $("#ChatMessages:visible"); + const SelectReceiver = $(".SelectReceiver"); + const SelectedReceiver = $(".SelectedReceiver"); + const TypingIndicatorAnimationElement = "
"; + + const WebSocketConnectTimerStart = performance.now(); // START CONNECTION EXECUTION TIMER + const ChatSocket = new WebSocket('wss://marvinborner.ddnss.de:1337'); + ChatSocket.onerror = function () { + setTimeout(function () { + console.log("%c[CHATSOCKET LOGGER] Connection failed. Trying again...", "color: red"); + InitializeChatServer(); + }, 5000); + }; + ChatSocket.onopen = function () { + // CONNECTION SUCCESSFUL! + const WebSocketConnectTimerEnd = performance.now(); // END CONNECTION EXECUTION TIMER + console.log("%c[CHATSOCKET LOGGER] Chat connection established! (Took " + (WebSocketConnectTimerEnd - WebSocketConnectTimerStart) + " milliseconds)", "color: darkorange"); + // START VERIFICATION + ChatSocket.send(JSON.stringify({ + ClientMessageType: "Verify", + Cookie: document.cookie, + UserID: current_user_id + })); + console.log("%c[CHATSOCKET LOGGER] Started chat verification process...", "color: gray"); + // GOT MESSAGE + ChatSocket.onmessage = function (e) { + // DECLARATIONS + const TypingIndicatorMessage = $(".TypingIndicatorMessage").parent(); + const MessageObject = JSON.parse(e.data); + const Message = MessageObject.Message; // ENCRYPTED MESSAGE (NOT ENCRYPTED ON SERVER MESSAGES) + const MessageId = MessageObject.MessageId; + const Fullname = MessageObject.Fullname; + const Avatar = MessageObject.Avatar; + const GroupName = MessageObject.GroupName; + const ServerMessageType = MessageObject.ServerMessageType; + let State = MessageObject.State; + let ServerMessage = MessageObject.ServerMessage; + let WasHimself = MessageObject.WasHimself; + let Granted = MessageObject.Granted; + let Success = MessageObject.Success; + + // GLOBAL OVERWRITES + LastMessage = $(".MessageWrapper.Normal:last .ChatMessage"); + CurrentChatMessagesWindow = $("#ChatMessages[data-username=" + ReceiversUsername + "]"); + Username = MessageObject.Username; + + // GET OWN PUBLIC KEY FIRST + if (!(current_username in PublicKey)) { + $.ajax({ + type: 'GET', + url: site.uri.public + '/api/users/u/' + current_username + '/publickey', + dataType: "json", + success: function (response) { + PublicKey[current_username] = response.PublicKey; + console.log("%c[ENCRYPTION LOGGER]\nPublickey of " + current_username + ": \n\n" + PublicKey[current_username].substr(96).slice(0, -35), "font-family: monospace; white-space: pre; display: inline-block; border-radius: 10px; padding: 5px; color: #20c20e; background-color: black;") + } + }); + } + + // GET PUBLIC KEY IF NOT ALREADY DID + if (!(ReceiversUsername in PublicKey) && ReceiversUsername !== null && ReceiversUsername !== undefined) { + $.ajax({ + type: 'GET', + url: site.uri.public + '/api/users/u/' + ReceiversUsername + '/publickey', + dataType: "json", + success: function (response) { + PublicKey[ReceiversUsername] = response.PublicKey; + console.log("%c[ENCRYPTION LOGGER]\nPublickey of " + ReceiversUsername + ": \n\n" + PublicKey[ReceiversUsername].substr(96).slice(0, -35), "font-family: monospace; white-space: pre; display: inline-block; border-radius: 10px; padding: 5px; color: #20c20e; background-color: black;") + } + }); + } + + if (ServerMessage) { // SERVER MESSAGE + if (ServerMessageType === "GroupJoin") { // TYPE: USER JOINED A GROUP + if (WasHimself) { // HIMSELF JOINED A GROUP -> NOTIFY + CurrentChatMessagesWindow.empty(); // -> EMPTY MESSAGES ON NEW GROUP JOIN + CurrentChatMessagesWindow.append("
" + GroupName + "

"); + ReplaceServerMessage("YouGroupJoin"); // FOR TRANSLATION + console.log("%c[CHATSOCKET LOGGER] You joined the group " + GroupName + "!", "color: darkorange"); + } else { // OTHER USER JOINED A GROUP -> NOTIFY + CurrentChatMessagesWindow.append("
" + Username + "

"); + ReplaceServerMessage("UserGroupJoin"); // FOR TRANSLATION + console.log("%c[CHATSOCKET LOGGER] " + Username + " joined the group!", "color: darkorange"); + } + } else if (ServerMessageType === "UserDisconnect") { // TYPE: USER DISCONNECTED -> NOTIFY + CurrentChatMessagesWindow.append("
" + Username + "

"); + ReplaceServerMessage("UserDisconnect"); // FOR TRANSLATION + console.log("%c[CHATSOCKET LOGGER] " + Username + " disconnected from server!", "color: darkorange"); + } else if (ServerMessageType === "TypingState") { // TYPE: SOMEBODY'S TYPING STATE CHANGED! + if (State) { // IF 'SOMEBODY' STARTED TYPING + if (WasHimself) { // IDENTIFY 'SOMEBODY' -> WAS HIMSELF -> NOT THAT IMPORTANT (USER KNOWS WHEN HE STARTS TYPING?) + console.log("%c[CHAT TYPING LOGGER] You started typing!", "color: gray"); + } else if (!WasHimself) { // IDENTIFY 'SOMEBODY' -> WAS OTHER USER -> SHOW TYPING ANIMATION ON RECEIVER'S SIDE + CurrentChatMessagesWindow.append("
" + TypingIndicatorAnimationElement + "
"); + console.log("%c[CHAT TYPING LOGGER] " + Username + " started typing!", "color: gray"); + } + } else { // IF 'SOMEBODY' STOPPED TYPING + if (WasHimself) { // IDENTIFY 'SOMEBODY' -> WAS HIMSELF -> NOT THAT IMPORTANT (USER KNOWS WHEN HE STOPS TYPING?) + console.log("%c[CHAT TYPING LOGGER] You stopped typing!", "color: gray"); + } else { // IDENTIFY 'SOMEBODY' -> WAS OTHER USER -> REMOVE TYPING ANIMATION + //TypingIndicatorMessage.fadeOut("fast"); + TypingIndicatorMessage.remove(); + console.log("%c[CHAT TYPING LOGGER] " + Username + " stopped typing!", "color: gray"); + } + } + } else if (ServerMessageType === "Verify") { // TYPE: SERVER CHECKED ACCESS -- MOSTLY HANDLED IN BACKEND + if (Granted) { + console.log("%c[CHATSOCKET LOGGER] Chat access granted!", "color: green"); + } else { + triggerErrorPopup("ChatNotAllowed"); + console.log("%c[CHATSOCKET LOGGER] Chat access denied!", "color: red"); + } + } else if (ServerMessageType === "SetReceiver") { // TYPE: SERVER CHECKED ACCESS -- MOSTLY HANDLED IN BACKEND + if (Success) { + console.log("%c[CHATSOCKET LOGGER] Setting receiver succeeded!", "color: green"); + + // CHANGE HEADER TAB CAPTION + $(".ChatTab .headerWrap .header .HeaderCaption.TabCaption").hide(); + $(".HeaderCaption#" + ReceiversUsername).length + ? $(".HeaderCaption#" + ReceiversUsername).show() + : $(".ChatTab .headerWrap .header > .LeftButtonHeader").after("" + ReceiversUsername + ""); + $(".ChatTab .headerWrap .LeftButtonHeader").html(""); // REPLACE MENU BUTTON WITH BACK BUTTON + + SelectReceiver.hide(); + SelectedReceiver.show(); // SHOW PARENT DIV + $(".SelectedReceiver > #ChatMessages").hide(); // HIDE EVERY CHAT INSTANCE + $(".SelectedReceiver > *").addClass("animated slideInRight"); + ChatTextInput.show(); // SHOW CHAT INPUT + CurrentChatMessagesWindow.show(); // ONLY SHOW SELECTED CHAT INSTANCE + } else { + console.log("%c[CHATSOCKET LOGGER] Setting receiver failed!", "color: red"); + } + } + } else { // NO SERVER MESSAGE -> SENT BY USER + // DECRYPT MESSAGE + options = { + message: openpgp.message.readArmored("-----BEGIN PGP MESSAGE-----\r\nVersion: OpenPGP.js v3.0.9\r\nComment: https://openpgpjs.org\r\n\r\n" + Message + "\r\n\-----END PGP MESSAGE-----\r\n"), // FORMAT MESSAGE + publicKeys: openpgp.key.readArmored(PublicKey[Username]).keys, // FOR VERIFICATION + privateKeys: [privKeyObj] + }; + openpgp.decrypt(options).then(function (plaintext) { + plaintext ? console.log("%c[ENCRYPTION LOGGER] Decrypting succeeded!", "font-family: monospace; white-space: pre; display: inline-block; border-radius: 10px; padding: 2px; color: #20c20e; background-color: black;") : console.log("%c[ENCRYPTION LOGGER] Decrypting failed!", "font-family: monospace; white-space: pre; display: inline-block; border-radius: 10px; padding: 2px; color: red; background-color: black;"); + DecryptedMessage = plaintext.data; + if (WasHimself) { // -> MESSAGE WAS FROM HIMSELF -> Don't write to chat, as its done directly (on enter function at the bottom, for performance) + console.log("%c[CHATSOCKET LOGGER] Message sending succeeded!", "color: darkorange"); + } else { // -> MESSAGE WAS FROM OTHER USER -> decrypt + console.log("%c[CHATSOCKET LOGGER] You received a message!", "color: darkorange"); + NotifySound.play(); + Push.create(Fullname, { // CREATE NOTIFICATION + body: DecryptedMessage, + icon: Avatar, + timeout: 5000, + onClick: function () { + window.focus(); + this.close(); + } + }); + if (LastMessage.hasClass("MessageReceived")) { + if (LastMessage.hasClass("MessageReceived")) { // IF PREVIOUS MESSAGE WAS FROM OTHER USER TOO -> CREATE WITH CORRESPONDING CLASSES FOR DESIGN + CurrentChatMessagesWindow.append("
" + DecryptedMessage + "
"); + if (LastMessage.hasClass("AloneMessage")) { + LastMessage.removeClass("AloneMessage"); + LastMessage.addClass("TopMessage"); + } else if (LastMessage.hasClass("BottomMessage")) { + LastMessage.removeClass("BottomMessage"); + LastMessage.addClass("MiddleMessage"); + } + } + } else { // CHECK IF PREVIOUS MESSAGE WAS FROM OTHER USER TOO -> IF NOT, CREATE NEW 'ALONE' MESSAGE + CurrentChatMessagesWindow.append("
" + DecryptedMessage + "
"); + } + } + }); + + // CONVERT LINKS TO LINKS + $('.ChatMessage').linkify({ + target: "_blank" + }); + } + // SCROLL TO BOTTOM ON NEW MESSAGE OF ANY KIND + if ((CurrentChatMessagesWindow.scrollTop() + CurrentChatMessagesWindow.innerHeight() < CurrentChatMessagesWindow[0].scrollHeight)) { + CurrentChatMessagesWindow.animate({scrollTop: document.querySelector("#ChatMessages").scrollHeight}); + } + }; + + + // TYPING RECOGNITION + let typingTimer; + let isTyping = false; + + ChatTextInput.keydown(function () { + sendStartTyping(); + clearTimeout(typingTimer); + }); + + ChatTextInput.keyup(function () { + clearTimeout(typingTimer); + typingTimer = setTimeout(function () { + sendStopTyping() + }, 2500) + }); + + function sendStartTyping() { + if (!isTyping) { + sendTypingState(true); + isTyping = true; + } + } + + function sendStopTyping() { + if (isTyping) { + sendTypingState(false); + isTyping = false; + } + } + + function sendTypingState(state) { // SEND STATE TO CHAT SERVER + ChatSocket.send(JSON.stringify({ClientMessageType: "TypingState", State: state})); + } + + // SEND MESSAGE FROM INPUT FIELD + ChatTextInput.keyup(function (e) { + if (ChatSocket.readyState === 1) { + if (e.keyCode === 13 && ChatTextInput.val().length > 0) { + const ChatTextInputText = ChatTextInput.val(); + const LastMessage = $(".MessageWrapper.Normal:last .ChatMessage"); + ChatTextInput.val(""); + if (!LastMessage.hasClass("MessageSent")) { // CHECK IF PREVIOUS MESSAGE WAS FROM HIMSELF TOO -> IF NOT, CREATE NEW 'ALONE' MESSAGE + CurrentChatMessagesWindow.append("
" + ChatTextInputText + "
"); + } else if (LastMessage.hasClass("MessageSent")) { // IF PREVIOUS MESSAGE WAS FROM HIMSELF TOO -> CREATE WITH CORRESPONDING CLASSES FOR DESIGN + CurrentChatMessagesWindow.append("
" + ChatTextInputText + "
"); + if (LastMessage.hasClass("AloneMessage")) { + LastMessage.removeClass("AloneMessage"); + LastMessage.addClass("TopMessage"); + } else if (LastMessage.hasClass("BottomMessage")) { + LastMessage.removeClass("BottomMessage"); + LastMessage.addClass("MiddleMessage"); + } + } + + // USER USUALLY STOPS TYPING ON SENDING -> CHANGE STATE TO FALSE + sendTypingState(false); + isTyping = false; + clearTimeout(typingTimer); + + // ENCRYPT AND SEND MESSAGE WITH OWN PUBLIC KEY + options = { + data: ChatTextInputText, + publicKeys: openpgp.key.readArmored(PublicKey[current_username]).keys, + privateKeys: [privKeyObj] // FOR SIGNING + }; + openpgp.encrypt(options).then(function (Encrypted) { + EncryptedMessage = Encrypted.data.substr(91).slice(0, -29); // SLICING FOR DATABASE SAVING (LESS DATA) + console.log("%c[ENCRYPTION LOGGER]\nEncrypted message for sender: \n\n" + EncryptedMessage, "font-family: monospace; white-space: pre; display: inline-block; border-radius: 10px; padding: 5px; color: #20c20e; background-color: black;"); + + ChatSocket.send(JSON.stringify({ + ClientMessageType: "ChatMessage", + EncryptedWithKeyOfUsername: current_username, + Message: EncryptedMessage + })); + }); + + // ENCRYPT AND SEND MESSAGE WITH RECEIVERS PUBLIC KEY + options = { + data: ChatTextInputText, + publicKeys: openpgp.key.readArmored(PublicKey[ReceiversUsername]).keys, + privateKeys: [privKeyObj] // FOR SIGNING + }; + openpgp.encrypt(options).then(function (Encrypted) { + EncryptedMessage = Encrypted.data.substr(91).slice(0, -29); // SLICING FOR DATABASE SAVING (LESS DATA) + console.log("%c[ENCRYPTION LOGGER]\nEncrypted message for receiver: \n\n" + EncryptedMessage, "font-family: monospace; white-space: pre; display: inline-block; border-radius: 10px; padding: 5px; color: #20c20e; background-color: black;"); + + ChatSocket.send(JSON.stringify({ + ClientMessageType: "ChatMessage", + EncryptedWithKeyOfUsername: ReceiversUsername, + Message: EncryptedMessage + })); + }); + } + } else { + NotConnectedAnymore(); + } + }); + + // SET RECEIVER + $(document).on("click", ".ReceiverSelector", function () { + ReceiversUsername = $(this).attr("data-username"); + ReceiversId = $(this).attr("data-id"); + ChatSocket.send(JSON.stringify({ + ClientMessageType: "SetReceiver", + ReceiversId: ReceiversId, + ReceiversUsername: ReceiversUsername + })); + }); + + /** + * SEVERAL THINGS WHICH DON'T MATCH ANY OTHER SECTION + */ + function NotConnectedAnymore() { + ChatTextInput.off("keyup"); + console.log("%c[CHATSOCKET LOGGER] Not connected to Websocket anymore! Trying to connect again...", "color: red"); + InitializeChatServer(); + } + + // BACK BUTTON + $(document).on("click", "#BackToChatSelectorButton", function () { + $(".SelectReceiver > *").addClass("animated slideInLeft"); + $(".ChatTab .headerWrap .header .HeaderCaption").hide(); + $(".ChatTab .headerWrap .header .HeaderCaption.TabCaption").show(); + $(".ChatTab .headerWrap .LeftButtonHeader").html(""); // REPLACE BACK BUTTON WITH MENU BUTTON + SelectedReceiver.hide(); + SelectReceiver.show(); + }); + + // USER STOPS TYPING ON PAGE LEAVE + window.history.pushState({page: 1}, "", ""); + window.onpopstate = function (event) { + if (event) { + sendStopTyping(); + } + }; + $(window).unload(function () { + sendStopTyping(); + }); + }; +} + InitializeChatServer(); // EVERYTHING IN ONE FUNCTION FOR SIMPLICITY (GLOBAL FUNCTIONS ETC) \ No newline at end of file diff --git a/main/app/sprinkles/core/assets/SiteAssets/js/console.image.js b/main/app/sprinkles/core/assets/SiteAssets/js/console.image.js index c698c02..b0d682e 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/js/console.image.js +++ b/main/app/sprinkles/core/assets/SiteAssets/js/console.image.js @@ -1,280 +1,280 @@ -/** - * Dubiously created by Adrian Cooney - * http://adriancooney.github.io - */ -(function (console) { - "use strict"; - - //Bootlegged of imgur.com/memegen - var memes = { - "10 Guy": "//i.imgur.com/LaENqOV.jpg", - "3rd World Success Kid": "//i.imgur.com/WA5duA1.jpg", - "90's Problems": "//i.imgur.com/tL47qtp.jpg", - "Aaand It's Gone": "//i.imgur.com/yf12saq.jpg", - "Actual Advice Mallard": "//i.imgur.com/WymFmVy.jpg", - "Advice Dog": "//i.imgur.com/Qk0VO6D.jpg", - "Advice God": "//i.imgur.com/xH2fSFg.jpg", - "Almost Politically Correct Redneck": "//i.imgur.com/YqLgINf.jpg", - "Am I The Only One": "//i.imgur.com/gS9YL5U.jpg", - "Ancient Aliens": "//i.imgur.com/NfCknz0.jpg", - "Annoyed Picard": "//i.imgur.com/s9GmfSS.jpg", - "Annoying Childhood Friend": "//i.imgur.com/27VCyQw.jpg", - "Annoying Facebook Girl": "//i.imgur.com/ccczyGt.jpg", - "Anti-Joke Chicken (Rooster)": "//i.imgur.com/KOsW0jh.jpg", - "Awkward Penguin": "//i.imgur.com/ez1tQrq.jpg", - "Back In My Day Grandpa": "//i.imgur.com/zuJSZp8.jpg", - "Bad Advice Mallard": "//i.imgur.com/QEPvL2B.jpg", - "Bad Luck Brian": "//i.imgur.com/sRW8BiO.jpg", - "Bear Grylls": "//i.imgur.com/6Spqy1D.jpg", - "Brace Yourself": "//i.imgur.com/NhIq0LY.jpg", - "Captain Obvious": "//i.imgur.com/DmUcxBu.jpg", - "Chemistry Cat": "//i.imgur.com/8agP4Xe.jpg", - "College Freshman": "//i.imgur.com/2Ynyv9t.jpg", - "College Liberal": "//i.imgur.com/OWfvSFE.jpg", - "Condescending Wonka": "//i.imgur.com/D0e5fgL.jpg", - "Confession Bear": "//i.imgur.com/kH1SKhp.jpg", - "Confession Kid": "//i.imgur.com/jhOxR12.jpg", - "Confused Gandalf": "//i.imgur.com/iIb5SEo.jpg", - "Conspiracy Keanu": "//i.imgur.com/pFyk3J7.jpg", - "Courage Wolf": "//i.imgur.com/H5qoXFb.jpg", - "Dating Site Murderer": "//i.imgur.com/jffNNql.jpg", - "Depression Dog": "//i.imgur.com/wgad6P8.jpg", - "Drunk Baby": "//i.imgur.com/QvZdbRE.jpg", - "English Motherfucker": "//i.imgur.com/sJThEC0.jpg", - "Evil Plotting Raccoon": "//i.imgur.com/xMslWFf.jpg", - "First Day On The Internet Kid": "//i.imgur.com/TWfdmVu.jpg", - "First World Cat Problems": "//i.imgur.com/0vR5Slq.jpg", - "First World Problem": "//i.imgur.com/ATcIl08.jpg", - "Forever Alone": "//i.imgur.com/pcfXSUU.jpg", - "Forever Resentful Mother": "//i.imgur.com/pIrdwo2.jpg", - "Foul Bachelor Frog": "//i.imgur.com/JUFmusm.jpg", - "Foul Bachelorette Frog": "//i.imgur.com/dYf971U.jpg", - "Friendzone Fiona": "//i.imgur.com/Qu1eedL.jpg", - "Frustrated Farnsworth": "//i.imgur.com/U3SElKP.jpg", - "Fuck Me, Right?": "//i.imgur.com/J9gfxsx.jpg", - "Gangster Baby": "//i.imgur.com/C3XhI56.jpg", - "Good Girl Gina": "//i.imgur.com/qK6lYr2.jpg", - "Good Guy Greg": "//i.imgur.com/UXMPoKN.jpg", - "Grandma Finds The Internet": "//i.imgur.com/xPfGYqu.jpg", - "Grinds My Gears": "//i.imgur.com/t4JqU1j.jpg", - "Grumpy Cat (Tard)": "//i.imgur.com/dU5CDxN.jpg", - "High Expectations Asian Father": "//i.imgur.com/7QeB9LI.jpg", - "Hipster Barista": "//i.imgur.com/AbWxdy2.jpg", - "Horrifying House Guest": "//i.imgur.com/DxmoFp1.jpg", - "I Dare You Samuel Jackson": "//i.imgur.com/UQtpdqj.jpg", - "I Should Buy A Boat": "//i.imgur.com/XqlqPxn.jpg", - "I Too Like To Live Dangerously": "//i.imgur.com/qF70EL9.jpg", - "Idiot Nerd Girl": "//i.imgur.com/8hYPYwd.jpg", - "Insanity Wolf": "//i.imgur.com/GOOdg3k.jpg", - "Joker Mind Loss": "//i.imgur.com/qQIRaOD.jpg", - "Joseph Ducreux": "//i.imgur.com/QL7TyR9.jpg", - "Lame Joke Eel": "//i.imgur.com/oQXw3jF.jpg", - "Lame Pun Raccoon": "//i.imgur.com/nvALRK3.jpg", - "Lazy College Senior": "//i.imgur.com/PpkVfzz.jpg", - "Mad Karma": "//i.imgur.com/G0QMPum.jpg", - "Masturbating Spidey": "//i.imgur.com/dZ7AB4c.jpg", - "Matrix Morpheus": "//i.imgur.com/8Yrw6cZ.jpg", - "Mayonnaise Patrick": "//i.imgur.com/5jE0Y7f.jpg", - "Musically Oblivious 8th Grader": "//i.imgur.com/l5YHN5D.jpg", - "Not Sure Fry": "//i.imgur.com/7rFgBB1.jpg", - "Oblivious Suburban Mom": "//i.imgur.com/Y7o7UJs.jpg", - "One Does Not Simply": "//i.imgur.com/7LrwR1Y.jpg", - "Overly Attached Girlfriend": "//i.imgur.com/5blLJLR.jpg", - "Overly Manly Man": "//i.imgur.com/dOSn9Na.jpg", - "Paranoid Parrot": "//i.imgur.com/KooYHdg.jpg", - "Pedobear": "//i.imgur.com/c6JZKRW.jpg", - "Pepperidge Farm Remembers": "//i.imgur.com/uFde4v5.jpg", - "Philosoraptor": "//i.imgur.com/eERhI5h.jpg", - "Priority Peter": "//i.imgur.com/BBEFk0e.jpg", - "Rasta Science Teacher": "//i.imgur.com/Js6Ai5T.jpg", - "Redditor's Wife": "//i.imgur.com/d1XfJeD.jpg", - "Revenge Band Kid": "//i.imgur.com/dlvmaRI.jpg", - "Schrute Facts": "//i.imgur.com/UxcvPwT.jpg", - "Scumbag Brain": "//i.imgur.com/OZhhZdS.jpg", - "Scumbag Stacy": "//i.imgur.com/Qqz1axp.jpg", - "Scumbag Steve": "//i.imgur.com/Rfvoc0Y.jpg", - "Sexually Oblivious Rhino": "//i.imgur.com/RoaNuEC.jpg", - "Sheltering Suburban Mom": "//i.imgur.com/vMkSofv.jpg", - "Shut Up And Take My Money": "//i.imgur.com/uWe0rtQ.jpg", - "Skeptical Third World Kid": "//i.imgur.com/uwAusxV.jpg", - "Smug Spongebob": "//i.imgur.com/OTTRjrv.jpg", - "Socially Awesome Penguin": "//i.imgur.com/S6WgQW7.jpg", - "Success Kid": "//i.imgur.com/ZibijBz.jpg", - "Successful Black Man": "//i.imgur.com/ogIm0cy.jpg", - "Sudden Clarity Clarence": "//i.imgur.com/N3Xmfbe.jpg", - "Tech Impaired Duck": "//i.imgur.com/riz28ci.jpg", - "The Most Interesting Man In The World": "//i.imgur.com/MGv15MH.jpg", - "The Rent Is Too High": "//i.imgur.com/r5WLktQ.jpg", - "Tough Spongebob": "//i.imgur.com/2w0F1HX.jpg", - "Unhelpful Highschool Teacher": "//i.imgur.com/ohbGhuD.jpg", - "Vengeance Dad": "//i.imgur.com/0nUStsa.jpg", - "What Year Is It?": "//i.imgur.com/fj79hQS.jpg", - "X, X Everywhere": "//i.imgur.com/GGy94Gt.jpg", - "Yeah That'd Be Great": "//i.imgur.com/nz9M2pl.jpg", - "Yo Dawg Xzibit": "//i.imgur.com/XOyGqF2.jpg", - "You're Bad And You Should Feel Bad": "//i.imgur.com/YsabGnQ.jpg", - "You're Gonna Have A Bad Time": "//i.imgur.com/2tNR7P7.jpg" - }; - - /** - * Since the console.log doesn't respond to the `display` style, - * setting a width and height has no effect. In fact, the only styles - * I've found it responds to is font-size, background-image and color. - * To combat the image repeating, we have to get a create a font bounding - * box so to speak with the unicode box characters. EDIT: See Readme.md - * - * @param {int} width The height of the box - * @param {int} height The width of the box - * @return {object} {string, css} - */ - function getBox(width, height) { - return { - string: "+", - style: "font-size: 1px; padding: " + Math.floor(height / 2) + "px " + Math.floor(width / 2) + "px; line-height: " + height + "px;" - } - } - - /** - * Draw's meme text on a context. - * - * @param {CanvasRenderingContext2D} ctx The canvas context - * @param {string} type "upper"|"lower" - * @param {string} text The text to draw - * @param {int} width The width of the image - * @param {int} y The y value to draw at - * @return {null} - */ - function drawMemeText(ctx, type, text, width, y) { - text = text.toUpperCase(); - //Determine the font size - if (text.length < 24) { - var val = Math.max(0, text.length - 12), - size = 70 + (val * -3); - - drawText(ctx, size, text, width / 2, y); - } else if (text.length < 29) { - drawText(ctx, 40, text, width / 2, y); - } else { - var strs = wrap(text, 27); - strs.forEach(function (str, i) { - drawText(ctx, 40, str, width / 2, (type == "lower") ? (y - ((strs.length - 1) * 40)) + (i * 40) : y + (i * 40)); - }); - } - } - - /** - * Draws text in impact font with stroke on context - * - * @param {CanvasRenderingContext2D} ctx The canvas context - * @param {int} size Font size - * @param {string} text The string to write - * @param {int} x X Position - * @param {int} y Y position - * @return {null} - */ - function drawText(ctx, size, text, x, y) { - //Set the text styles - ctx.font = "bold " + size + "px Impact"; - ctx.fillStyle = "#fff"; - ctx.textAlign = "center"; - ctx.textBaseline = "middle"; - ctx.lineWidth = 7; - ctx.strokeStyle = "#000"; - ctx.strokeText(text, x, y); - ctx.fillText(text, x, y); - } - - /** - * Wrap a line of text at an index - * - * @param {string} text The text - * @param {int} num The index to wrap at - * @return {array} Array of text - */ - function wrap(text, num) { - var output = [], - split = text.split(" "); - - var str = []; - for (var i = 0, cache = split.length; i < cache; i++) { - if ((str + split[i]).length < num) str.push(split[i]) - else { - output.push(str.join(" ")); - str.length = 0; - str.push(split[i]); - } - } - - //Push the final line - output.push(str.join(" ")); - - return output; - } - - /** - * Add a meme to the console! - * - * @param {string} upper The upper text - * @param {string} lower The lower text - * @param {string} image The meme type (see `console.meme` for all supported) or image url (Make sure it's CORS enabled) - * @param {int} width The width of the meme - * @param {int} height The height of the meme - * @return {null} - */ - console.meme = function (upper, lower, image, width, height) { - if (!upper) console.error("Yo, you forgot the text for the upper part of the meme. The bit at the top. Yeah, that bit."); - if (!lower) console.error("You forgot the text for the bottom of the meme, stupid."); - if (!image) console.error("Dude, you forgot the meme type or url for the background image (CORS enabled, *hint* imgur *hint*). To see a list of supported memes, hit `console.meme()`"); - if (!upper && !lower && !image) return console.log("> " + Object.keys(memes).join("\n> ")); - - var canvas = document.createElement("canvas"), - ctx = canvas.getContext("2d"), - width = width || 500, - height = height || 500, - //I tweaked it at these dimensions, - //So everything scales from here - _w = 500, _h = 500; - - var img = new Image(); - img.setAttribute('crossOrigin', 'anonymous'); - img.onload = function () { - canvas.width = width; - canvas.height = height; - - var text = upper.toUpperCase(); - - ctx.scale(width / 500, height / 500); - - //Draw the background - ctx.drawImage(this, 0, 0, _w, _h); - - drawMemeText(ctx, "upper", upper, _w, 50); //upper - drawMemeText(ctx, "lower", lower, _w, _h - 50); //upper - - console.image(canvas.toDataURL()); - }; - - if (memes[image]) var url = memes[image]; - else var url = image; - - img.src = url; //"http://www.corsproxy.com/" + url.replace(/https?:\/\//, ""); - }; - - /** - * Display an image in the console. - * @param {string} url The url of the image. - * @param {int} scale Scale factor on the image - * @return {null} - */ - console.image = function (url, scale) { - scale = scale || 1; - var img = new Image(); - - img.onload = function () { - var dim = getBox(this.width * scale, this.height * scale); - console.log("%c" + dim.string, dim.style + "background: url(" + url + "); background-size: " + (this.width * scale) + "px " + (this.height * scale) + "px; color: transparent;"); - }; - - img.src = url; - }; +/** + * Dubiously created by Adrian Cooney + * http://adriancooney.github.io + */ +(function (console) { + "use strict"; + + //Bootlegged of imgur.com/memegen + var memes = { + "10 Guy": "//i.imgur.com/LaENqOV.jpg", + "3rd World Success Kid": "//i.imgur.com/WA5duA1.jpg", + "90's Problems": "//i.imgur.com/tL47qtp.jpg", + "Aaand It's Gone": "//i.imgur.com/yf12saq.jpg", + "Actual Advice Mallard": "//i.imgur.com/WymFmVy.jpg", + "Advice Dog": "//i.imgur.com/Qk0VO6D.jpg", + "Advice God": "//i.imgur.com/xH2fSFg.jpg", + "Almost Politically Correct Redneck": "//i.imgur.com/YqLgINf.jpg", + "Am I The Only One": "//i.imgur.com/gS9YL5U.jpg", + "Ancient Aliens": "//i.imgur.com/NfCknz0.jpg", + "Annoyed Picard": "//i.imgur.com/s9GmfSS.jpg", + "Annoying Childhood Friend": "//i.imgur.com/27VCyQw.jpg", + "Annoying Facebook Girl": "//i.imgur.com/ccczyGt.jpg", + "Anti-Joke Chicken (Rooster)": "//i.imgur.com/KOsW0jh.jpg", + "Awkward Penguin": "//i.imgur.com/ez1tQrq.jpg", + "Back In My Day Grandpa": "//i.imgur.com/zuJSZp8.jpg", + "Bad Advice Mallard": "//i.imgur.com/QEPvL2B.jpg", + "Bad Luck Brian": "//i.imgur.com/sRW8BiO.jpg", + "Bear Grylls": "//i.imgur.com/6Spqy1D.jpg", + "Brace Yourself": "//i.imgur.com/NhIq0LY.jpg", + "Captain Obvious": "//i.imgur.com/DmUcxBu.jpg", + "Chemistry Cat": "//i.imgur.com/8agP4Xe.jpg", + "College Freshman": "//i.imgur.com/2Ynyv9t.jpg", + "College Liberal": "//i.imgur.com/OWfvSFE.jpg", + "Condescending Wonka": "//i.imgur.com/D0e5fgL.jpg", + "Confession Bear": "//i.imgur.com/kH1SKhp.jpg", + "Confession Kid": "//i.imgur.com/jhOxR12.jpg", + "Confused Gandalf": "//i.imgur.com/iIb5SEo.jpg", + "Conspiracy Keanu": "//i.imgur.com/pFyk3J7.jpg", + "Courage Wolf": "//i.imgur.com/H5qoXFb.jpg", + "Dating Site Murderer": "//i.imgur.com/jffNNql.jpg", + "Depression Dog": "//i.imgur.com/wgad6P8.jpg", + "Drunk Baby": "//i.imgur.com/QvZdbRE.jpg", + "English Motherfucker": "//i.imgur.com/sJThEC0.jpg", + "Evil Plotting Raccoon": "//i.imgur.com/xMslWFf.jpg", + "First Day On The Internet Kid": "//i.imgur.com/TWfdmVu.jpg", + "First World Cat Problems": "//i.imgur.com/0vR5Slq.jpg", + "First World Problem": "//i.imgur.com/ATcIl08.jpg", + "Forever Alone": "//i.imgur.com/pcfXSUU.jpg", + "Forever Resentful Mother": "//i.imgur.com/pIrdwo2.jpg", + "Foul Bachelor Frog": "//i.imgur.com/JUFmusm.jpg", + "Foul Bachelorette Frog": "//i.imgur.com/dYf971U.jpg", + "Friendzone Fiona": "//i.imgur.com/Qu1eedL.jpg", + "Frustrated Farnsworth": "//i.imgur.com/U3SElKP.jpg", + "Fuck Me, Right?": "//i.imgur.com/J9gfxsx.jpg", + "Gangster Baby": "//i.imgur.com/C3XhI56.jpg", + "Good Girl Gina": "//i.imgur.com/qK6lYr2.jpg", + "Good Guy Greg": "//i.imgur.com/UXMPoKN.jpg", + "Grandma Finds The Internet": "//i.imgur.com/xPfGYqu.jpg", + "Grinds My Gears": "//i.imgur.com/t4JqU1j.jpg", + "Grumpy Cat (Tard)": "//i.imgur.com/dU5CDxN.jpg", + "High Expectations Asian Father": "//i.imgur.com/7QeB9LI.jpg", + "Hipster Barista": "//i.imgur.com/AbWxdy2.jpg", + "Horrifying House Guest": "//i.imgur.com/DxmoFp1.jpg", + "I Dare You Samuel Jackson": "//i.imgur.com/UQtpdqj.jpg", + "I Should Buy A Boat": "//i.imgur.com/XqlqPxn.jpg", + "I Too Like To Live Dangerously": "//i.imgur.com/qF70EL9.jpg", + "Idiot Nerd Girl": "//i.imgur.com/8hYPYwd.jpg", + "Insanity Wolf": "//i.imgur.com/GOOdg3k.jpg", + "Joker Mind Loss": "//i.imgur.com/qQIRaOD.jpg", + "Joseph Ducreux": "//i.imgur.com/QL7TyR9.jpg", + "Lame Joke Eel": "//i.imgur.com/oQXw3jF.jpg", + "Lame Pun Raccoon": "//i.imgur.com/nvALRK3.jpg", + "Lazy College Senior": "//i.imgur.com/PpkVfzz.jpg", + "Mad Karma": "//i.imgur.com/G0QMPum.jpg", + "Masturbating Spidey": "//i.imgur.com/dZ7AB4c.jpg", + "Matrix Morpheus": "//i.imgur.com/8Yrw6cZ.jpg", + "Mayonnaise Patrick": "//i.imgur.com/5jE0Y7f.jpg", + "Musically Oblivious 8th Grader": "//i.imgur.com/l5YHN5D.jpg", + "Not Sure Fry": "//i.imgur.com/7rFgBB1.jpg", + "Oblivious Suburban Mom": "//i.imgur.com/Y7o7UJs.jpg", + "One Does Not Simply": "//i.imgur.com/7LrwR1Y.jpg", + "Overly Attached Girlfriend": "//i.imgur.com/5blLJLR.jpg", + "Overly Manly Man": "//i.imgur.com/dOSn9Na.jpg", + "Paranoid Parrot": "//i.imgur.com/KooYHdg.jpg", + "Pedobear": "//i.imgur.com/c6JZKRW.jpg", + "Pepperidge Farm Remembers": "//i.imgur.com/uFde4v5.jpg", + "Philosoraptor": "//i.imgur.com/eERhI5h.jpg", + "Priority Peter": "//i.imgur.com/BBEFk0e.jpg", + "Rasta Science Teacher": "//i.imgur.com/Js6Ai5T.jpg", + "Redditor's Wife": "//i.imgur.com/d1XfJeD.jpg", + "Revenge Band Kid": "//i.imgur.com/dlvmaRI.jpg", + "Schrute Facts": "//i.imgur.com/UxcvPwT.jpg", + "Scumbag Brain": "//i.imgur.com/OZhhZdS.jpg", + "Scumbag Stacy": "//i.imgur.com/Qqz1axp.jpg", + "Scumbag Steve": "//i.imgur.com/Rfvoc0Y.jpg", + "Sexually Oblivious Rhino": "//i.imgur.com/RoaNuEC.jpg", + "Sheltering Suburban Mom": "//i.imgur.com/vMkSofv.jpg", + "Shut Up And Take My Money": "//i.imgur.com/uWe0rtQ.jpg", + "Skeptical Third World Kid": "//i.imgur.com/uwAusxV.jpg", + "Smug Spongebob": "//i.imgur.com/OTTRjrv.jpg", + "Socially Awesome Penguin": "//i.imgur.com/S6WgQW7.jpg", + "Success Kid": "//i.imgur.com/ZibijBz.jpg", + "Successful Black Man": "//i.imgur.com/ogIm0cy.jpg", + "Sudden Clarity Clarence": "//i.imgur.com/N3Xmfbe.jpg", + "Tech Impaired Duck": "//i.imgur.com/riz28ci.jpg", + "The Most Interesting Man In The World": "//i.imgur.com/MGv15MH.jpg", + "The Rent Is Too High": "//i.imgur.com/r5WLktQ.jpg", + "Tough Spongebob": "//i.imgur.com/2w0F1HX.jpg", + "Unhelpful Highschool Teacher": "//i.imgur.com/ohbGhuD.jpg", + "Vengeance Dad": "//i.imgur.com/0nUStsa.jpg", + "What Year Is It?": "//i.imgur.com/fj79hQS.jpg", + "X, X Everywhere": "//i.imgur.com/GGy94Gt.jpg", + "Yeah That'd Be Great": "//i.imgur.com/nz9M2pl.jpg", + "Yo Dawg Xzibit": "//i.imgur.com/XOyGqF2.jpg", + "You're Bad And You Should Feel Bad": "//i.imgur.com/YsabGnQ.jpg", + "You're Gonna Have A Bad Time": "//i.imgur.com/2tNR7P7.jpg" + }; + + /** + * Since the console.log doesn't respond to the `display` style, + * setting a width and height has no effect. In fact, the only styles + * I've found it responds to is font-size, background-image and color. + * To combat the image repeating, we have to get a create a font bounding + * box so to speak with the unicode box characters. EDIT: See Readme.md + * + * @param {int} width The height of the box + * @param {int} height The width of the box + * @return {object} {string, css} + */ + function getBox(width, height) { + return { + string: "+", + style: "font-size: 1px; padding: " + Math.floor(height / 2) + "px " + Math.floor(width / 2) + "px; line-height: " + height + "px;" + } + } + + /** + * Draw's meme text on a context. + * + * @param {CanvasRenderingContext2D} ctx The canvas context + * @param {string} type "upper"|"lower" + * @param {string} text The text to draw + * @param {int} width The width of the image + * @param {int} y The y value to draw at + * @return {null} + */ + function drawMemeText(ctx, type, text, width, y) { + text = text.toUpperCase(); + //Determine the font size + if (text.length < 24) { + var val = Math.max(0, text.length - 12), + size = 70 + (val * -3); + + drawText(ctx, size, text, width / 2, y); + } else if (text.length < 29) { + drawText(ctx, 40, text, width / 2, y); + } else { + var strs = wrap(text, 27); + strs.forEach(function (str, i) { + drawText(ctx, 40, str, width / 2, (type == "lower") ? (y - ((strs.length - 1) * 40)) + (i * 40) : y + (i * 40)); + }); + } + } + + /** + * Draws text in impact font with stroke on context + * + * @param {CanvasRenderingContext2D} ctx The canvas context + * @param {int} size Font size + * @param {string} text The string to write + * @param {int} x X Position + * @param {int} y Y position + * @return {null} + */ + function drawText(ctx, size, text, x, y) { + //Set the text styles + ctx.font = "bold " + size + "px Impact"; + ctx.fillStyle = "#fff"; + ctx.textAlign = "center"; + ctx.textBaseline = "middle"; + ctx.lineWidth = 7; + ctx.strokeStyle = "#000"; + ctx.strokeText(text, x, y); + ctx.fillText(text, x, y); + } + + /** + * Wrap a line of text at an index + * + * @param {string} text The text + * @param {int} num The index to wrap at + * @return {array} Array of text + */ + function wrap(text, num) { + var output = [], + split = text.split(" "); + + var str = []; + for (var i = 0, cache = split.length; i < cache; i++) { + if ((str + split[i]).length < num) str.push(split[i]) + else { + output.push(str.join(" ")); + str.length = 0; + str.push(split[i]); + } + } + + //Push the final line + output.push(str.join(" ")); + + return output; + } + + /** + * Add a meme to the console! + * + * @param {string} upper The upper text + * @param {string} lower The lower text + * @param {string} image The meme type (see `console.meme` for all supported) or image url (Make sure it's CORS enabled) + * @param {int} width The width of the meme + * @param {int} height The height of the meme + * @return {null} + */ + console.meme = function (upper, lower, image, width, height) { + if (!upper) console.error("Yo, you forgot the text for the upper part of the meme. The bit at the top. Yeah, that bit."); + if (!lower) console.error("You forgot the text for the bottom of the meme, stupid."); + if (!image) console.error("Dude, you forgot the meme type or url for the background image (CORS enabled, *hint* imgur *hint*). To see a list of supported memes, hit `console.meme()`"); + if (!upper && !lower && !image) return console.log("> " + Object.keys(memes).join("\n> ")); + + var canvas = document.createElement("canvas"), + ctx = canvas.getContext("2d"), + width = width || 500, + height = height || 500, + //I tweaked it at these dimensions, + //So everything scales from here + _w = 500, _h = 500; + + var img = new Image(); + img.setAttribute('crossOrigin', 'anonymous'); + img.onload = function () { + canvas.width = width; + canvas.height = height; + + var text = upper.toUpperCase(); + + ctx.scale(width / 500, height / 500); + + //Draw the background + ctx.drawImage(this, 0, 0, _w, _h); + + drawMemeText(ctx, "upper", upper, _w, 50); //upper + drawMemeText(ctx, "lower", lower, _w, _h - 50); //upper + + console.image(canvas.toDataURL()); + }; + + if (memes[image]) var url = memes[image]; + else var url = image; + + img.src = url; //"http://www.corsproxy.com/" + url.replace(/https?:\/\//, ""); + }; + + /** + * Display an image in the console. + * @param {string} url The url of the image. + * @param {int} scale Scale factor on the image + * @return {null} + */ + console.image = function (url, scale) { + scale = scale || 1; + var img = new Image(); + + img.onload = function () { + var dim = getBox(this.width * scale, this.height * scale); + console.log("%c" + dim.string, dim.style + "background: url(" + url + "); background-size: " + (this.width * scale) + "px " + (this.height * scale) + "px; color: transparent;"); + }; + + img.src = url; + }; })(console); \ No newline at end of file diff --git a/main/app/sprinkles/core/assets/SiteAssets/js/console.js b/main/app/sprinkles/core/assets/SiteAssets/js/console.js index c36f7e6..85ea689 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/js/console.js +++ b/main/app/sprinkles/core/assets/SiteAssets/js/console.js @@ -1,75 +1,75 @@ -/** - * File for some things logged in console // TODO: Create Error/Success logger functions so we don't need to write the whole log things several times - */ - -console.log("%s%c%s%c%s%c%s%c%s%c%s%c", - " ____ _____ _ __ __ \n" + - "| __ ) | ____| / \\ | \\/ |\n" + - "| _ \\ | _| / _ \\ | |\\/| |\n" + - "| |_) || |___ / ___ \\ | | | |\n" + - "|____/ |_____|/_/ \\_\\|_| |_|\n", - "whitespace: pre;", - "Hello, world! Thanks for checking our code.\nAs this project is completely open source it would be an better option to look here:\n", - "color: blue;", "https://github.com/marvinborner/BEAM-Messenger\n\n", - "", "...or even clone the entire repo with:\n", - "border-radius: 100px; padding: 2px; background-color: black; color: white;", "git clone https://github.com/marvinborner/BEAM-Messenger.git\n", - "", "\nWe are also thankful for every contributor we have, so if you have any idea, fix or anything else - feel free to create a pull request.", - "font-family: monospace;"); - -function playGame() { - var a, b, d, e, f, g, h, k, l, m, n, p, q, r; - h = "<0>-----------------------<0>--------------"; - f = [0, 20]; - p = []; - n = !1; - m = d = 0; - q = 1; - e = function (c) { - var s; - s = p[c[0]].substr(c[1] + 1, 1); - p[c[0]] = p[c[0]].substr(0, c[1]) + "X" + p[c[0]].substr(c[1] + 1); - return s - }; - b = function (c) { - return /[<0>]/.test(c) - }; - k = function () { - n = !0; - return setTimeout(function () { - alert("Oops, you got squashed.\n\nTry again"); - n = !1; - f = [0, 20]; - return q++ - }, 60) - }; - r = function () { - n = !0; - setTimeout(function () { - alert("CONGRATULATIONS! You made it! Nice.\n\nIt took you " + q + " tries, " + m + " moves, and " + d + " draw cycles"); - n = !1; - m = d = 0; - q = 1; - return f = [0, 20] - }, 60) - }; - g = null; - l = { - 38: function () { - if (f[0] < p.length - 1) return f[0]++ - }, 40: function () { - if (0 < f[0]) return f[0]-- - }, 37: function () { - if (0 < f[1]) return f[1]-- - }, 39: function () { - if (f[1] < h.length - 1) return f[1]++ - } - }; - document.onkeydown = function (c) { - g = c.keyCode; - return m++ - }; - a = setInterval(function () { - var c; - if (!n) if (d++, l[g] && (l[g](), g = null), 27 === g) clearInterval(a); else if (h = h.substr(-1) + h.substr(0, h.length - 1), p = ["ooooooooooooooooooooooooooooooooooooooooooo", h, h.split("").reverse().join(""), h.substr(-11) + h.substr(0, h.length - 11), h.split("").reverse().join("").substr(-11) + h.split("").reverse().join("").substr(0, h.length - 11), "ooooooooooooooooooooooooooooooooooooooooooo"], c = e(f), console.clear(), console.log("\n\nYou found a secret game!\nTake a break from coding and play it! :)\n\nYour Goal: Use the arrow keys to move the 'X' across the street and avoid the cars - just ignore the rest of the screen.\nPress 'Esc' to stop the game.\n\n(Note, if your cursor is in the console you'll need to click on the page outside the console so the arrow keys will work)\n\n\n"), console.log(p[5]), console.log(p[4]), console.log(p[3]), console.log(p[2]), console.log(p[1]), console.log(p[0]), console.log("\n\nMade by @jschomay"), f[0] >= p.length - 1 && r(), b(c)) return k() - }, 60); +/** + * File for some things logged in console // TODO: Create Error/Success logger functions so we don't need to write the whole log things several times + */ + +console.log("%s%c%s%c%s%c%s%c%s%c%s%c", + " ____ _____ _ __ __ \n" + + "| __ ) | ____| / \\ | \\/ |\n" + + "| _ \\ | _| / _ \\ | |\\/| |\n" + + "| |_) || |___ / ___ \\ | | | |\n" + + "|____/ |_____|/_/ \\_\\|_| |_|\n", + "whitespace: pre;", + "Hello, world! Thanks for checking our code.\nAs this project is completely open source it would be an better option to look here:\n", + "color: blue;", "https://github.com/marvinborner/BEAM-Messenger\n\n", + "", "...or even clone the entire repo with:\n", + "border-radius: 100px; padding: 2px; background-color: black; color: white;", "git clone https://github.com/marvinborner/BEAM-Messenger.git\n", + "", "\nWe are also thankful for every contributor we have, so if you have any idea, fix or anything else - feel free to create a pull request.", + "font-family: monospace;"); + +function playGame() { + var a, b, d, e, f, g, h, k, l, m, n, p, q, r; + h = "<0>-----------------------<0>--------------"; + f = [0, 20]; + p = []; + n = !1; + m = d = 0; + q = 1; + e = function (c) { + var s; + s = p[c[0]].substr(c[1] + 1, 1); + p[c[0]] = p[c[0]].substr(0, c[1]) + "X" + p[c[0]].substr(c[1] + 1); + return s + }; + b = function (c) { + return /[<0>]/.test(c) + }; + k = function () { + n = !0; + return setTimeout(function () { + alert("Oops, you got squashed.\n\nTry again"); + n = !1; + f = [0, 20]; + return q++ + }, 60) + }; + r = function () { + n = !0; + setTimeout(function () { + alert("CONGRATULATIONS! You made it! Nice.\n\nIt took you " + q + " tries, " + m + " moves, and " + d + " draw cycles"); + n = !1; + m = d = 0; + q = 1; + return f = [0, 20] + }, 60) + }; + g = null; + l = { + 38: function () { + if (f[0] < p.length - 1) return f[0]++ + }, 40: function () { + if (0 < f[0]) return f[0]-- + }, 37: function () { + if (0 < f[1]) return f[1]-- + }, 39: function () { + if (f[1] < h.length - 1) return f[1]++ + } + }; + document.onkeydown = function (c) { + g = c.keyCode; + return m++ + }; + a = setInterval(function () { + var c; + if (!n) if (d++, l[g] && (l[g](), g = null), 27 === g) clearInterval(a); else if (h = h.substr(-1) + h.substr(0, h.length - 1), p = ["ooooooooooooooooooooooooooooooooooooooooooo", h, h.split("").reverse().join(""), h.substr(-11) + h.substr(0, h.length - 11), h.split("").reverse().join("").substr(-11) + h.split("").reverse().join("").substr(0, h.length - 11), "ooooooooooooooooooooooooooooooooooooooooooo"], c = e(f), console.clear(), console.log("\n\nYou found a secret game!\nTake a break from coding and play it! :)\n\nYour Goal: Use the arrow keys to move the 'X' across the street and avoid the cars - just ignore the rest of the screen.\nPress 'Esc' to stop the game.\n\n(Note, if your cursor is in the console you'll need to click on the page outside the console so the arrow keys will work)\n\n\n"), console.log(p[5]), console.log(p[4]), console.log(p[3]), console.log(p[2]), console.log(p[1]), console.log(p[0]), console.log("\n\nMade by @jschomay"), f[0] >= p.length - 1 && r(), b(c)) return k() + }, 60); } \ No newline at end of file diff --git a/main/app/sprinkles/core/assets/SiteAssets/js/encryption.js b/main/app/sprinkles/core/assets/SiteAssets/js/encryption.js index 0b406e7..9185505 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/js/encryption.js +++ b/main/app/sprinkles/core/assets/SiteAssets/js/encryption.js @@ -1,19121 +1,19121 @@ -/*! OpenPGP.js v3.0.9 - 2018-04-30 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */ -!function (e) { - if ("object" == typeof exports && "undefined" != typeof module) module.exports = e(); else if ("function" == typeof define && define.amd) define([], e); else { - ("undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : this).openpgp = e() - } -}(function () { - return function e(t, r, n) { - function i(s, o) { - if (!r[s]) { - if (!t[s]) { - var u = "function" == typeof require && require; - if (!o && u) return u(s, !0); - if (a) return a(s, !0); - var f = new Error("Cannot find module '" + s + "'"); - throw f.code = "MODULE_NOT_FOUND", f - } - var c = r[s] = {exports: {}}; - t[s][0].call(c.exports, function (e) { - var r = t[s][1][e]; - return i(r || e) - }, c, c.exports, e, t, r, n) - } - return r[s].exports - } - - for (var a = "function" == typeof require && require, s = 0; s < n.length; s++) i(n[s]); - return i - }({ - 1: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}); - r.AES_asm = function () { - var e, t, r = !1; - - function n(r, n) { - var i = e[(t[r] + t[n]) % 255]; - return 0 !== r && 0 !== n || (i = 0), i - } - - var i, a, s, o; - - function u() { - function u(r) { - var n, i, a; - for (i = a = function (r) { - var n = e[255 - t[r]]; - return 0 === r && (n = 0), n - }(r), n = 0; n < 4; n++) a ^= i = 255 & (i << 1 | i >>> 7); - return a ^= 99 - } - - r || function () { - e = [], t = []; - var n, i, a = 1; - for (n = 0; n < 255; n++) e[n] = a, i = 128 & a, a <<= 1, a &= 255, 128 === i && (a ^= 27), a ^= e[n], t[e[n]] = n; - e[255] = e[0], t[0] = 0, r = !0 - }(), i = [], a = [], s = [[], [], [], []], o = [[], [], [], []]; - for (var f = 0; f < 256; f++) { - var c = u(f); - i[f] = c, a[c] = f, s[0][f] = n(2, c) << 24 | c << 16 | c << 8 | n(3, c), o[0][c] = n(14, f) << 24 | n(9, f) << 16 | n(13, f) << 8 | n(11, f); - for (var d = 1; d < 4; d++) s[d][f] = s[d - 1][f] >>> 8 | s[d - 1][f] << 24, o[d][c] = o[d - 1][c] >>> 8 | o[d - 1][c] << 24 - } - } - - var f = function (e, t) { - u(); - var r = new Uint32Array(t); - r.set(i, 512), r.set(a, 768); - for (var n = 0; n < 4; n++) r.set(s[n], 4096 + 1024 * n >> 2), r.set(o[n], 8192 + 1024 * n >> 2); - var f = function (e, t, r) { - "use asm"; - var n = 0, i = 0, a = 0, s = 0, o = 0, u = 0, f = 0, c = 0, d = 0, l = 0, h = 0, p = 0, y = 0, - b = 0, m = 0, g = 0, v = 0, _ = 0, w = 0, k = 0, A = 0; - var x = new e.Uint32Array(r), S = new e.Uint8Array(r); - - function E(e, t, r, o, u, f, c, d) { - e = e | 0; - t = t | 0; - r = r | 0; - o = o | 0; - u = u | 0; - f = f | 0; - c = c | 0; - d = d | 0; - var l = 0, h = 0, p = 0, y = 0, b = 0, m = 0, g = 0, v = 0; - l = r | 0x400, h = r | 0x800, p = r | 0xc00; - u = u ^ x[(e | 0) >> 2], f = f ^ x[(e | 4) >> 2], c = c ^ x[(e | 8) >> 2], d = d ^ x[(e | 12) >> 2]; - for (v = 16; (v | 0) <= o << 4; v = v + 16 | 0) { - y = x[(r | u >> 22 & 1020) >> 2] ^ x[(l | f >> 14 & 1020) >> 2] ^ x[(h | c >> 6 & 1020) >> 2] ^ x[(p | d << 2 & 1020) >> 2] ^ x[(e | v | 0) >> 2], b = x[(r | f >> 22 & 1020) >> 2] ^ x[(l | c >> 14 & 1020) >> 2] ^ x[(h | d >> 6 & 1020) >> 2] ^ x[(p | u << 2 & 1020) >> 2] ^ x[(e | v | 4) >> 2], m = x[(r | c >> 22 & 1020) >> 2] ^ x[(l | d >> 14 & 1020) >> 2] ^ x[(h | u >> 6 & 1020) >> 2] ^ x[(p | f << 2 & 1020) >> 2] ^ x[(e | v | 8) >> 2], g = x[(r | d >> 22 & 1020) >> 2] ^ x[(l | u >> 14 & 1020) >> 2] ^ x[(h | f >> 6 & 1020) >> 2] ^ x[(p | c << 2 & 1020) >> 2] ^ x[(e | v | 12) >> 2]; - u = y, f = b, c = m, d = g - } - n = x[(t | u >> 22 & 1020) >> 2] << 24 ^ x[(t | f >> 14 & 1020) >> 2] << 16 ^ x[(t | c >> 6 & 1020) >> 2] << 8 ^ x[(t | d << 2 & 1020) >> 2] ^ x[(e | v | 0) >> 2], i = x[(t | f >> 22 & 1020) >> 2] << 24 ^ x[(t | c >> 14 & 1020) >> 2] << 16 ^ x[(t | d >> 6 & 1020) >> 2] << 8 ^ x[(t | u << 2 & 1020) >> 2] ^ x[(e | v | 4) >> 2], a = x[(t | c >> 22 & 1020) >> 2] << 24 ^ x[(t | d >> 14 & 1020) >> 2] << 16 ^ x[(t | u >> 6 & 1020) >> 2] << 8 ^ x[(t | f << 2 & 1020) >> 2] ^ x[(e | v | 8) >> 2], s = x[(t | d >> 22 & 1020) >> 2] << 24 ^ x[(t | u >> 14 & 1020) >> 2] << 16 ^ x[(t | f >> 6 & 1020) >> 2] << 8 ^ x[(t | c << 2 & 1020) >> 2] ^ x[(e | v | 12) >> 2] - } - - function M(e, t, r, n) { - e = e | 0; - t = t | 0; - r = r | 0; - n = n | 0; - E(0x0000, 0x0800, 0x1000, A, e, t, r, n) - } - - function C(e, t, r, n) { - e = e | 0; - t = t | 0; - r = r | 0; - n = n | 0; - var a = 0; - E(0x0400, 0x0c00, 0x2000, A, e, n, r, t); - a = i, i = s, s = a - } - - function j(e, t, r, d) { - e = e | 0; - t = t | 0; - r = r | 0; - d = d | 0; - E(0x0000, 0x0800, 0x1000, A, o ^ e, u ^ t, f ^ r, c ^ d); - o = n, u = i, f = a, c = s - } - - function P(e, t, r, d) { - e = e | 0; - t = t | 0; - r = r | 0; - d = d | 0; - var l = 0; - E(0x0400, 0x0c00, 0x2000, A, e, d, r, t); - l = i, i = s, s = l; - n = n ^ o, i = i ^ u, a = a ^ f, s = s ^ c; - o = e, u = t, f = r, c = d - } - - function B(e, t, r, d) { - e = e | 0; - t = t | 0; - r = r | 0; - d = d | 0; - E(0x0000, 0x0800, 0x1000, A, o, u, f, c); - o = n = n ^ e, u = i = i ^ t, f = a = a ^ r, c = s = s ^ d - } - - function U(e, t, r, d) { - e = e | 0; - t = t | 0; - r = r | 0; - d = d | 0; - E(0x0000, 0x0800, 0x1000, A, o, u, f, c); - n = n ^ e, i = i ^ t, a = a ^ r, s = s ^ d; - o = e, u = t, f = r, c = d - } - - function K(e, t, r, d) { - e = e | 0; - t = t | 0; - r = r | 0; - d = d | 0; - E(0x0000, 0x0800, 0x1000, A, o, u, f, c); - o = n, u = i, f = a, c = s; - n = n ^ e, i = i ^ t, a = a ^ r, s = s ^ d - } - - function I(e, t, r, o) { - e = e | 0; - t = t | 0; - r = r | 0; - o = o | 0; - E(0x0000, 0x0800, 0x1000, A, d, l, h, p); - p = ~g & p | g & p + 1; - h = ~m & h | m & h + ((p | 0) == 0); - l = ~b & l | b & l + ((h | 0) == 0); - d = ~y & d | y & d + ((l | 0) == 0); - n = n ^ e; - i = i ^ t; - a = a ^ r; - s = s ^ o - } - - function T(e, t, r, n) { - e = e | 0; - t = t | 0; - r = r | 0; - n = n | 0; - var i = 0, a = 0, s = 0, d = 0, l = 0, h = 0, p = 0, y = 0, b = 0, m = 0; - e = e ^ o, t = t ^ u, r = r ^ f, n = n ^ c; - i = v | 0, a = _ | 0, s = w | 0, d = k | 0; - for (; (b | 0) < 128; b = b + 1 | 0) { - if (i >>> 31) { - l = l ^ e, h = h ^ t, p = p ^ r, y = y ^ n - } - i = i << 1 | a >>> 31, a = a << 1 | s >>> 31, s = s << 1 | d >>> 31, d = d << 1; - m = n & 1; - n = n >>> 1 | r << 31, r = r >>> 1 | t << 31, t = t >>> 1 | e << 31, e = e >>> 1; - if (m) e = e ^ 0xe1000000 - } - o = l, u = h, f = p, c = y - } - - function O(e) { - e = e | 0; - A = e - } - - function R(e, t, r, o) { - e = e | 0; - t = t | 0; - r = r | 0; - o = o | 0; - n = e, i = t, a = r, s = o - } - - function D(e, t, r, n) { - e = e | 0; - t = t | 0; - r = r | 0; - n = n | 0; - o = e, u = t, f = r, c = n - } - - function z(e, t, r, n) { - e = e | 0; - t = t | 0; - r = r | 0; - n = n | 0; - d = e, l = t, h = r, p = n - } - - function L(e, t, r, n) { - e = e | 0; - t = t | 0; - r = r | 0; - n = n | 0; - y = e, b = t, m = r, g = n - } - - function F(e, t, r, n) { - e = e | 0; - t = t | 0; - r = r | 0; - n = n | 0; - p = ~g & p | g & n, h = ~m & h | m & r, l = ~b & l | b & t, d = ~y & d | y & e - } - - function N(e) { - e = e | 0; - if (e & 15) return -1; - S[e | 0] = n >>> 24, S[e | 1] = n >>> 16 & 255, S[e | 2] = n >>> 8 & 255, S[e | 3] = n & 255, S[e | 4] = i >>> 24, S[e | 5] = i >>> 16 & 255, S[e | 6] = i >>> 8 & 255, S[e | 7] = i & 255, S[e | 8] = a >>> 24, S[e | 9] = a >>> 16 & 255, S[e | 10] = a >>> 8 & 255, S[e | 11] = a & 255, S[e | 12] = s >>> 24, S[e | 13] = s >>> 16 & 255, S[e | 14] = s >>> 8 & 255, S[e | 15] = s & 255; - return 16 - } - - function q(e) { - e = e | 0; - if (e & 15) return -1; - S[e | 0] = o >>> 24, S[e | 1] = o >>> 16 & 255, S[e | 2] = o >>> 8 & 255, S[e | 3] = o & 255, S[e | 4] = u >>> 24, S[e | 5] = u >>> 16 & 255, S[e | 6] = u >>> 8 & 255, S[e | 7] = u & 255, S[e | 8] = f >>> 24, S[e | 9] = f >>> 16 & 255, S[e | 10] = f >>> 8 & 255, S[e | 11] = f & 255, S[e | 12] = c >>> 24, S[e | 13] = c >>> 16 & 255, S[e | 14] = c >>> 8 & 255, S[e | 15] = c & 255; - return 16 - } - - function G() { - M(0, 0, 0, 0); - v = n, _ = i, w = a, k = s - } - - function H(e, t, r) { - e = e | 0; - t = t | 0; - r = r | 0; - var o = 0; - if (t & 15) return -1; - while ((r | 0) >= 16) { - V[e & 7](S[t | 0] << 24 | S[t | 1] << 16 | S[t | 2] << 8 | S[t | 3], S[t | 4] << 24 | S[t | 5] << 16 | S[t | 6] << 8 | S[t | 7], S[t | 8] << 24 | S[t | 9] << 16 | S[t | 10] << 8 | S[t | 11], S[t | 12] << 24 | S[t | 13] << 16 | S[t | 14] << 8 | S[t | 15]); - S[t | 0] = n >>> 24, S[t | 1] = n >>> 16 & 255, S[t | 2] = n >>> 8 & 255, S[t | 3] = n & 255, S[t | 4] = i >>> 24, S[t | 5] = i >>> 16 & 255, S[t | 6] = i >>> 8 & 255, S[t | 7] = i & 255, S[t | 8] = a >>> 24, S[t | 9] = a >>> 16 & 255, S[t | 10] = a >>> 8 & 255, S[t | 11] = a & 255, S[t | 12] = s >>> 24, S[t | 13] = s >>> 16 & 255, S[t | 14] = s >>> 8 & 255, S[t | 15] = s & 255; - o = o + 16 | 0, t = t + 16 | 0, r = r - 16 | 0 - } - return o | 0 - } - - function Z(e, t, r) { - e = e | 0; - t = t | 0; - r = r | 0; - var n = 0; - if (t & 15) return -1; - while ((r | 0) >= 16) { - W[e & 1](S[t | 0] << 24 | S[t | 1] << 16 | S[t | 2] << 8 | S[t | 3], S[t | 4] << 24 | S[t | 5] << 16 | S[t | 6] << 8 | S[t | 7], S[t | 8] << 24 | S[t | 9] << 16 | S[t | 10] << 8 | S[t | 11], S[t | 12] << 24 | S[t | 13] << 16 | S[t | 14] << 8 | S[t | 15]); - n = n + 16 | 0, t = t + 16 | 0, r = r - 16 | 0 - } - return n | 0 - } - - var V = [M, C, j, P, B, U, K, I]; - var W = [j, T]; - return { - set_rounds: O, - set_state: R, - set_iv: D, - set_nonce: z, - set_mask: L, - set_counter: F, - get_state: N, - get_iv: q, - gcm_init: G, - cipher: H, - mac: Z - } - }({Uint8Array: Uint8Array, Uint32Array: Uint32Array}, e, t); - return f.set_key = function (e, t, n, a, s, u, c, d, l) { - var h = r.subarray(0, 60), p = r.subarray(256, 316); - h.set([t, n, a, s, u, c, d, l]); - for (var y = e, b = 1; y < 4 * e + 28; y++) { - var m = h[y - 1]; - (y % e == 0 || 8 === e && y % e == 4) && (m = i[m >>> 24] << 24 ^ i[m >>> 16 & 255] << 16 ^ i[m >>> 8 & 255] << 8 ^ i[255 & m]), y % e == 0 && (m = m << 8 ^ m >>> 24 ^ b << 24, b = b << 1 ^ (128 & b ? 27 : 0)), h[y] = h[y - e] ^ m - } - for (var g = 0; g < y; g += 4) for (var v = 0; v < 4; v++) m = h[y - (4 + g) + (4 - v) % 4], p[g + v] = g < 4 || g >= y - 4 ? m : o[0][i[m >>> 24]] ^ o[1][i[m >>> 16 & 255]] ^ o[2][i[m >>> 8 & 255]] ^ o[3][i[255 & m]]; - f.set_rounds(e + 5) - }, f - }; - return f.ENC = {ECB: 0, CBC: 2, CFB: 4, OFB: 6, CTR: 7}, f.DEC = { - ECB: 1, - CBC: 3, - CFB: 5, - OFB: 6, - CTR: 7 - }, f.MAC = {CBC: 0, GCM: 1}, f.HEAP_DATA = 16384, f - }() - }, {}], - 2: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r.AES = void 0; - var n = u(e("babel-runtime/helpers/classCallCheck")), i = u(e("babel-runtime/helpers/createClass")), - a = e("./aes.asm"), s = e("../utils"), o = e("../errors"); - - function u(e) { - return e && e.__esModule ? e : {default: e} - } - - r.AES = function () { - function e(t, r, i, o, u) { - (0, n.default)(this, e), this.nonce = null, this.counter = 0, this.counterSize = 0, this.heap = (0, s._heap_init)(Uint8Array, o).subarray(a.AES_asm.HEAP_DATA), this.asm = u || (0, a.AES_asm)(null, this.heap.buffer), this.mode = null, this.key = null, this.AES_reset(t, r, i) - } - - return (0, i.default)(e, [{ - key: "AES_set_key", value: function (e) { - if (void 0 !== e) { - if (!(0, s.is_bytes)(e)) throw new TypeError("unexpected key type"); - var t = e.length; - if (16 !== t && 24 !== t && 32 !== t) throw new o.IllegalArgumentError("illegal key size"); - var r = new DataView(e.buffer, e.byteOffset, e.byteLength); - this.asm.set_key(t >> 2, r.getUint32(0), r.getUint32(4), r.getUint32(8), r.getUint32(12), t > 16 ? r.getUint32(16) : 0, t > 16 ? r.getUint32(20) : 0, t > 24 ? r.getUint32(24) : 0, t > 24 ? r.getUint32(28) : 0), this.key = e - } else if (!this.key) throw new Error("key is required") - } - }, { - key: "AES_CTR_set_options", value: function (e, t, r) { - if (void 0 !== r) { - if (r < 8 || r > 48) throw new o.IllegalArgumentError("illegal counter size"); - this.counterSize = r; - var n = Math.pow(2, r) - 1; - this.asm.set_mask(0, 0, n / 4294967296 | 0, 0 | n) - } else this.counterSize = r = 48, this.asm.set_mask(0, 0, 65535, 4294967295); - if (void 0 === e) throw new Error("nonce is required"); - if (!(0, s.is_bytes)(e)) throw new TypeError("unexpected nonce type"); - var i = e.length; - if (!i || i > 16) throw new o.IllegalArgumentError("illegal nonce size"); - this.nonce = e; - var a = new DataView(new ArrayBuffer(16)); - if (new Uint8Array(a.buffer).set(e), this.asm.set_nonce(a.getUint32(0), a.getUint32(4), a.getUint32(8), a.getUint32(12)), void 0 !== t) { - if (!(0, s.is_number)(t)) throw new TypeError("unexpected counter type"); - if (t < 0 || t >= Math.pow(2, r)) throw new o.IllegalArgumentError("illegal counter value"); - this.counter = t, this.asm.set_counter(0, 0, t / 4294967296 | 0, 0 | t) - } else this.counter = 0 - } - }, { - key: "AES_set_iv", value: function (e) { - if (void 0 !== e) { - if (!(0, s.is_bytes)(e)) throw new TypeError("unexpected iv type"); - if (16 !== e.length) throw new o.IllegalArgumentError("illegal iv size"); - var t = new DataView(e.buffer, e.byteOffset, e.byteLength); - this.iv = e, this.asm.set_iv(t.getUint32(0), t.getUint32(4), t.getUint32(8), t.getUint32(12)) - } else this.iv = null, this.asm.set_iv(0, 0, 0, 0) - } - }, { - key: "AES_set_padding", value: function (e) { - this.padding = void 0 === e || !!e - } - }, { - key: "AES_reset", value: function (e, t, r) { - return this.result = null, this.pos = 0, this.len = 0, this.AES_set_key(e), this.AES_set_iv(t), this.AES_set_padding(r), this - } - }, { - key: "AES_Encrypt_process", value: function (e) { - if (!(0, s.is_bytes)(e)) throw new TypeError("data isn't of expected type"); - for (var t = this.asm, r = this.heap, n = a.AES_asm.ENC[this.mode], i = a.AES_asm.HEAP_DATA, o = this.pos, u = this.len, f = 0, c = e.length || 0, d = 0, l = 0, h = new Uint8Array(u + c & -16); c > 0;) u += l = (0, s._heap_write)(r, o + u, e, f, c), f += l, c -= l, (l = t.cipher(n, i + o, u)) && h.set(r.subarray(o, o + l), d), d += l, l < u ? (o += l, u -= l) : (o = 0, u = 0); - return this.result = h, this.pos = o, this.len = u, this - } - }, { - key: "AES_Encrypt_finish", value: function (e) { - var t = null, r = 0; - void 0 !== e && (r = (t = this.AES_Encrypt_process(e).result).length); - var n = this.asm, i = this.heap, s = a.AES_asm.ENC[this.mode], u = a.AES_asm.HEAP_DATA, - f = this.pos, c = this.len, d = 16 - c % 16, l = c; - if (this.hasOwnProperty("padding")) { - if (this.padding) { - for (var h = 0; h < d; ++h) i[f + c + h] = d; - l = c += d - } else if (c % 16) throw new o.IllegalArgumentError("data length must be a multiple of the block size") - } else c += d; - var p = new Uint8Array(r + l); - return r && p.set(t), c && n.cipher(s, u + f, c), l && p.set(i.subarray(f, f + l), r), this.result = p, this.pos = 0, this.len = 0, this - } - }, { - key: "AES_Decrypt_process", value: function (e) { - if (!(0, s.is_bytes)(e)) throw new TypeError("data isn't of expected type"); - var t = this.asm, r = this.heap, n = a.AES_asm.DEC[this.mode], i = a.AES_asm.HEAP_DATA, - o = this.pos, u = this.len, f = 0, c = e.length || 0, d = 0, l = u + c & -16, h = 0, p = 0; - this.padding && (l -= h = u + c - l || 16); - for (var y = new Uint8Array(l); c > 0;) u += p = (0, s._heap_write)(r, o + u, e, f, c), f += p, c -= p, (p = t.cipher(n, i + o, u - (c ? 0 : h))) && y.set(r.subarray(o, o + p), d), d += p, p < u ? (o += p, u -= p) : (o = 0, u = 0); - return this.result = y, this.pos = o, this.len = u, this - } - }, { - key: "AES_Decrypt_finish", value: function (e) { - var t = null, r = 0; - void 0 !== e && (r = (t = this.AES_Decrypt_process(e).result).length); - var n = this.asm, i = this.heap, s = a.AES_asm.DEC[this.mode], u = a.AES_asm.HEAP_DATA, - f = this.pos, c = this.len, d = c; - if (c > 0) { - if (c % 16) { - if (this.hasOwnProperty("padding")) throw new o.IllegalArgumentError("data length must be a multiple of the block size"); - c += 16 - c % 16 - } - if (n.cipher(s, u + f, c), this.hasOwnProperty("padding") && this.padding) { - var l = i[f + d - 1]; - if (l < 1 || l > 16 || l > d) throw new o.SecurityError("bad padding"); - for (var h = 0, p = l; p > 1; p--) h |= l ^ i[f + d - p]; - if (h) throw new o.SecurityError("bad padding"); - d -= l - } - } - var y = new Uint8Array(r + d); - return r > 0 && y.set(t), d > 0 && y.set(i.subarray(f, f + d), r), this.result = y, this.pos = 0, this.len = 0, this - } - }]), e - }() - }, { - "../errors": 13, - "../utils": 18, - "./aes.asm": 1, - "babel-runtime/helpers/classCallCheck": 32, - "babel-runtime/helpers/createClass": 33 - }], - 3: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r.AES_CBC_Decrypt = r.AES_CBC_Encrypt = r.AES_CBC = void 0; - var n = f(e("babel-runtime/core-js/object/get-prototype-of")), - i = f(e("babel-runtime/helpers/classCallCheck")), a = f(e("babel-runtime/helpers/createClass")), - s = f(e("babel-runtime/helpers/possibleConstructorReturn")), o = f(e("babel-runtime/helpers/inherits")), - u = e("../aes"); - - function f(e) { - return e && e.__esModule ? e : {default: e} - } - - var c = r.AES_CBC = function (e) { - function t(e) { - var r = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : null, - a = !(arguments.length > 2 && void 0 !== arguments[2]) || arguments[2], o = arguments[3], - u = arguments[4]; - (0, i.default)(this, t); - var f = (0, s.default)(this, (t.__proto__ || (0, n.default)(t)).call(this, e, r, a, o, u)); - return f.mode = "CBC", f.BLOCK_SIZE = 16, f - } - - return (0, o.default)(t, e), (0, a.default)(t, [{ - key: "encrypt", value: function (e) { - return this.AES_Encrypt_finish(e) - } - }, { - key: "decrypt", value: function (e) { - return this.AES_Decrypt_finish(e) - } - }]), t - }(u.AES); - r.AES_CBC_Encrypt = function (e) { - function t(e, r, a, o, u) { - return (0, i.default)(this, t), (0, s.default)(this, (t.__proto__ || (0, n.default)(t)).call(this, e, r, a, o, u)) - } - - return (0, o.default)(t, e), (0, a.default)(t, [{ - key: "reset", value: function (e) { - return this.AES_reset(e, null, !0) - } - }, { - key: "process", value: function (e) { - return this.AES_Encrypt_process(e) - } - }, { - key: "finish", value: function (e) { - return this.AES_Encrypt_finish(e) - } - }]), t - }(c), r.AES_CBC_Decrypt = function (e) { - function t(e, r, a, o, u) { - return (0, i.default)(this, t), (0, s.default)(this, (t.__proto__ || (0, n.default)(t)).call(this, e, r, a, o, u)) - } - - return (0, o.default)(t, e), (0, a.default)(t, [{ - key: "reset", value: function (e) { - return this.AES_reset(e, null, !0) - } - }, { - key: "process", value: function (e) { - return this.AES_Decrypt_process(e) - } - }, { - key: "finish", value: function (e) { - return this.AES_Decrypt_finish(e) - } - }]), t - }(c) - }, { - "../aes": 2, - "babel-runtime/core-js/object/get-prototype-of": 26, - "babel-runtime/helpers/classCallCheck": 32, - "babel-runtime/helpers/createClass": 33, - "babel-runtime/helpers/inherits": 34, - "babel-runtime/helpers/possibleConstructorReturn": 35 - }], - 4: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r.AES_CBC_Decrypt = r.AES_CBC_Encrypt = r.AES_CBC = void 0; - var n = e("../exports"), i = e("./cbc"); - i.AES_CBC.encrypt = function (e, t, r, a) { - if (void 0 === e) throw new SyntaxError("data required"); - if (void 0 === t) throw new SyntaxError("key required"); - return new i.AES_CBC(t, a, r, n._AES_heap_instance, n._AES_asm_instance).encrypt(e).result - }, i.AES_CBC.decrypt = function (e, t, r, a) { - if (void 0 === e) throw new SyntaxError("data required"); - if (void 0 === t) throw new SyntaxError("key required"); - return new i.AES_CBC(t, a, r, n._AES_heap_instance, n._AES_asm_instance).decrypt(e).result - }, r.AES_CBC = i.AES_CBC, r.AES_CBC_Encrypt = i.AES_CBC_Encrypt, r.AES_CBC_Decrypt = i.AES_CBC_Decrypt - }, {"../exports": 10, "./cbc": 3}], - 5: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r.AES_CFB_Decrypt = r.AES_CFB_Encrypt = r.AES_CFB = void 0; - var n = f(e("babel-runtime/core-js/object/get-prototype-of")), - i = f(e("babel-runtime/helpers/classCallCheck")), a = f(e("babel-runtime/helpers/createClass")), - s = f(e("babel-runtime/helpers/possibleConstructorReturn")), o = f(e("babel-runtime/helpers/inherits")), - u = e("../aes"); - - function f(e) { - return e && e.__esModule ? e : {default: e} - } - - var c = r.AES_CFB = function (e) { - function t(e, r, a, o) { - (0, i.default)(this, t); - var u = (0, s.default)(this, (t.__proto__ || (0, n.default)(t)).call(this, e, r, !0, a, o)); - return delete u.padding, u.mode = "CFB", u.BLOCK_SIZE = 16, u - } - - return (0, o.default)(t, e), (0, a.default)(t, [{ - key: "encrypt", value: function (e) { - return this.AES_Encrypt_finish(e) - } - }, { - key: "decrypt", value: function (e) { - return this.AES_Decrypt_finish(e) - } - }]), t - }(u.AES); - r.AES_CFB_Encrypt = function (e) { - function t(e, r, a, o) { - return (0, i.default)(this, t), (0, s.default)(this, (t.__proto__ || (0, n.default)(t)).call(this, e, r, a, o)) - } - - return (0, o.default)(t, e), (0, a.default)(t, [{ - key: "reset", value: function (e, t, r) { - return this.AES_reset(e, t, r) - } - }, { - key: "process", value: function (e) { - return this.AES_Encrypt_process(e) - } - }, { - key: "finish", value: function (e) { - return this.AES_Encrypt_finish(e) - } - }]), t - }(c), r.AES_CFB_Decrypt = function (e) { - function t(e, r, a, o) { - return (0, i.default)(this, t), (0, s.default)(this, (t.__proto__ || (0, n.default)(t)).call(this, e, r, a, o)) - } - - return (0, o.default)(t, e), (0, a.default)(t, [{ - key: "reset", value: function (e, t, r) { - return this.AES_reset(e, t, r) - } - }, { - key: "process", value: function (e) { - return this.AES_Decrypt_process(e) - } - }, { - key: "finish", value: function (e) { - return this.AES_Decrypt_finish(e) - } - }]), t - }(c) - }, { - "../aes": 2, - "babel-runtime/core-js/object/get-prototype-of": 26, - "babel-runtime/helpers/classCallCheck": 32, - "babel-runtime/helpers/createClass": 33, - "babel-runtime/helpers/inherits": 34, - "babel-runtime/helpers/possibleConstructorReturn": 35 - }], - 6: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r.AES_CFB_Decrypt = r.AES_CFB_Encrypt = r.AES_CFB = void 0; - var n = e("../exports"), i = e("./cfb"); - i.AES_CFB.encrypt = function (e, t, r) { - if (void 0 === e) throw new SyntaxError("data required"); - if (void 0 === t) throw new SyntaxError("key required"); - return new i.AES_CFB(t, r, n._AES_heap_instance, n._AES_asm_instance).encrypt(e).result - }, i.AES_CFB.decrypt = function (e, t, r) { - if (void 0 === e) throw new SyntaxError("data required"); - if (void 0 === t) throw new SyntaxError("key required"); - return new i.AES_CFB(t, r, n._AES_heap_instance, n._AES_asm_instance).decrypt(e).result - }, r.AES_CFB = i.AES_CFB, r.AES_CFB_Encrypt = i.AES_CFB_Encrypt, r.AES_CFB_Decrypt = i.AES_CFB_Decrypt - }, {"../exports": 10, "./cfb": 5}], - 7: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r.AES_CTR_Crypt = r.AES_CTR = void 0; - var n = f(e("babel-runtime/core-js/object/get-prototype-of")), - i = f(e("babel-runtime/helpers/classCallCheck")), a = f(e("babel-runtime/helpers/createClass")), - s = f(e("babel-runtime/helpers/possibleConstructorReturn")), o = f(e("babel-runtime/helpers/inherits")), - u = e("../aes"); - - function f(e) { - return e && e.__esModule ? e : {default: e} - } - - var c = r.AES_CTR = function (e) { - function t(e, r, a, o) { - (0, i.default)(this, t); - var u = (0, s.default)(this, (t.__proto__ || (0, n.default)(t)).call(this, e, void 0, void 0, a, o)); - return u.reset(e, r), u.AES_CTR_set_options(r), delete u.padding, u.mode = "CTR", u.BLOCK_SIZE = 16, u - } - - return (0, o.default)(t, e), (0, a.default)(t, [{ - key: "reset", value: function (e, t, r, n) { - return this.AES_reset(e, void 0, void 0), this.AES_CTR_set_options(t, r, n), this - } - }, { - key: "encrypt", value: function (e) { - return this.AES_Encrypt_finish(e) - } - }, { - key: "decrypt", value: function (e) { - return this.AES_Encrypt_finish(e) - } - }]), t - }(u.AES); - r.AES_CTR_Crypt = function (e) { - function t(e, r, a, o) { - (0, i.default)(this, t); - var u = (0, s.default)(this, (t.__proto__ || (0, n.default)(t)).call(this, e, r, a, o)); - return u.BLOCK_SIZE = 16, u - } - - return (0, o.default)(t, e), (0, a.default)(t, [{ - key: "reset", value: function (e, t, r, n) { - return this.AES_reset(e, void 0, void 0), this.AES_CTR_set_options(t, r, n), this - } - }, { - key: "process", value: function (e) { - return this.AES_Encrypt_process(e) - } - }, { - key: "finish", value: function (e) { - return this.AES_Encrypt_finish(e) - } - }]), t - }(c) - }, { - "../aes": 2, - "babel-runtime/core-js/object/get-prototype-of": 26, - "babel-runtime/helpers/classCallCheck": 32, - "babel-runtime/helpers/createClass": 33, - "babel-runtime/helpers/inherits": 34, - "babel-runtime/helpers/possibleConstructorReturn": 35 - }], - 8: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r.AES_CTR = void 0; - var n = e("../exports"), i = e("./ctr"); - - function a(e, t, r) { - if (void 0 === e) throw new SyntaxError("data required"); - if (void 0 === t) throw new SyntaxError("key required"); - if (void 0 === r) throw new SyntaxError("nonce required"); - return new i.AES_CTR(t, r, n._AES_heap_instance, n._AES_asm_instance).encrypt(e).result - } - - i.AES_CTR.encrypt = a, i.AES_CTR.decrypt = a, r.AES_CTR = i.AES_CTR - }, {"../exports": 10, "./ctr": 7}], - 9: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r.AES_ECB_Decrypt = r.AES_ECB_Encrypt = r.AES_ECB = void 0; - var n = f(e("babel-runtime/core-js/object/get-prototype-of")), - i = f(e("babel-runtime/helpers/classCallCheck")), a = f(e("babel-runtime/helpers/createClass")), - s = f(e("babel-runtime/helpers/possibleConstructorReturn")), o = f(e("babel-runtime/helpers/inherits")), - u = e("../aes"); - - function f(e) { - return e && e.__esModule ? e : {default: e} - } - - var c = r.AES_ECB = function (e) { - function t(e, r, a) { - (0, i.default)(this, t); - var o = (0, s.default)(this, (t.__proto__ || (0, n.default)(t)).call(this, e, void 0, !1, r, a)); - return o.mode = "ECB", o.BLOCK_SIZE = 16, o - } - - return (0, o.default)(t, e), (0, a.default)(t, [{ - key: "encrypt", value: function (e) { - return this.AES_Encrypt_finish(e) - } - }, { - key: "decrypt", value: function (e) { - return this.AES_Decrypt_finish(e) - } - }]), t - }(u.AES); - r.AES_ECB_Encrypt = function (e) { - function t(e, r, a) { - return (0, i.default)(this, t), (0, s.default)(this, (t.__proto__ || (0, n.default)(t)).call(this, e, r, a)) - } - - return (0, o.default)(t, e), (0, a.default)(t, [{ - key: "reset", value: function (e) { - return this.AES_reset(e, null, !0) - } - }, { - key: "process", value: function (e) { - return this.AES_Encrypt_process(e) - } - }, { - key: "finish", value: function (e) { - return this.AES_Encrypt_finish(e) - } - }]), t - }(c), r.AES_ECB_Decrypt = function (e) { - function t(e, r, a) { - return (0, i.default)(this, t), (0, s.default)(this, (t.__proto__ || (0, n.default)(t)).call(this, e, r, a)) - } - - return (0, o.default)(t, e), (0, a.default)(t, [{ - key: "reset", value: function (e) { - return this.AES_reset(e, null, !0) - } - }, { - key: "process", value: function (e) { - return this.AES_Decrypt_process(e) - } - }, { - key: "finish", value: function (e) { - return this.AES_Decrypt_finish(e) - } - }]), t - }(c) - }, { - "../aes": 2, - "babel-runtime/core-js/object/get-prototype-of": 26, - "babel-runtime/helpers/classCallCheck": 32, - "babel-runtime/helpers/createClass": 33, - "babel-runtime/helpers/inherits": 34, - "babel-runtime/helpers/possibleConstructorReturn": 35 - }], - 10: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r._AES_asm_instance = r._AES_heap_instance = void 0; - var n = e("./aes.asm"), i = r._AES_heap_instance = new Uint8Array(1048576); - r._AES_asm_instance = (0, n.AES_asm)(null, i.buffer) - }, {"./aes.asm": 1}], - 11: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r.AES_GCM_Decrypt = r.AES_GCM_Encrypt = r.AES_GCM = void 0; - var n = e("../exports"), i = e("./gcm"); - i.AES_GCM.encrypt = function (e, t, r, a, s) { - if (void 0 === e) throw new SyntaxError("data required"); - if (void 0 === t) throw new SyntaxError("key required"); - if (void 0 === r) throw new SyntaxError("nonce required"); - return new i.AES_GCM(t, r, a, s, n._AES_heap_instance, n._AES_asm_instance).encrypt(e).result - }, i.AES_GCM.decrypt = function (e, t, r, a, s) { - if (void 0 === e) throw new SyntaxError("data required"); - if (void 0 === t) throw new SyntaxError("key required"); - if (void 0 === r) throw new SyntaxError("nonce required"); - return new i.AES_GCM(t, r, a, s, n._AES_heap_instance, n._AES_asm_instance).decrypt(e).result - }, r.AES_GCM = i.AES_GCM, r.AES_GCM_Encrypt = i.AES_GCM_Encrypt, r.AES_GCM_Decrypt = i.AES_GCM_Decrypt - }, {"../exports": 10, "./gcm": 12}], - 12: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r.AES_GCM_Decrypt = r.AES_GCM_Encrypt = r.AES_GCM = void 0; - var n = l(e("babel-runtime/core-js/object/get-prototype-of")), - i = l(e("babel-runtime/helpers/classCallCheck")), a = l(e("babel-runtime/helpers/createClass")), - s = l(e("babel-runtime/helpers/possibleConstructorReturn")), o = l(e("babel-runtime/helpers/inherits")), - u = e("../../errors"), f = e("../../utils"), c = e("../aes"), d = e("../aes.asm"); - - function l(e) { - return e && e.__esModule ? e : {default: e} - } - - var h = r.AES_GCM = function (e) { - function t(e, r, a, o, u, f) { - (0, i.default)(this, t); - var c = (0, s.default)(this, (t.__proto__ || (0, n.default)(t)).call(this, e, void 0, !1, u, f)); - return c.nonce = null, c.adata = null, c.iv = null, c.counter = 1, c.tagSize = 16, c.mode = "GCM", c.BLOCK_SIZE = 16, c.reset(e, o, r, a), c - } - - return (0, o.default)(t, e), (0, a.default)(t, [{ - key: "reset", value: function (e, t, r, n) { - return this.AES_GCM_reset(e, t, r, n) - } - }, { - key: "encrypt", value: function (e) { - return this.AES_GCM_encrypt(e) - } - }, { - key: "decrypt", value: function (e) { - return this.AES_GCM_decrypt(e) - } - }, { - key: "AES_GCM_Encrypt_process", value: function (e) { - if (!(0, f.is_bytes)(e)) throw new TypeError("data isn't of expected type"); - var t = 0, r = e.length || 0, n = this.asm, i = this.heap, a = this.counter, s = this.pos, - o = this.len, u = 0, c = o + r & -16, l = 0; - if ((a - 1 << 4) + o + r > 68719476704) throw new RangeError("counter overflow"); - for (var h = new Uint8Array(c); r > 0;) o += l = (0, f._heap_write)(i, s + o, e, t, r), t += l, r -= l, l = n.cipher(d.AES_asm.ENC.CTR, d.AES_asm.HEAP_DATA + s, o), (l = n.mac(d.AES_asm.MAC.GCM, d.AES_asm.HEAP_DATA + s, l)) && h.set(i.subarray(s, s + l), u), a += l >>> 4, u += l, l < o ? (s += l, o -= l) : (s = 0, o = 0); - return this.result = h, this.counter = a, this.pos = s, this.len = o, this - } - }, { - key: "AES_GCM_Encrypt_finish", value: function () { - var e = this.asm, t = this.heap, r = this.counter, n = this.tagSize, i = this.adata, - a = this.pos, s = this.len, o = new Uint8Array(s + n); - e.cipher(d.AES_asm.ENC.CTR, d.AES_asm.HEAP_DATA + a, s + 15 & -16), s && o.set(t.subarray(a, a + s)); - for (var u = s; 15 & u; u++) t[a + u] = 0; - e.mac(d.AES_asm.MAC.GCM, d.AES_asm.HEAP_DATA + a, u); - var f = null !== i ? i.length : 0, c = (r - 1 << 4) + s; - return t[0] = t[1] = t[2] = 0, t[3] = f >>> 29, t[4] = f >>> 21, t[5] = f >>> 13 & 255, t[6] = f >>> 5 & 255, t[7] = f << 3 & 255, t[8] = t[9] = t[10] = 0, t[11] = c >>> 29, t[12] = c >>> 21 & 255, t[13] = c >>> 13 & 255, t[14] = c >>> 5 & 255, t[15] = c << 3 & 255, e.mac(d.AES_asm.MAC.GCM, d.AES_asm.HEAP_DATA, 16), e.get_iv(d.AES_asm.HEAP_DATA), e.set_counter(0, 0, 0, this.gamma0), e.cipher(d.AES_asm.ENC.CTR, d.AES_asm.HEAP_DATA, 16), o.set(t.subarray(0, n), s), this.result = o, this.counter = 1, this.pos = 0, this.len = 0, this - } - }, { - key: "AES_GCM_Decrypt_process", value: function (e) { - if (!(0, f.is_bytes)(e)) throw new TypeError("data isn't of expected type"); - var t = 0, r = e.length || 0, n = this.asm, i = this.heap, a = this.counter, s = this.tagSize, - o = this.pos, u = this.len, c = 0, l = u + r > s ? u + r - s & -16 : 0, h = u + r - l, - p = 0; - if ((a - 1 << 4) + u + r > 68719476704) throw new RangeError("counter overflow"); - for (var y = new Uint8Array(l); r > h;) u += p = (0, f._heap_write)(i, o + u, e, t, r - h), t += p, r -= p, p = n.mac(d.AES_asm.MAC.GCM, d.AES_asm.HEAP_DATA + o, p), (p = n.cipher(d.AES_asm.DEC.CTR, d.AES_asm.HEAP_DATA + o, p)) && y.set(i.subarray(o, o + p), c), a += p >>> 4, c += p, o = 0, u = 0; - return r > 0 && (u += (0, f._heap_write)(i, 0, e, t, r)), this.result = y, this.counter = a, this.pos = o, this.len = u, this - } - }, { - key: "AES_GCM_Decrypt_finish", value: function () { - var e = this.asm, t = this.heap, r = this.tagSize, n = this.adata, i = this.counter, - a = this.pos, s = this.len, o = s - r; - if (s < r) throw new u.IllegalStateError("authentication tag not found"); - for (var f = new Uint8Array(o), c = new Uint8Array(t.subarray(a + o, a + s)), l = o; 15 & l; l++) t[a + l] = 0; - e.mac(d.AES_asm.MAC.GCM, d.AES_asm.HEAP_DATA + a, l), e.cipher(d.AES_asm.DEC.CTR, d.AES_asm.HEAP_DATA + a, l), o && f.set(t.subarray(a, a + o)); - var h = null !== n ? n.length : 0, p = (i - 1 << 4) + s - r; - t[0] = t[1] = t[2] = 0, t[3] = h >>> 29, t[4] = h >>> 21, t[5] = h >>> 13 & 255, t[6] = h >>> 5 & 255, t[7] = h << 3 & 255, t[8] = t[9] = t[10] = 0, t[11] = p >>> 29, t[12] = p >>> 21 & 255, t[13] = p >>> 13 & 255, t[14] = p >>> 5 & 255, t[15] = p << 3 & 255, e.mac(d.AES_asm.MAC.GCM, d.AES_asm.HEAP_DATA, 16), e.get_iv(d.AES_asm.HEAP_DATA), e.set_counter(0, 0, 0, this.gamma0), e.cipher(d.AES_asm.ENC.CTR, d.AES_asm.HEAP_DATA, 16); - var y = 0; - for (l = 0; l < r; ++l) y |= c[l] ^ t[l]; - if (y) throw new u.SecurityError("data integrity check failed"); - return this.result = f, this.counter = 1, this.pos = 0, this.len = 0, this - } - }, { - key: "AES_GCM_decrypt", value: function (e) { - var t = this.AES_GCM_Decrypt_process(e).result, r = this.AES_GCM_Decrypt_finish().result, - n = new Uint8Array(t.length + r.length); - return t.length && n.set(t), r.length && n.set(r, t.length), this.result = n, this - } - }, { - key: "AES_GCM_encrypt", value: function (e) { - var t = this.AES_GCM_Encrypt_process(e).result, r = this.AES_GCM_Encrypt_finish().result, - n = new Uint8Array(t.length + r.length); - return t.length && n.set(t), r.length && n.set(r, t.length), this.result = n, this - } - }, { - key: "AES_GCM_reset", value: function (e, t, r, n, i, a) { - this.AES_reset(e, void 0, !1); - var s = this.asm, o = this.heap; - if (s.gcm_init(), void 0 !== (t = t)) { - if (!(0, f.is_number)(t)) throw new TypeError("tagSize must be a number"); - if (t < 4 || t > 16) throw new u.IllegalArgumentError("illegal tagSize value"); - this.tagSize = t - } else this.tagSize = 16; - if (void 0 === r) throw new Error("nonce is required"); - if (!(0, f.is_bytes)(r)) throw new TypeError("unexpected nonce type"); - this.nonce = r; - var c = r.length || 0, l = new Uint8Array(16); - 12 !== c ? (this._gcm_mac_process(r), o[0] = o[1] = o[2] = o[3] = o[4] = o[5] = o[6] = o[7] = o[8] = o[9] = o[10] = 0, o[11] = c >>> 29, o[12] = c >>> 21 & 255, o[13] = c >>> 13 & 255, o[14] = c >>> 5 & 255, o[15] = c << 3 & 255, s.mac(d.AES_asm.MAC.GCM, d.AES_asm.HEAP_DATA, 16), s.get_iv(d.AES_asm.HEAP_DATA), s.set_iv(), l.set(o.subarray(0, 16))) : (l.set(r), l[15] = 1); - var h = new DataView(l.buffer); - if (this.gamma0 = h.getUint32(12), s.set_nonce(h.getUint32(0), h.getUint32(4), h.getUint32(8), 0), s.set_mask(0, 0, 0, 4294967295), void 0 !== n && null !== n) { - if (!(0, f.is_bytes)(n)) throw new TypeError("unexpected adata type"); - if (n.length > 68719476704) throw new u.IllegalArgumentError("illegal adata length"); - n.length ? (this.adata = n, this._gcm_mac_process(n)) : this.adata = null - } else this.adata = null; - if (void 0 !== i) { - if (!(0, f.is_number)(i)) throw new TypeError("counter must be a number"); - if (i < 1 || i > 4294967295) throw new RangeError("counter must be a positive 32-bit integer"); - this.counter = i, s.set_counter(0, 0, 0, this.gamma0 + i | 0) - } else this.counter = 1, s.set_counter(0, 0, 0, this.gamma0 + 1 | 0); - if (void 0 !== a) { - if (!(0, f.is_number)(a)) throw new TypeError("iv must be a number"); - this.iv = a, this.AES_set_iv(a) - } - return this - } - }, { - key: "_gcm_mac_process", value: function (e) { - for (var t = this.heap, r = this.asm, n = 0, i = e.length || 0, a = 0; i > 0;) { - for (n += a = (0, f._heap_write)(t, 0, e, n, i), i -= a; 15 & a;) t[a++] = 0; - r.mac(d.AES_asm.MAC.GCM, d.AES_asm.HEAP_DATA, a) - } - } - }]), t - }(c.AES); - r.AES_GCM_Encrypt = function (e) { - function t(e, r, a, o, u, f) { - return (0, i.default)(this, t), (0, s.default)(this, (t.__proto__ || (0, n.default)(t)).call(this, e, r, a, o, u, f)) - } - - return (0, o.default)(t, e), (0, a.default)(t, [{ - key: "process", value: function (e) { - return this.AES_GCM_Encrypt_process(e) - } - }, { - key: "finish", value: function () { - return this.AES_GCM_Encrypt_finish() - } - }]), t - }(h), r.AES_GCM_Decrypt = function (e) { - function t(e, r, a, o, u, f) { - return (0, i.default)(this, t), (0, s.default)(this, (t.__proto__ || (0, n.default)(t)).call(this, e, r, a, o, u, f)) - } - - return (0, o.default)(t, e), (0, a.default)(t, [{ - key: "process", value: function (e) { - return this.AES_GCM_Decrypt_process(e) - } - }, { - key: "finish", value: function () { - return this.AES_GCM_Decrypt_finish() - } - }]), t - }(h) - }, { - "../../errors": 13, - "../../utils": 18, - "../aes": 2, - "../aes.asm": 1, - "babel-runtime/core-js/object/get-prototype-of": 26, - "babel-runtime/helpers/classCallCheck": 32, - "babel-runtime/helpers/createClass": 33, - "babel-runtime/helpers/inherits": 34, - "babel-runtime/helpers/possibleConstructorReturn": 35 - }], - 13: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}); - var n, i = e("babel-runtime/core-js/object/create"), a = (n = i) && n.__esModule ? n : {default: n}; - - function s() { - var e = Error.apply(this, arguments); - this.message = e.message, this.stack = e.stack - } - - function o() { - var e = Error.apply(this, arguments); - this.message = e.message, this.stack = e.stack - } - - function u() { - var e = Error.apply(this, arguments); - this.message = e.message, this.stack = e.stack - } - - r.IllegalStateError = s, r.IllegalArgumentError = o, r.SecurityError = u, s.prototype = (0, a.default)(Error.prototype, {name: {value: "IllegalStateError"}}), o.prototype = (0, a.default)(Error.prototype, {name: {value: "IllegalArgumentError"}}), u.prototype = (0, a.default)(Error.prototype, {name: {value: "SecurityError"}}) - }, {"babel-runtime/core-js/object/create": 23}], - 14: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r.hash_reset = function () { - return this.result = null, this.pos = 0, this.len = 0, this.asm.reset(), this - }, r.hash_process = function (e) { - if (null !== this.result) throw new i.IllegalStateError("state must be reset before processing new data"); - (0, n.is_string)(e) && (e = (0, n.string_to_bytes)(e)); - (0, n.is_buffer)(e) && (e = new Uint8Array(e)); - if (!(0, n.is_bytes)(e)) throw new TypeError("data isn't of expected type"); - var t = this.asm, r = this.heap, a = this.pos, s = this.len, o = 0, u = e.length, f = 0; - for (; u > 0;) f = (0, n._heap_write)(r, a + s, e, o, u), s += f, o += f, u -= f, f = t.process(a, s), a += f, (s -= f) || (a = 0); - return this.pos = a, this.len = s, this - }, r.hash_finish = function () { - if (null !== this.result) throw new i.IllegalStateError("state must be reset before processing new data"); - return this.asm.finish(this.pos, this.len, 0), this.result = new Uint8Array(this.HASH_SIZE), this.result.set(this.heap.subarray(0, this.HASH_SIZE)), this.pos = 0, this.len = 0, this - }; - var n = e("../utils"), i = e("../errors") - }, {"../errors": 13, "../utils": 18}], - 15: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r.SHA256 = void 0; - var n = e("./sha256"), i = e("../../utils"); - - function a(e) { - if (void 0 === e) throw new SyntaxError("data required"); - return (0, n.get_sha256_instance)().reset().process(e).finish().result - } - - var s = r.SHA256 = n.sha256_constructor; - s.bytes = a, s.hex = function (e) { - var t = a(e); - return (0, i.bytes_to_hex)(t) - }, s.base64 = function (e) { - var t = a(e); - return (0, i.bytes_to_base64)(t) - } - }, {"../../utils": 18, "./sha256": 17}], - 16: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r.sha256_asm = function (e, t, r) { - "use asm"; - var n = 0, i = 0, a = 0, s = 0, o = 0, u = 0, f = 0, c = 0, d = 0, l = 0, h = 0, p = 0, y = 0, b = 0, - m = 0, g = 0, v = 0, _ = 0, w = 0, k = 0, A = 0, x = 0, S = 0, E = 0, M = 0, C = 0, - j = new e.Uint8Array(r); - - function P(e, t, r, d, l, h, p, y, b, m, g, v, _, w, k, A) { - e = e | 0; - t = t | 0; - r = r | 0; - d = d | 0; - l = l | 0; - h = h | 0; - p = p | 0; - y = y | 0; - b = b | 0; - m = m | 0; - g = g | 0; - v = v | 0; - _ = _ | 0; - w = w | 0; - k = k | 0; - A = A | 0; - var x = 0, S = 0, E = 0, M = 0, C = 0, j = 0, P = 0, B = 0; - x = n; - S = i; - E = a; - M = s; - C = o; - j = u; - P = f; - B = c; - B = e + B + (C >>> 6 ^ C >>> 11 ^ C >>> 25 ^ C << 26 ^ C << 21 ^ C << 7) + (P ^ C & (j ^ P)) + 0x428a2f98 | 0; - M = M + B | 0; - B = B + (x & S ^ E & (x ^ S)) + (x >>> 2 ^ x >>> 13 ^ x >>> 22 ^ x << 30 ^ x << 19 ^ x << 10) | 0; - P = t + P + (M >>> 6 ^ M >>> 11 ^ M >>> 25 ^ M << 26 ^ M << 21 ^ M << 7) + (j ^ M & (C ^ j)) + 0x71374491 | 0; - E = E + P | 0; - P = P + (B & x ^ S & (B ^ x)) + (B >>> 2 ^ B >>> 13 ^ B >>> 22 ^ B << 30 ^ B << 19 ^ B << 10) | 0; - j = r + j + (E >>> 6 ^ E >>> 11 ^ E >>> 25 ^ E << 26 ^ E << 21 ^ E << 7) + (C ^ E & (M ^ C)) + 0xb5c0fbcf | 0; - S = S + j | 0; - j = j + (P & B ^ x & (P ^ B)) + (P >>> 2 ^ P >>> 13 ^ P >>> 22 ^ P << 30 ^ P << 19 ^ P << 10) | 0; - C = d + C + (S >>> 6 ^ S >>> 11 ^ S >>> 25 ^ S << 26 ^ S << 21 ^ S << 7) + (M ^ S & (E ^ M)) + 0xe9b5dba5 | 0; - x = x + C | 0; - C = C + (j & P ^ B & (j ^ P)) + (j >>> 2 ^ j >>> 13 ^ j >>> 22 ^ j << 30 ^ j << 19 ^ j << 10) | 0; - M = l + M + (x >>> 6 ^ x >>> 11 ^ x >>> 25 ^ x << 26 ^ x << 21 ^ x << 7) + (E ^ x & (S ^ E)) + 0x3956c25b | 0; - B = B + M | 0; - M = M + (C & j ^ P & (C ^ j)) + (C >>> 2 ^ C >>> 13 ^ C >>> 22 ^ C << 30 ^ C << 19 ^ C << 10) | 0; - E = h + E + (B >>> 6 ^ B >>> 11 ^ B >>> 25 ^ B << 26 ^ B << 21 ^ B << 7) + (S ^ B & (x ^ S)) + 0x59f111f1 | 0; - P = P + E | 0; - E = E + (M & C ^ j & (M ^ C)) + (M >>> 2 ^ M >>> 13 ^ M >>> 22 ^ M << 30 ^ M << 19 ^ M << 10) | 0; - S = p + S + (P >>> 6 ^ P >>> 11 ^ P >>> 25 ^ P << 26 ^ P << 21 ^ P << 7) + (x ^ P & (B ^ x)) + 0x923f82a4 | 0; - j = j + S | 0; - S = S + (E & M ^ C & (E ^ M)) + (E >>> 2 ^ E >>> 13 ^ E >>> 22 ^ E << 30 ^ E << 19 ^ E << 10) | 0; - x = y + x + (j >>> 6 ^ j >>> 11 ^ j >>> 25 ^ j << 26 ^ j << 21 ^ j << 7) + (B ^ j & (P ^ B)) + 0xab1c5ed5 | 0; - C = C + x | 0; - x = x + (S & E ^ M & (S ^ E)) + (S >>> 2 ^ S >>> 13 ^ S >>> 22 ^ S << 30 ^ S << 19 ^ S << 10) | 0; - B = b + B + (C >>> 6 ^ C >>> 11 ^ C >>> 25 ^ C << 26 ^ C << 21 ^ C << 7) + (P ^ C & (j ^ P)) + 0xd807aa98 | 0; - M = M + B | 0; - B = B + (x & S ^ E & (x ^ S)) + (x >>> 2 ^ x >>> 13 ^ x >>> 22 ^ x << 30 ^ x << 19 ^ x << 10) | 0; - P = m + P + (M >>> 6 ^ M >>> 11 ^ M >>> 25 ^ M << 26 ^ M << 21 ^ M << 7) + (j ^ M & (C ^ j)) + 0x12835b01 | 0; - E = E + P | 0; - P = P + (B & x ^ S & (B ^ x)) + (B >>> 2 ^ B >>> 13 ^ B >>> 22 ^ B << 30 ^ B << 19 ^ B << 10) | 0; - j = g + j + (E >>> 6 ^ E >>> 11 ^ E >>> 25 ^ E << 26 ^ E << 21 ^ E << 7) + (C ^ E & (M ^ C)) + 0x243185be | 0; - S = S + j | 0; - j = j + (P & B ^ x & (P ^ B)) + (P >>> 2 ^ P >>> 13 ^ P >>> 22 ^ P << 30 ^ P << 19 ^ P << 10) | 0; - C = v + C + (S >>> 6 ^ S >>> 11 ^ S >>> 25 ^ S << 26 ^ S << 21 ^ S << 7) + (M ^ S & (E ^ M)) + 0x550c7dc3 | 0; - x = x + C | 0; - C = C + (j & P ^ B & (j ^ P)) + (j >>> 2 ^ j >>> 13 ^ j >>> 22 ^ j << 30 ^ j << 19 ^ j << 10) | 0; - M = _ + M + (x >>> 6 ^ x >>> 11 ^ x >>> 25 ^ x << 26 ^ x << 21 ^ x << 7) + (E ^ x & (S ^ E)) + 0x72be5d74 | 0; - B = B + M | 0; - M = M + (C & j ^ P & (C ^ j)) + (C >>> 2 ^ C >>> 13 ^ C >>> 22 ^ C << 30 ^ C << 19 ^ C << 10) | 0; - E = w + E + (B >>> 6 ^ B >>> 11 ^ B >>> 25 ^ B << 26 ^ B << 21 ^ B << 7) + (S ^ B & (x ^ S)) + 0x80deb1fe | 0; - P = P + E | 0; - E = E + (M & C ^ j & (M ^ C)) + (M >>> 2 ^ M >>> 13 ^ M >>> 22 ^ M << 30 ^ M << 19 ^ M << 10) | 0; - S = k + S + (P >>> 6 ^ P >>> 11 ^ P >>> 25 ^ P << 26 ^ P << 21 ^ P << 7) + (x ^ P & (B ^ x)) + 0x9bdc06a7 | 0; - j = j + S | 0; - S = S + (E & M ^ C & (E ^ M)) + (E >>> 2 ^ E >>> 13 ^ E >>> 22 ^ E << 30 ^ E << 19 ^ E << 10) | 0; - x = A + x + (j >>> 6 ^ j >>> 11 ^ j >>> 25 ^ j << 26 ^ j << 21 ^ j << 7) + (B ^ j & (P ^ B)) + 0xc19bf174 | 0; - C = C + x | 0; - x = x + (S & E ^ M & (S ^ E)) + (S >>> 2 ^ S >>> 13 ^ S >>> 22 ^ S << 30 ^ S << 19 ^ S << 10) | 0; - e = (t >>> 7 ^ t >>> 18 ^ t >>> 3 ^ t << 25 ^ t << 14) + (k >>> 17 ^ k >>> 19 ^ k >>> 10 ^ k << 15 ^ k << 13) + e + m | 0; - B = e + B + (C >>> 6 ^ C >>> 11 ^ C >>> 25 ^ C << 26 ^ C << 21 ^ C << 7) + (P ^ C & (j ^ P)) + 0xe49b69c1 | 0; - M = M + B | 0; - B = B + (x & S ^ E & (x ^ S)) + (x >>> 2 ^ x >>> 13 ^ x >>> 22 ^ x << 30 ^ x << 19 ^ x << 10) | 0; - t = (r >>> 7 ^ r >>> 18 ^ r >>> 3 ^ r << 25 ^ r << 14) + (A >>> 17 ^ A >>> 19 ^ A >>> 10 ^ A << 15 ^ A << 13) + t + g | 0; - P = t + P + (M >>> 6 ^ M >>> 11 ^ M >>> 25 ^ M << 26 ^ M << 21 ^ M << 7) + (j ^ M & (C ^ j)) + 0xefbe4786 | 0; - E = E + P | 0; - P = P + (B & x ^ S & (B ^ x)) + (B >>> 2 ^ B >>> 13 ^ B >>> 22 ^ B << 30 ^ B << 19 ^ B << 10) | 0; - r = (d >>> 7 ^ d >>> 18 ^ d >>> 3 ^ d << 25 ^ d << 14) + (e >>> 17 ^ e >>> 19 ^ e >>> 10 ^ e << 15 ^ e << 13) + r + v | 0; - j = r + j + (E >>> 6 ^ E >>> 11 ^ E >>> 25 ^ E << 26 ^ E << 21 ^ E << 7) + (C ^ E & (M ^ C)) + 0x0fc19dc6 | 0; - S = S + j | 0; - j = j + (P & B ^ x & (P ^ B)) + (P >>> 2 ^ P >>> 13 ^ P >>> 22 ^ P << 30 ^ P << 19 ^ P << 10) | 0; - d = (l >>> 7 ^ l >>> 18 ^ l >>> 3 ^ l << 25 ^ l << 14) + (t >>> 17 ^ t >>> 19 ^ t >>> 10 ^ t << 15 ^ t << 13) + d + _ | 0; - C = d + C + (S >>> 6 ^ S >>> 11 ^ S >>> 25 ^ S << 26 ^ S << 21 ^ S << 7) + (M ^ S & (E ^ M)) + 0x240ca1cc | 0; - x = x + C | 0; - C = C + (j & P ^ B & (j ^ P)) + (j >>> 2 ^ j >>> 13 ^ j >>> 22 ^ j << 30 ^ j << 19 ^ j << 10) | 0; - l = (h >>> 7 ^ h >>> 18 ^ h >>> 3 ^ h << 25 ^ h << 14) + (r >>> 17 ^ r >>> 19 ^ r >>> 10 ^ r << 15 ^ r << 13) + l + w | 0; - M = l + M + (x >>> 6 ^ x >>> 11 ^ x >>> 25 ^ x << 26 ^ x << 21 ^ x << 7) + (E ^ x & (S ^ E)) + 0x2de92c6f | 0; - B = B + M | 0; - M = M + (C & j ^ P & (C ^ j)) + (C >>> 2 ^ C >>> 13 ^ C >>> 22 ^ C << 30 ^ C << 19 ^ C << 10) | 0; - h = (p >>> 7 ^ p >>> 18 ^ p >>> 3 ^ p << 25 ^ p << 14) + (d >>> 17 ^ d >>> 19 ^ d >>> 10 ^ d << 15 ^ d << 13) + h + k | 0; - E = h + E + (B >>> 6 ^ B >>> 11 ^ B >>> 25 ^ B << 26 ^ B << 21 ^ B << 7) + (S ^ B & (x ^ S)) + 0x4a7484aa | 0; - P = P + E | 0; - E = E + (M & C ^ j & (M ^ C)) + (M >>> 2 ^ M >>> 13 ^ M >>> 22 ^ M << 30 ^ M << 19 ^ M << 10) | 0; - p = (y >>> 7 ^ y >>> 18 ^ y >>> 3 ^ y << 25 ^ y << 14) + (l >>> 17 ^ l >>> 19 ^ l >>> 10 ^ l << 15 ^ l << 13) + p + A | 0; - S = p + S + (P >>> 6 ^ P >>> 11 ^ P >>> 25 ^ P << 26 ^ P << 21 ^ P << 7) + (x ^ P & (B ^ x)) + 0x5cb0a9dc | 0; - j = j + S | 0; - S = S + (E & M ^ C & (E ^ M)) + (E >>> 2 ^ E >>> 13 ^ E >>> 22 ^ E << 30 ^ E << 19 ^ E << 10) | 0; - y = (b >>> 7 ^ b >>> 18 ^ b >>> 3 ^ b << 25 ^ b << 14) + (h >>> 17 ^ h >>> 19 ^ h >>> 10 ^ h << 15 ^ h << 13) + y + e | 0; - x = y + x + (j >>> 6 ^ j >>> 11 ^ j >>> 25 ^ j << 26 ^ j << 21 ^ j << 7) + (B ^ j & (P ^ B)) + 0x76f988da | 0; - C = C + x | 0; - x = x + (S & E ^ M & (S ^ E)) + (S >>> 2 ^ S >>> 13 ^ S >>> 22 ^ S << 30 ^ S << 19 ^ S << 10) | 0; - b = (m >>> 7 ^ m >>> 18 ^ m >>> 3 ^ m << 25 ^ m << 14) + (p >>> 17 ^ p >>> 19 ^ p >>> 10 ^ p << 15 ^ p << 13) + b + t | 0; - B = b + B + (C >>> 6 ^ C >>> 11 ^ C >>> 25 ^ C << 26 ^ C << 21 ^ C << 7) + (P ^ C & (j ^ P)) + 0x983e5152 | 0; - M = M + B | 0; - B = B + (x & S ^ E & (x ^ S)) + (x >>> 2 ^ x >>> 13 ^ x >>> 22 ^ x << 30 ^ x << 19 ^ x << 10) | 0; - m = (g >>> 7 ^ g >>> 18 ^ g >>> 3 ^ g << 25 ^ g << 14) + (y >>> 17 ^ y >>> 19 ^ y >>> 10 ^ y << 15 ^ y << 13) + m + r | 0; - P = m + P + (M >>> 6 ^ M >>> 11 ^ M >>> 25 ^ M << 26 ^ M << 21 ^ M << 7) + (j ^ M & (C ^ j)) + 0xa831c66d | 0; - E = E + P | 0; - P = P + (B & x ^ S & (B ^ x)) + (B >>> 2 ^ B >>> 13 ^ B >>> 22 ^ B << 30 ^ B << 19 ^ B << 10) | 0; - g = (v >>> 7 ^ v >>> 18 ^ v >>> 3 ^ v << 25 ^ v << 14) + (b >>> 17 ^ b >>> 19 ^ b >>> 10 ^ b << 15 ^ b << 13) + g + d | 0; - j = g + j + (E >>> 6 ^ E >>> 11 ^ E >>> 25 ^ E << 26 ^ E << 21 ^ E << 7) + (C ^ E & (M ^ C)) + 0xb00327c8 | 0; - S = S + j | 0; - j = j + (P & B ^ x & (P ^ B)) + (P >>> 2 ^ P >>> 13 ^ P >>> 22 ^ P << 30 ^ P << 19 ^ P << 10) | 0; - v = (_ >>> 7 ^ _ >>> 18 ^ _ >>> 3 ^ _ << 25 ^ _ << 14) + (m >>> 17 ^ m >>> 19 ^ m >>> 10 ^ m << 15 ^ m << 13) + v + l | 0; - C = v + C + (S >>> 6 ^ S >>> 11 ^ S >>> 25 ^ S << 26 ^ S << 21 ^ S << 7) + (M ^ S & (E ^ M)) + 0xbf597fc7 | 0; - x = x + C | 0; - C = C + (j & P ^ B & (j ^ P)) + (j >>> 2 ^ j >>> 13 ^ j >>> 22 ^ j << 30 ^ j << 19 ^ j << 10) | 0; - _ = (w >>> 7 ^ w >>> 18 ^ w >>> 3 ^ w << 25 ^ w << 14) + (g >>> 17 ^ g >>> 19 ^ g >>> 10 ^ g << 15 ^ g << 13) + _ + h | 0; - M = _ + M + (x >>> 6 ^ x >>> 11 ^ x >>> 25 ^ x << 26 ^ x << 21 ^ x << 7) + (E ^ x & (S ^ E)) + 0xc6e00bf3 | 0; - B = B + M | 0; - M = M + (C & j ^ P & (C ^ j)) + (C >>> 2 ^ C >>> 13 ^ C >>> 22 ^ C << 30 ^ C << 19 ^ C << 10) | 0; - w = (k >>> 7 ^ k >>> 18 ^ k >>> 3 ^ k << 25 ^ k << 14) + (v >>> 17 ^ v >>> 19 ^ v >>> 10 ^ v << 15 ^ v << 13) + w + p | 0; - E = w + E + (B >>> 6 ^ B >>> 11 ^ B >>> 25 ^ B << 26 ^ B << 21 ^ B << 7) + (S ^ B & (x ^ S)) + 0xd5a79147 | 0; - P = P + E | 0; - E = E + (M & C ^ j & (M ^ C)) + (M >>> 2 ^ M >>> 13 ^ M >>> 22 ^ M << 30 ^ M << 19 ^ M << 10) | 0; - k = (A >>> 7 ^ A >>> 18 ^ A >>> 3 ^ A << 25 ^ A << 14) + (_ >>> 17 ^ _ >>> 19 ^ _ >>> 10 ^ _ << 15 ^ _ << 13) + k + y | 0; - S = k + S + (P >>> 6 ^ P >>> 11 ^ P >>> 25 ^ P << 26 ^ P << 21 ^ P << 7) + (x ^ P & (B ^ x)) + 0x06ca6351 | 0; - j = j + S | 0; - S = S + (E & M ^ C & (E ^ M)) + (E >>> 2 ^ E >>> 13 ^ E >>> 22 ^ E << 30 ^ E << 19 ^ E << 10) | 0; - A = (e >>> 7 ^ e >>> 18 ^ e >>> 3 ^ e << 25 ^ e << 14) + (w >>> 17 ^ w >>> 19 ^ w >>> 10 ^ w << 15 ^ w << 13) + A + b | 0; - x = A + x + (j >>> 6 ^ j >>> 11 ^ j >>> 25 ^ j << 26 ^ j << 21 ^ j << 7) + (B ^ j & (P ^ B)) + 0x14292967 | 0; - C = C + x | 0; - x = x + (S & E ^ M & (S ^ E)) + (S >>> 2 ^ S >>> 13 ^ S >>> 22 ^ S << 30 ^ S << 19 ^ S << 10) | 0; - e = (t >>> 7 ^ t >>> 18 ^ t >>> 3 ^ t << 25 ^ t << 14) + (k >>> 17 ^ k >>> 19 ^ k >>> 10 ^ k << 15 ^ k << 13) + e + m | 0; - B = e + B + (C >>> 6 ^ C >>> 11 ^ C >>> 25 ^ C << 26 ^ C << 21 ^ C << 7) + (P ^ C & (j ^ P)) + 0x27b70a85 | 0; - M = M + B | 0; - B = B + (x & S ^ E & (x ^ S)) + (x >>> 2 ^ x >>> 13 ^ x >>> 22 ^ x << 30 ^ x << 19 ^ x << 10) | 0; - t = (r >>> 7 ^ r >>> 18 ^ r >>> 3 ^ r << 25 ^ r << 14) + (A >>> 17 ^ A >>> 19 ^ A >>> 10 ^ A << 15 ^ A << 13) + t + g | 0; - P = t + P + (M >>> 6 ^ M >>> 11 ^ M >>> 25 ^ M << 26 ^ M << 21 ^ M << 7) + (j ^ M & (C ^ j)) + 0x2e1b2138 | 0; - E = E + P | 0; - P = P + (B & x ^ S & (B ^ x)) + (B >>> 2 ^ B >>> 13 ^ B >>> 22 ^ B << 30 ^ B << 19 ^ B << 10) | 0; - r = (d >>> 7 ^ d >>> 18 ^ d >>> 3 ^ d << 25 ^ d << 14) + (e >>> 17 ^ e >>> 19 ^ e >>> 10 ^ e << 15 ^ e << 13) + r + v | 0; - j = r + j + (E >>> 6 ^ E >>> 11 ^ E >>> 25 ^ E << 26 ^ E << 21 ^ E << 7) + (C ^ E & (M ^ C)) + 0x4d2c6dfc | 0; - S = S + j | 0; - j = j + (P & B ^ x & (P ^ B)) + (P >>> 2 ^ P >>> 13 ^ P >>> 22 ^ P << 30 ^ P << 19 ^ P << 10) | 0; - d = (l >>> 7 ^ l >>> 18 ^ l >>> 3 ^ l << 25 ^ l << 14) + (t >>> 17 ^ t >>> 19 ^ t >>> 10 ^ t << 15 ^ t << 13) + d + _ | 0; - C = d + C + (S >>> 6 ^ S >>> 11 ^ S >>> 25 ^ S << 26 ^ S << 21 ^ S << 7) + (M ^ S & (E ^ M)) + 0x53380d13 | 0; - x = x + C | 0; - C = C + (j & P ^ B & (j ^ P)) + (j >>> 2 ^ j >>> 13 ^ j >>> 22 ^ j << 30 ^ j << 19 ^ j << 10) | 0; - l = (h >>> 7 ^ h >>> 18 ^ h >>> 3 ^ h << 25 ^ h << 14) + (r >>> 17 ^ r >>> 19 ^ r >>> 10 ^ r << 15 ^ r << 13) + l + w | 0; - M = l + M + (x >>> 6 ^ x >>> 11 ^ x >>> 25 ^ x << 26 ^ x << 21 ^ x << 7) + (E ^ x & (S ^ E)) + 0x650a7354 | 0; - B = B + M | 0; - M = M + (C & j ^ P & (C ^ j)) + (C >>> 2 ^ C >>> 13 ^ C >>> 22 ^ C << 30 ^ C << 19 ^ C << 10) | 0; - h = (p >>> 7 ^ p >>> 18 ^ p >>> 3 ^ p << 25 ^ p << 14) + (d >>> 17 ^ d >>> 19 ^ d >>> 10 ^ d << 15 ^ d << 13) + h + k | 0; - E = h + E + (B >>> 6 ^ B >>> 11 ^ B >>> 25 ^ B << 26 ^ B << 21 ^ B << 7) + (S ^ B & (x ^ S)) + 0x766a0abb | 0; - P = P + E | 0; - E = E + (M & C ^ j & (M ^ C)) + (M >>> 2 ^ M >>> 13 ^ M >>> 22 ^ M << 30 ^ M << 19 ^ M << 10) | 0; - p = (y >>> 7 ^ y >>> 18 ^ y >>> 3 ^ y << 25 ^ y << 14) + (l >>> 17 ^ l >>> 19 ^ l >>> 10 ^ l << 15 ^ l << 13) + p + A | 0; - S = p + S + (P >>> 6 ^ P >>> 11 ^ P >>> 25 ^ P << 26 ^ P << 21 ^ P << 7) + (x ^ P & (B ^ x)) + 0x81c2c92e | 0; - j = j + S | 0; - S = S + (E & M ^ C & (E ^ M)) + (E >>> 2 ^ E >>> 13 ^ E >>> 22 ^ E << 30 ^ E << 19 ^ E << 10) | 0; - y = (b >>> 7 ^ b >>> 18 ^ b >>> 3 ^ b << 25 ^ b << 14) + (h >>> 17 ^ h >>> 19 ^ h >>> 10 ^ h << 15 ^ h << 13) + y + e | 0; - x = y + x + (j >>> 6 ^ j >>> 11 ^ j >>> 25 ^ j << 26 ^ j << 21 ^ j << 7) + (B ^ j & (P ^ B)) + 0x92722c85 | 0; - C = C + x | 0; - x = x + (S & E ^ M & (S ^ E)) + (S >>> 2 ^ S >>> 13 ^ S >>> 22 ^ S << 30 ^ S << 19 ^ S << 10) | 0; - b = (m >>> 7 ^ m >>> 18 ^ m >>> 3 ^ m << 25 ^ m << 14) + (p >>> 17 ^ p >>> 19 ^ p >>> 10 ^ p << 15 ^ p << 13) + b + t | 0; - B = b + B + (C >>> 6 ^ C >>> 11 ^ C >>> 25 ^ C << 26 ^ C << 21 ^ C << 7) + (P ^ C & (j ^ P)) + 0xa2bfe8a1 | 0; - M = M + B | 0; - B = B + (x & S ^ E & (x ^ S)) + (x >>> 2 ^ x >>> 13 ^ x >>> 22 ^ x << 30 ^ x << 19 ^ x << 10) | 0; - m = (g >>> 7 ^ g >>> 18 ^ g >>> 3 ^ g << 25 ^ g << 14) + (y >>> 17 ^ y >>> 19 ^ y >>> 10 ^ y << 15 ^ y << 13) + m + r | 0; - P = m + P + (M >>> 6 ^ M >>> 11 ^ M >>> 25 ^ M << 26 ^ M << 21 ^ M << 7) + (j ^ M & (C ^ j)) + 0xa81a664b | 0; - E = E + P | 0; - P = P + (B & x ^ S & (B ^ x)) + (B >>> 2 ^ B >>> 13 ^ B >>> 22 ^ B << 30 ^ B << 19 ^ B << 10) | 0; - g = (v >>> 7 ^ v >>> 18 ^ v >>> 3 ^ v << 25 ^ v << 14) + (b >>> 17 ^ b >>> 19 ^ b >>> 10 ^ b << 15 ^ b << 13) + g + d | 0; - j = g + j + (E >>> 6 ^ E >>> 11 ^ E >>> 25 ^ E << 26 ^ E << 21 ^ E << 7) + (C ^ E & (M ^ C)) + 0xc24b8b70 | 0; - S = S + j | 0; - j = j + (P & B ^ x & (P ^ B)) + (P >>> 2 ^ P >>> 13 ^ P >>> 22 ^ P << 30 ^ P << 19 ^ P << 10) | 0; - v = (_ >>> 7 ^ _ >>> 18 ^ _ >>> 3 ^ _ << 25 ^ _ << 14) + (m >>> 17 ^ m >>> 19 ^ m >>> 10 ^ m << 15 ^ m << 13) + v + l | 0; - C = v + C + (S >>> 6 ^ S >>> 11 ^ S >>> 25 ^ S << 26 ^ S << 21 ^ S << 7) + (M ^ S & (E ^ M)) + 0xc76c51a3 | 0; - x = x + C | 0; - C = C + (j & P ^ B & (j ^ P)) + (j >>> 2 ^ j >>> 13 ^ j >>> 22 ^ j << 30 ^ j << 19 ^ j << 10) | 0; - _ = (w >>> 7 ^ w >>> 18 ^ w >>> 3 ^ w << 25 ^ w << 14) + (g >>> 17 ^ g >>> 19 ^ g >>> 10 ^ g << 15 ^ g << 13) + _ + h | 0; - M = _ + M + (x >>> 6 ^ x >>> 11 ^ x >>> 25 ^ x << 26 ^ x << 21 ^ x << 7) + (E ^ x & (S ^ E)) + 0xd192e819 | 0; - B = B + M | 0; - M = M + (C & j ^ P & (C ^ j)) + (C >>> 2 ^ C >>> 13 ^ C >>> 22 ^ C << 30 ^ C << 19 ^ C << 10) | 0; - w = (k >>> 7 ^ k >>> 18 ^ k >>> 3 ^ k << 25 ^ k << 14) + (v >>> 17 ^ v >>> 19 ^ v >>> 10 ^ v << 15 ^ v << 13) + w + p | 0; - E = w + E + (B >>> 6 ^ B >>> 11 ^ B >>> 25 ^ B << 26 ^ B << 21 ^ B << 7) + (S ^ B & (x ^ S)) + 0xd6990624 | 0; - P = P + E | 0; - E = E + (M & C ^ j & (M ^ C)) + (M >>> 2 ^ M >>> 13 ^ M >>> 22 ^ M << 30 ^ M << 19 ^ M << 10) | 0; - k = (A >>> 7 ^ A >>> 18 ^ A >>> 3 ^ A << 25 ^ A << 14) + (_ >>> 17 ^ _ >>> 19 ^ _ >>> 10 ^ _ << 15 ^ _ << 13) + k + y | 0; - S = k + S + (P >>> 6 ^ P >>> 11 ^ P >>> 25 ^ P << 26 ^ P << 21 ^ P << 7) + (x ^ P & (B ^ x)) + 0xf40e3585 | 0; - j = j + S | 0; - S = S + (E & M ^ C & (E ^ M)) + (E >>> 2 ^ E >>> 13 ^ E >>> 22 ^ E << 30 ^ E << 19 ^ E << 10) | 0; - A = (e >>> 7 ^ e >>> 18 ^ e >>> 3 ^ e << 25 ^ e << 14) + (w >>> 17 ^ w >>> 19 ^ w >>> 10 ^ w << 15 ^ w << 13) + A + b | 0; - x = A + x + (j >>> 6 ^ j >>> 11 ^ j >>> 25 ^ j << 26 ^ j << 21 ^ j << 7) + (B ^ j & (P ^ B)) + 0x106aa070 | 0; - C = C + x | 0; - x = x + (S & E ^ M & (S ^ E)) + (S >>> 2 ^ S >>> 13 ^ S >>> 22 ^ S << 30 ^ S << 19 ^ S << 10) | 0; - e = (t >>> 7 ^ t >>> 18 ^ t >>> 3 ^ t << 25 ^ t << 14) + (k >>> 17 ^ k >>> 19 ^ k >>> 10 ^ k << 15 ^ k << 13) + e + m | 0; - B = e + B + (C >>> 6 ^ C >>> 11 ^ C >>> 25 ^ C << 26 ^ C << 21 ^ C << 7) + (P ^ C & (j ^ P)) + 0x19a4c116 | 0; - M = M + B | 0; - B = B + (x & S ^ E & (x ^ S)) + (x >>> 2 ^ x >>> 13 ^ x >>> 22 ^ x << 30 ^ x << 19 ^ x << 10) | 0; - t = (r >>> 7 ^ r >>> 18 ^ r >>> 3 ^ r << 25 ^ r << 14) + (A >>> 17 ^ A >>> 19 ^ A >>> 10 ^ A << 15 ^ A << 13) + t + g | 0; - P = t + P + (M >>> 6 ^ M >>> 11 ^ M >>> 25 ^ M << 26 ^ M << 21 ^ M << 7) + (j ^ M & (C ^ j)) + 0x1e376c08 | 0; - E = E + P | 0; - P = P + (B & x ^ S & (B ^ x)) + (B >>> 2 ^ B >>> 13 ^ B >>> 22 ^ B << 30 ^ B << 19 ^ B << 10) | 0; - r = (d >>> 7 ^ d >>> 18 ^ d >>> 3 ^ d << 25 ^ d << 14) + (e >>> 17 ^ e >>> 19 ^ e >>> 10 ^ e << 15 ^ e << 13) + r + v | 0; - j = r + j + (E >>> 6 ^ E >>> 11 ^ E >>> 25 ^ E << 26 ^ E << 21 ^ E << 7) + (C ^ E & (M ^ C)) + 0x2748774c | 0; - S = S + j | 0; - j = j + (P & B ^ x & (P ^ B)) + (P >>> 2 ^ P >>> 13 ^ P >>> 22 ^ P << 30 ^ P << 19 ^ P << 10) | 0; - d = (l >>> 7 ^ l >>> 18 ^ l >>> 3 ^ l << 25 ^ l << 14) + (t >>> 17 ^ t >>> 19 ^ t >>> 10 ^ t << 15 ^ t << 13) + d + _ | 0; - C = d + C + (S >>> 6 ^ S >>> 11 ^ S >>> 25 ^ S << 26 ^ S << 21 ^ S << 7) + (M ^ S & (E ^ M)) + 0x34b0bcb5 | 0; - x = x + C | 0; - C = C + (j & P ^ B & (j ^ P)) + (j >>> 2 ^ j >>> 13 ^ j >>> 22 ^ j << 30 ^ j << 19 ^ j << 10) | 0; - l = (h >>> 7 ^ h >>> 18 ^ h >>> 3 ^ h << 25 ^ h << 14) + (r >>> 17 ^ r >>> 19 ^ r >>> 10 ^ r << 15 ^ r << 13) + l + w | 0; - M = l + M + (x >>> 6 ^ x >>> 11 ^ x >>> 25 ^ x << 26 ^ x << 21 ^ x << 7) + (E ^ x & (S ^ E)) + 0x391c0cb3 | 0; - B = B + M | 0; - M = M + (C & j ^ P & (C ^ j)) + (C >>> 2 ^ C >>> 13 ^ C >>> 22 ^ C << 30 ^ C << 19 ^ C << 10) | 0; - h = (p >>> 7 ^ p >>> 18 ^ p >>> 3 ^ p << 25 ^ p << 14) + (d >>> 17 ^ d >>> 19 ^ d >>> 10 ^ d << 15 ^ d << 13) + h + k | 0; - E = h + E + (B >>> 6 ^ B >>> 11 ^ B >>> 25 ^ B << 26 ^ B << 21 ^ B << 7) + (S ^ B & (x ^ S)) + 0x4ed8aa4a | 0; - P = P + E | 0; - E = E + (M & C ^ j & (M ^ C)) + (M >>> 2 ^ M >>> 13 ^ M >>> 22 ^ M << 30 ^ M << 19 ^ M << 10) | 0; - p = (y >>> 7 ^ y >>> 18 ^ y >>> 3 ^ y << 25 ^ y << 14) + (l >>> 17 ^ l >>> 19 ^ l >>> 10 ^ l << 15 ^ l << 13) + p + A | 0; - S = p + S + (P >>> 6 ^ P >>> 11 ^ P >>> 25 ^ P << 26 ^ P << 21 ^ P << 7) + (x ^ P & (B ^ x)) + 0x5b9cca4f | 0; - j = j + S | 0; - S = S + (E & M ^ C & (E ^ M)) + (E >>> 2 ^ E >>> 13 ^ E >>> 22 ^ E << 30 ^ E << 19 ^ E << 10) | 0; - y = (b >>> 7 ^ b >>> 18 ^ b >>> 3 ^ b << 25 ^ b << 14) + (h >>> 17 ^ h >>> 19 ^ h >>> 10 ^ h << 15 ^ h << 13) + y + e | 0; - x = y + x + (j >>> 6 ^ j >>> 11 ^ j >>> 25 ^ j << 26 ^ j << 21 ^ j << 7) + (B ^ j & (P ^ B)) + 0x682e6ff3 | 0; - C = C + x | 0; - x = x + (S & E ^ M & (S ^ E)) + (S >>> 2 ^ S >>> 13 ^ S >>> 22 ^ S << 30 ^ S << 19 ^ S << 10) | 0; - b = (m >>> 7 ^ m >>> 18 ^ m >>> 3 ^ m << 25 ^ m << 14) + (p >>> 17 ^ p >>> 19 ^ p >>> 10 ^ p << 15 ^ p << 13) + b + t | 0; - B = b + B + (C >>> 6 ^ C >>> 11 ^ C >>> 25 ^ C << 26 ^ C << 21 ^ C << 7) + (P ^ C & (j ^ P)) + 0x748f82ee | 0; - M = M + B | 0; - B = B + (x & S ^ E & (x ^ S)) + (x >>> 2 ^ x >>> 13 ^ x >>> 22 ^ x << 30 ^ x << 19 ^ x << 10) | 0; - m = (g >>> 7 ^ g >>> 18 ^ g >>> 3 ^ g << 25 ^ g << 14) + (y >>> 17 ^ y >>> 19 ^ y >>> 10 ^ y << 15 ^ y << 13) + m + r | 0; - P = m + P + (M >>> 6 ^ M >>> 11 ^ M >>> 25 ^ M << 26 ^ M << 21 ^ M << 7) + (j ^ M & (C ^ j)) + 0x78a5636f | 0; - E = E + P | 0; - P = P + (B & x ^ S & (B ^ x)) + (B >>> 2 ^ B >>> 13 ^ B >>> 22 ^ B << 30 ^ B << 19 ^ B << 10) | 0; - g = (v >>> 7 ^ v >>> 18 ^ v >>> 3 ^ v << 25 ^ v << 14) + (b >>> 17 ^ b >>> 19 ^ b >>> 10 ^ b << 15 ^ b << 13) + g + d | 0; - j = g + j + (E >>> 6 ^ E >>> 11 ^ E >>> 25 ^ E << 26 ^ E << 21 ^ E << 7) + (C ^ E & (M ^ C)) + 0x84c87814 | 0; - S = S + j | 0; - j = j + (P & B ^ x & (P ^ B)) + (P >>> 2 ^ P >>> 13 ^ P >>> 22 ^ P << 30 ^ P << 19 ^ P << 10) | 0; - v = (_ >>> 7 ^ _ >>> 18 ^ _ >>> 3 ^ _ << 25 ^ _ << 14) + (m >>> 17 ^ m >>> 19 ^ m >>> 10 ^ m << 15 ^ m << 13) + v + l | 0; - C = v + C + (S >>> 6 ^ S >>> 11 ^ S >>> 25 ^ S << 26 ^ S << 21 ^ S << 7) + (M ^ S & (E ^ M)) + 0x8cc70208 | 0; - x = x + C | 0; - C = C + (j & P ^ B & (j ^ P)) + (j >>> 2 ^ j >>> 13 ^ j >>> 22 ^ j << 30 ^ j << 19 ^ j << 10) | 0; - _ = (w >>> 7 ^ w >>> 18 ^ w >>> 3 ^ w << 25 ^ w << 14) + (g >>> 17 ^ g >>> 19 ^ g >>> 10 ^ g << 15 ^ g << 13) + _ + h | 0; - M = _ + M + (x >>> 6 ^ x >>> 11 ^ x >>> 25 ^ x << 26 ^ x << 21 ^ x << 7) + (E ^ x & (S ^ E)) + 0x90befffa | 0; - B = B + M | 0; - M = M + (C & j ^ P & (C ^ j)) + (C >>> 2 ^ C >>> 13 ^ C >>> 22 ^ C << 30 ^ C << 19 ^ C << 10) | 0; - w = (k >>> 7 ^ k >>> 18 ^ k >>> 3 ^ k << 25 ^ k << 14) + (v >>> 17 ^ v >>> 19 ^ v >>> 10 ^ v << 15 ^ v << 13) + w + p | 0; - E = w + E + (B >>> 6 ^ B >>> 11 ^ B >>> 25 ^ B << 26 ^ B << 21 ^ B << 7) + (S ^ B & (x ^ S)) + 0xa4506ceb | 0; - P = P + E | 0; - E = E + (M & C ^ j & (M ^ C)) + (M >>> 2 ^ M >>> 13 ^ M >>> 22 ^ M << 30 ^ M << 19 ^ M << 10) | 0; - k = (A >>> 7 ^ A >>> 18 ^ A >>> 3 ^ A << 25 ^ A << 14) + (_ >>> 17 ^ _ >>> 19 ^ _ >>> 10 ^ _ << 15 ^ _ << 13) + k + y | 0; - S = k + S + (P >>> 6 ^ P >>> 11 ^ P >>> 25 ^ P << 26 ^ P << 21 ^ P << 7) + (x ^ P & (B ^ x)) + 0xbef9a3f7 | 0; - j = j + S | 0; - S = S + (E & M ^ C & (E ^ M)) + (E >>> 2 ^ E >>> 13 ^ E >>> 22 ^ E << 30 ^ E << 19 ^ E << 10) | 0; - A = (e >>> 7 ^ e >>> 18 ^ e >>> 3 ^ e << 25 ^ e << 14) + (w >>> 17 ^ w >>> 19 ^ w >>> 10 ^ w << 15 ^ w << 13) + A + b | 0; - x = A + x + (j >>> 6 ^ j >>> 11 ^ j >>> 25 ^ j << 26 ^ j << 21 ^ j << 7) + (B ^ j & (P ^ B)) + 0xc67178f2 | 0; - C = C + x | 0; - x = x + (S & E ^ M & (S ^ E)) + (S >>> 2 ^ S >>> 13 ^ S >>> 22 ^ S << 30 ^ S << 19 ^ S << 10) | 0; - n = n + x | 0; - i = i + S | 0; - a = a + E | 0; - s = s + M | 0; - o = o + C | 0; - u = u + j | 0; - f = f + P | 0; - c = c + B | 0 - } - - function B(e) { - e = e | 0; - P(j[e | 0] << 24 | j[e | 1] << 16 | j[e | 2] << 8 | j[e | 3], j[e | 4] << 24 | j[e | 5] << 16 | j[e | 6] << 8 | j[e | 7], j[e | 8] << 24 | j[e | 9] << 16 | j[e | 10] << 8 | j[e | 11], j[e | 12] << 24 | j[e | 13] << 16 | j[e | 14] << 8 | j[e | 15], j[e | 16] << 24 | j[e | 17] << 16 | j[e | 18] << 8 | j[e | 19], j[e | 20] << 24 | j[e | 21] << 16 | j[e | 22] << 8 | j[e | 23], j[e | 24] << 24 | j[e | 25] << 16 | j[e | 26] << 8 | j[e | 27], j[e | 28] << 24 | j[e | 29] << 16 | j[e | 30] << 8 | j[e | 31], j[e | 32] << 24 | j[e | 33] << 16 | j[e | 34] << 8 | j[e | 35], j[e | 36] << 24 | j[e | 37] << 16 | j[e | 38] << 8 | j[e | 39], j[e | 40] << 24 | j[e | 41] << 16 | j[e | 42] << 8 | j[e | 43], j[e | 44] << 24 | j[e | 45] << 16 | j[e | 46] << 8 | j[e | 47], j[e | 48] << 24 | j[e | 49] << 16 | j[e | 50] << 8 | j[e | 51], j[e | 52] << 24 | j[e | 53] << 16 | j[e | 54] << 8 | j[e | 55], j[e | 56] << 24 | j[e | 57] << 16 | j[e | 58] << 8 | j[e | 59], j[e | 60] << 24 | j[e | 61] << 16 | j[e | 62] << 8 | j[e | 63]) - } - - function U(e) { - e = e | 0; - j[e | 0] = n >>> 24; - j[e | 1] = n >>> 16 & 255; - j[e | 2] = n >>> 8 & 255; - j[e | 3] = n & 255; - j[e | 4] = i >>> 24; - j[e | 5] = i >>> 16 & 255; - j[e | 6] = i >>> 8 & 255; - j[e | 7] = i & 255; - j[e | 8] = a >>> 24; - j[e | 9] = a >>> 16 & 255; - j[e | 10] = a >>> 8 & 255; - j[e | 11] = a & 255; - j[e | 12] = s >>> 24; - j[e | 13] = s >>> 16 & 255; - j[e | 14] = s >>> 8 & 255; - j[e | 15] = s & 255; - j[e | 16] = o >>> 24; - j[e | 17] = o >>> 16 & 255; - j[e | 18] = o >>> 8 & 255; - j[e | 19] = o & 255; - j[e | 20] = u >>> 24; - j[e | 21] = u >>> 16 & 255; - j[e | 22] = u >>> 8 & 255; - j[e | 23] = u & 255; - j[e | 24] = f >>> 24; - j[e | 25] = f >>> 16 & 255; - j[e | 26] = f >>> 8 & 255; - j[e | 27] = f & 255; - j[e | 28] = c >>> 24; - j[e | 29] = c >>> 16 & 255; - j[e | 30] = c >>> 8 & 255; - j[e | 31] = c & 255 - } - - function K() { - n = 0x6a09e667; - i = 0xbb67ae85; - a = 0x3c6ef372; - s = 0xa54ff53a; - o = 0x510e527f; - u = 0x9b05688c; - f = 0x1f83d9ab; - c = 0x5be0cd19; - d = l = 0 - } - - function I(e, t, r, h, p, y, b, m, g, v) { - e = e | 0; - t = t | 0; - r = r | 0; - h = h | 0; - p = p | 0; - y = y | 0; - b = b | 0; - m = m | 0; - g = g | 0; - v = v | 0; - n = e; - i = t; - a = r; - s = h; - o = p; - u = y; - f = b; - c = m; - d = g; - l = v - } - - function T(e, t) { - e = e | 0; - t = t | 0; - var r = 0; - if (e & 63) return -1; - while ((t | 0) >= 64) { - B(e); - e = e + 64 | 0; - t = t - 64 | 0; - r = r + 64 | 0 - } - d = d + r | 0; - if (d >>> 0 < r >>> 0) l = l + 1 | 0; - return r | 0 - } - - function O(e, t, r) { - e = e | 0; - t = t | 0; - r = r | 0; - var n = 0, i = 0; - if (e & 63) return -1; - if (~r) if (r & 31) return -1; - if ((t | 0) >= 64) { - n = T(e, t) | 0; - if ((n | 0) == -1) return -1; - e = e + n | 0; - t = t - n | 0 - } - n = n + t | 0; - d = d + t | 0; - if (d >>> 0 < t >>> 0) l = l + 1 | 0; - j[e | t] = 0x80; - if ((t | 0) >= 56) { - for (i = t + 1 | 0; (i | 0) < 64; i = i + 1 | 0) { - j[e | i] = 0x00 - } - B(e); - t = 0; - j[e | 0] = 0 - } - for (i = t + 1 | 0; (i | 0) < 59; i = i + 1 | 0) { - j[e | i] = 0 - } - j[e | 56] = l >>> 21 & 255; - j[e | 57] = l >>> 13 & 255; - j[e | 58] = l >>> 5 & 255; - j[e | 59] = l << 3 & 255 | d >>> 29; - j[e | 60] = d >>> 21 & 255; - j[e | 61] = d >>> 13 & 255; - j[e | 62] = d >>> 5 & 255; - j[e | 63] = d << 3 & 255; - B(e); - if (~r) U(r); - return n | 0 - } - - function R() { - n = h; - i = p; - a = y; - s = b; - o = m; - u = g; - f = v; - c = _; - d = 64; - l = 0 - } - - function D() { - n = w; - i = k; - a = A; - s = x; - o = S; - u = E; - f = M; - c = C; - d = 64; - l = 0 - } - - function z(e, t, r, j, B, U, I, T, O, R, D, z, L, F, N, q) { - e = e | 0; - t = t | 0; - r = r | 0; - j = j | 0; - B = B | 0; - U = U | 0; - I = I | 0; - T = T | 0; - O = O | 0; - R = R | 0; - D = D | 0; - z = z | 0; - L = L | 0; - F = F | 0; - N = N | 0; - q = q | 0; - K(); - P(e ^ 0x5c5c5c5c, t ^ 0x5c5c5c5c, r ^ 0x5c5c5c5c, j ^ 0x5c5c5c5c, B ^ 0x5c5c5c5c, U ^ 0x5c5c5c5c, I ^ 0x5c5c5c5c, T ^ 0x5c5c5c5c, O ^ 0x5c5c5c5c, R ^ 0x5c5c5c5c, D ^ 0x5c5c5c5c, z ^ 0x5c5c5c5c, L ^ 0x5c5c5c5c, F ^ 0x5c5c5c5c, N ^ 0x5c5c5c5c, q ^ 0x5c5c5c5c); - w = n; - k = i; - A = a; - x = s; - S = o; - E = u; - M = f; - C = c; - K(); - P(e ^ 0x36363636, t ^ 0x36363636, r ^ 0x36363636, j ^ 0x36363636, B ^ 0x36363636, U ^ 0x36363636, I ^ 0x36363636, T ^ 0x36363636, O ^ 0x36363636, R ^ 0x36363636, D ^ 0x36363636, z ^ 0x36363636, L ^ 0x36363636, F ^ 0x36363636, N ^ 0x36363636, q ^ 0x36363636); - h = n; - p = i; - y = a; - b = s; - m = o; - g = u; - v = f; - _ = c; - d = 64; - l = 0 - } - - function L(e, t, r) { - e = e | 0; - t = t | 0; - r = r | 0; - var d = 0, l = 0, h = 0, p = 0, y = 0, b = 0, m = 0, g = 0, v = 0; - if (e & 63) return -1; - if (~r) if (r & 31) return -1; - v = O(e, t, -1) | 0; - d = n, l = i, h = a, p = s, y = o, b = u, m = f, g = c; - D(); - P(d, l, h, p, y, b, m, g, 0x80000000, 0, 0, 0, 0, 0, 0, 768); - if (~r) U(r); - return v | 0 - } - - function F(e, t, r, d, l) { - e = e | 0; - t = t | 0; - r = r | 0; - d = d | 0; - l = l | 0; - var h = 0, p = 0, y = 0, b = 0, m = 0, g = 0, v = 0, _ = 0, w = 0, k = 0, A = 0, x = 0, S = 0, - E = 0, M = 0, C = 0; - if (e & 63) return -1; - if (~l) if (l & 31) return -1; - j[e + t | 0] = r >>> 24; - j[e + t + 1 | 0] = r >>> 16 & 255; - j[e + t + 2 | 0] = r >>> 8 & 255; - j[e + t + 3 | 0] = r & 255; - L(e, t + 4 | 0, -1) | 0; - h = w = n, p = k = i, y = A = a, b = x = s, m = S = o, g = E = u, v = M = f, _ = C = c; - d = d - 1 | 0; - while ((d | 0) > 0) { - R(); - P(w, k, A, x, S, E, M, C, 0x80000000, 0, 0, 0, 0, 0, 0, 768); - w = n, k = i, A = a, x = s, S = o, E = u, M = f, C = c; - D(); - P(w, k, A, x, S, E, M, C, 0x80000000, 0, 0, 0, 0, 0, 0, 768); - w = n, k = i, A = a, x = s, S = o, E = u, M = f, C = c; - h = h ^ n; - p = p ^ i; - y = y ^ a; - b = b ^ s; - m = m ^ o; - g = g ^ u; - v = v ^ f; - _ = _ ^ c; - d = d - 1 | 0 - } - n = h; - i = p; - a = y; - s = b; - o = m; - u = g; - f = v; - c = _; - if (~l) U(l); - return 0 - } - - return { - reset: K, - init: I, - process: T, - finish: O, - hmac_reset: R, - hmac_init: z, - hmac_finish: L, - pbkdf2_generate_block: F - } - } - }, {}], - 17: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r._sha256_hash_size = r._sha256_block_size = void 0, r.sha256_constructor = u, r.get_sha256_instance = function () { - null === c && (c = new u({heapSize: 1048576})); - return c - }; - var n = e("./sha256.asm"), i = e("../hash"), a = e("../../utils"), s = r._sha256_block_size = 64, - o = r._sha256_hash_size = 32; - - function u(e) { - e = e || {}, this.heap = (0, a._heap_init)(Uint8Array, e.heap), this.asm = e.asm || (0, n.sha256_asm)({Uint8Array: Uint8Array}, null, this.heap.buffer), this.BLOCK_SIZE = s, this.HASH_SIZE = o, this.reset() - } - - u.BLOCK_SIZE = s, u.HASH_SIZE = o, u.NAME = "sha256"; - var f = u.prototype; - f.reset = i.hash_reset, f.process = i.hash_process, f.finish = i.hash_finish; - var c = null - }, {"../../utils": 18, "../hash": 14, "./sha256.asm": 16}], - 18: [function (e, t, r) { - "use strict"; - Object.defineProperty(r, "__esModule", {value: !0}), r.string_to_bytes = n, r.hex_to_bytes = function (e) { - var t = e.length; - 1 & t && (e = "0" + e, t++); - for (var r = new Uint8Array(t >> 1), n = 0; n < t; n += 2) r[n >> 1] = parseInt(e.substr(n, 2), 16); - return r - }, r.base64_to_bytes = function (e) { - return n(atob(e)) - }, r.bytes_to_string = i, r.bytes_to_hex = function (e) { - for (var t = "", r = 0; r < e.length; r++) { - var n = (255 & e[r]).toString(16); - n.length < 2 && (t += "0"), t += n - } - return t - }, r.bytes_to_base64 = function (e) { - return btoa(i(e)) - }, r.pow2_ceil = function (e) { - return e -= 1, e |= e >>> 1, e |= e >>> 2, e |= e >>> 4, e |= e >>> 8, e |= e >>> 16, e += 1 - }, r.is_number = function (e) { - return "number" == typeof e - }, r.is_string = function (e) { - return "string" == typeof e - }, r.is_buffer = function (e) { - return e instanceof ArrayBuffer - }, r.is_bytes = function (e) { - return e instanceof Uint8Array - }, r.is_typed_array = function (e) { - return e instanceof Int8Array || e instanceof Uint8Array || e instanceof Int16Array || e instanceof Uint16Array || e instanceof Int32Array || e instanceof Uint32Array || e instanceof Float32Array || e instanceof Float64Array - }, r._heap_init = function (e, t, r) { - var n = t ? t.byteLength : r || 65536; - if (4095 & n || n <= 0) throw new Error("heap size must be a positive integer and a multiple of 4096"); - return t = t || new e(new ArrayBuffer(n)) - }, r._heap_write = function (e, t, r, n, i) { - var a = e.length - t, s = a < i ? a : i; - return e.set(r.subarray(n, n + s), t), s - }; - r.FloatArray = "undefined" != typeof Float64Array ? Float64Array : Float32Array; - - function n(e, t) { - t = !!t; - for (var r = e.length, n = new Uint8Array(t ? 4 * r : r), i = 0, a = 0; i < r; i++) { - var s = e.charCodeAt(i); - if (t && 55296 <= s && s <= 56319) { - if (++i >= r) throw new Error("Malformed string, low surrogate expected at position " + i); - s = (55296 ^ s) << 10 | 65536 | 56320 ^ e.charCodeAt(i) - } else if (!t && s >>> 8) throw new Error("Wide characters are not allowed."); - !t || s <= 127 ? n[a++] = s : s <= 2047 ? (n[a++] = 192 | s >> 6, n[a++] = 128 | 63 & s) : s <= 65535 ? (n[a++] = 224 | s >> 12, n[a++] = 128 | s >> 6 & 63, n[a++] = 128 | 63 & s) : (n[a++] = 240 | s >> 18, n[a++] = 128 | s >> 12 & 63, n[a++] = 128 | s >> 6 & 63, n[a++] = 128 | 63 & s) - } - return n.subarray(0, a) - } - - function i(e, t) { - t = !!t; - for (var r = e.length, n = new Array(r), i = 0, a = 0; i < r; i++) { - var s = e[i]; - if (!t || s < 128) n[a++] = s; else if (s >= 192 && s < 224 && i + 1 < r) n[a++] = (31 & s) << 6 | 63 & e[++i]; else if (s >= 224 && s < 240 && i + 2 < r) n[a++] = (15 & s) << 12 | (63 & e[++i]) << 6 | 63 & e[++i]; else { - if (!(s >= 240 && s < 248 && i + 3 < r)) throw new Error("Malformed UTF8 character at byte offset " + i); - var o = (7 & s) << 18 | (63 & e[++i]) << 12 | (63 & e[++i]) << 6 | 63 & e[++i]; - o <= 65535 ? n[a++] = o : (o ^= 65536, n[a++] = 55296 | o >> 10, n[a++] = 56320 | 1023 & o) - } - } - var u = ""; - for (i = 0; i < a; i += 16384) u += String.fromCharCode.apply(String, n.slice(i, i + 16384 <= a ? i + 16384 : a)); - return u - } - }, {}], - 19: [function (e, t, r) { - t.exports = {default: e("core-js/library/fn/array/from"), __esModule: !0} - }, {"core-js/library/fn/array/from": 51}], - 20: [function (e, t, r) { - t.exports = {default: e("core-js/library/fn/get-iterator"), __esModule: !0} - }, {"core-js/library/fn/get-iterator": 52}], - 21: [function (e, t, r) { - t.exports = {default: e("core-js/library/fn/is-iterable"), __esModule: !0} - }, {"core-js/library/fn/is-iterable": 53}], - 22: [function (e, t, r) { - t.exports = {default: e("core-js/library/fn/json/stringify"), __esModule: !0} - }, {"core-js/library/fn/json/stringify": 54}], - 23: [function (e, t, r) { - t.exports = {default: e("core-js/library/fn/object/create"), __esModule: !0} - }, {"core-js/library/fn/object/create": 55}], - 24: [function (e, t, r) { - t.exports = {default: e("core-js/library/fn/object/define-property"), __esModule: !0} - }, {"core-js/library/fn/object/define-property": 56}], - 25: [function (e, t, r) { - t.exports = {default: e("core-js/library/fn/object/freeze"), __esModule: !0} - }, {"core-js/library/fn/object/freeze": 57}], - 26: [function (e, t, r) { - t.exports = {default: e("core-js/library/fn/object/get-prototype-of"), __esModule: !0} - }, {"core-js/library/fn/object/get-prototype-of": 58}], - 27: [function (e, t, r) { - t.exports = {default: e("core-js/library/fn/object/set-prototype-of"), __esModule: !0} - }, {"core-js/library/fn/object/set-prototype-of": 59}], - 28: [function (e, t, r) { - t.exports = {default: e("core-js/library/fn/promise"), __esModule: !0} - }, {"core-js/library/fn/promise": 60}], - 29: [function (e, t, r) { - t.exports = {default: e("core-js/library/fn/symbol"), __esModule: !0} - }, {"core-js/library/fn/symbol": 61}], - 30: [function (e, t, r) { - t.exports = {default: e("core-js/library/fn/symbol/iterator"), __esModule: !0} - }, {"core-js/library/fn/symbol/iterator": 62}], - 31: [function (e, t, r) { - "use strict"; - r.__esModule = !0; - var n, i = e("../core-js/promise"), a = (n = i) && n.__esModule ? n : {default: n}; - r.default = function (e) { - return function () { - var t = e.apply(this, arguments); - return new a.default(function (e, r) { - return function n(i, s) { - try { - var o = t[i](s), u = o.value - } catch (e) { - return void r(e) - } - if (!o.done) return a.default.resolve(u).then(function (e) { - n("next", e) - }, function (e) { - n("throw", e) - }); - e(u) - }("next") - }) - } - } - }, {"../core-js/promise": 28}], - 32: [function (e, t, r) { - "use strict"; - r.__esModule = !0, r.default = function (e, t) { - if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") - } - }, {}], - 33: [function (e, t, r) { - "use strict"; - r.__esModule = !0; - var n, i = e("../core-js/object/define-property"), a = (n = i) && n.__esModule ? n : {default: n}; - r.default = function () { - function e(e, t) { - for (var r = 0; r < t.length; r++) { - var n = t[r]; - n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), (0, a.default)(e, n.key, n) - } - } - - return function (t, r, n) { - return r && e(t.prototype, r), n && e(t, n), t - } - }() - }, {"../core-js/object/define-property": 24}], - 34: [function (e, t, r) { - "use strict"; - r.__esModule = !0; - var n = s(e("../core-js/object/set-prototype-of")), i = s(e("../core-js/object/create")), - a = s(e("../helpers/typeof")); - - function s(e) { - return e && e.__esModule ? e : {default: e} - } - - r.default = function (e, t) { - if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function, not " + (void 0 === t ? "undefined" : (0, a.default)(t))); - e.prototype = (0, i.default)(t && t.prototype, { - constructor: { - value: e, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), t && (n.default ? (0, n.default)(e, t) : e.__proto__ = t) - } - }, {"../core-js/object/create": 23, "../core-js/object/set-prototype-of": 27, "../helpers/typeof": 37}], - 35: [function (e, t, r) { - "use strict"; - r.__esModule = !0; - var n, i = e("../helpers/typeof"), a = (n = i) && n.__esModule ? n : {default: n}; - r.default = function (e, t) { - if (!e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !t || "object" !== (void 0 === t ? "undefined" : (0, a.default)(t)) && "function" != typeof t ? e : t - } - }, {"../helpers/typeof": 37}], - 36: [function (e, t, r) { - "use strict"; - r.__esModule = !0; - var n = a(e("../core-js/is-iterable")), i = a(e("../core-js/get-iterator")); - - function a(e) { - return e && e.__esModule ? e : {default: e} - } - - r.default = function () { - return function (e, t) { - if (Array.isArray(e)) return e; - if ((0, n.default)(Object(e))) return function (e, t) { - var r = [], n = !0, a = !1, s = void 0; - try { - for (var o, u = (0, i.default)(e); !(n = (o = u.next()).done) && (r.push(o.value), !t || r.length !== t); n = !0) ; - } catch (e) { - a = !0, s = e - } finally { - try { - !n && u.return && u.return() - } finally { - if (a) throw s - } - } - return r - }(e, t); - throw new TypeError("Invalid attempt to destructure non-iterable instance") - } - }() - }, {"../core-js/get-iterator": 20, "../core-js/is-iterable": 21}], - 37: [function (e, t, r) { - "use strict"; - r.__esModule = !0; - var n = s(e("../core-js/symbol/iterator")), i = s(e("../core-js/symbol")), - a = "function" == typeof i.default && "symbol" == typeof n.default ? function (e) { - return typeof e - } : function (e) { - return e && "function" == typeof i.default && e.constructor === i.default && e !== i.default.prototype ? "symbol" : typeof e - }; - - function s(e) { - return e && e.__esModule ? e : {default: e} - } - - r.default = "function" == typeof i.default && "symbol" === a(n.default) ? function (e) { - return void 0 === e ? "undefined" : a(e) - } : function (e) { - return e && "function" == typeof i.default && e.constructor === i.default && e !== i.default.prototype ? "symbol" : void 0 === e ? "undefined" : a(e) - } - }, {"../core-js/symbol": 29, "../core-js/symbol/iterator": 30}], - 38: [function (e, t, r) { - t.exports = e("regenerator-runtime") - }, {"regenerator-runtime": 302}], - 39: [function (e, t, r) { - "use strict"; - r.byteLength = function (e) { - return 3 * e.length / 4 - f(e) - }, r.toByteArray = function (e) { - var t, r, n, s, o, u = e.length; - s = f(e), o = new a(3 * u / 4 - s), r = s > 0 ? u - 4 : u; - var c = 0; - for (t = 0; t < r; t += 4) n = i[e.charCodeAt(t)] << 18 | i[e.charCodeAt(t + 1)] << 12 | i[e.charCodeAt(t + 2)] << 6 | i[e.charCodeAt(t + 3)], o[c++] = n >> 16 & 255, o[c++] = n >> 8 & 255, o[c++] = 255 & n; - 2 === s ? (n = i[e.charCodeAt(t)] << 2 | i[e.charCodeAt(t + 1)] >> 4, o[c++] = 255 & n) : 1 === s && (n = i[e.charCodeAt(t)] << 10 | i[e.charCodeAt(t + 1)] << 4 | i[e.charCodeAt(t + 2)] >> 2, o[c++] = n >> 8 & 255, o[c++] = 255 & n); - return o - }, r.fromByteArray = function (e) { - for (var t, r = e.length, i = r % 3, a = "", s = [], o = 0, u = r - i; o < u; o += 16383) s.push(c(e, o, o + 16383 > u ? u : o + 16383)); - 1 === i ? (t = e[r - 1], a += n[t >> 2], a += n[t << 4 & 63], a += "==") : 2 === i && (t = (e[r - 2] << 8) + e[r - 1], a += n[t >> 10], a += n[t >> 4 & 63], a += n[t << 2 & 63], a += "="); - return s.push(a), s.join("") - }; - for (var n = [], i = [], a = "undefined" != typeof Uint8Array ? Uint8Array : Array, s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", o = 0, u = s.length; o < u; ++o) n[o] = s[o], i[s.charCodeAt(o)] = o; - - function f(e) { - var t = e.length; - if (t % 4 > 0) throw new Error("Invalid string. Length must be a multiple of 4"); - return "=" === e[t - 2] ? 2 : "=" === e[t - 1] ? 1 : 0 - } - - function c(e, t, r) { - for (var i, a, s = [], o = t; o < r; o += 3) i = (e[o] << 16) + (e[o + 1] << 8) + e[o + 2], s.push(n[(a = i) >> 18 & 63] + n[a >> 12 & 63] + n[a >> 6 & 63] + n[63 & a]); - return s.join("") - } - - i["-".charCodeAt(0)] = 62, i["_".charCodeAt(0)] = 63 - }, {}], - 40: [function (e, t, r) { - !function (t, r) { - "use strict"; - - function n(e, t) { - if (!e) throw new Error(t || "Assertion failed") - } - - function i(e, t) { - e.super_ = t; - var r = function () { - }; - r.prototype = t.prototype, e.prototype = new r, e.prototype.constructor = e - } - - function a(e, t, r) { - if (a.isBN(e)) return e; - this.negative = 0, this.words = null, this.length = 0, this.red = null, null !== e && ("le" !== t && "be" !== t || (r = t, t = 10), this._init(e || 0, t || 10, r || "be")) - } - - var s; - "object" == typeof t ? t.exports = a : r.BN = a, a.BN = a, a.wordSize = 26; - try { - s = e("buffer").Buffer - } catch (e) { - } - - function o(e, t, r) { - for (var n = 0, i = Math.min(e.length, r), a = t; a < i; a++) { - var s = e.charCodeAt(a) - 48; - n <<= 4, n |= s >= 49 && s <= 54 ? s - 49 + 10 : s >= 17 && s <= 22 ? s - 17 + 10 : 15 & s - } - return n - } - - function u(e, t, r, n) { - for (var i = 0, a = Math.min(e.length, r), s = t; s < a; s++) { - var o = e.charCodeAt(s) - 48; - i *= n, i += o >= 49 ? o - 49 + 10 : o >= 17 ? o - 17 + 10 : o - } - return i - } - - a.isBN = function (e) { - return e instanceof a || null !== e && "object" == typeof e && e.constructor.wordSize === a.wordSize && Array.isArray(e.words) - }, a.max = function (e, t) { - return e.cmp(t) > 0 ? e : t - }, a.min = function (e, t) { - return e.cmp(t) < 0 ? e : t - }, a.prototype._init = function (e, t, r) { - if ("number" == typeof e) return this._initNumber(e, t, r); - if ("object" == typeof e) return this._initArray(e, t, r); - "hex" === t && (t = 16), n(t === (0 | t) && t >= 2 && t <= 36); - var i = 0; - "-" === (e = e.toString().replace(/\s+/g, ""))[0] && i++, 16 === t ? this._parseHex(e, i) : this._parseBase(e, t, i), "-" === e[0] && (this.negative = 1), this.strip(), "le" === r && this._initArray(this.toArray(), t, r) - }, a.prototype._initNumber = function (e, t, r) { - e < 0 && (this.negative = 1, e = -e), e < 67108864 ? (this.words = [67108863 & e], this.length = 1) : e < 4503599627370496 ? (this.words = [67108863 & e, e / 67108864 & 67108863], this.length = 2) : (n(e < 9007199254740992), this.words = [67108863 & e, e / 67108864 & 67108863, 1], this.length = 3), "le" === r && this._initArray(this.toArray(), t, r) - }, a.prototype._initArray = function (e, t, r) { - if (n("number" == typeof e.length), e.length <= 0) return this.words = [0], this.length = 1, this; - this.length = Math.ceil(e.length / 3), this.words = new Array(this.length); - for (var i = 0; i < this.length; i++) this.words[i] = 0; - var a, s, o = 0; - if ("be" === r) for (i = e.length - 1, a = 0; i >= 0; i -= 3) s = e[i] | e[i - 1] << 8 | e[i - 2] << 16, this.words[a] |= s << o & 67108863, this.words[a + 1] = s >>> 26 - o & 67108863, (o += 24) >= 26 && (o -= 26, a++); else if ("le" === r) for (i = 0, a = 0; i < e.length; i += 3) s = e[i] | e[i + 1] << 8 | e[i + 2] << 16, this.words[a] |= s << o & 67108863, this.words[a + 1] = s >>> 26 - o & 67108863, (o += 24) >= 26 && (o -= 26, a++); - return this.strip() - }, a.prototype._parseHex = function (e, t) { - this.length = Math.ceil((e.length - t) / 6), this.words = new Array(this.length); - for (var r = 0; r < this.length; r++) this.words[r] = 0; - var n, i, a = 0; - for (r = e.length - 6, n = 0; r >= t; r -= 6) i = o(e, r, r + 6), this.words[n] |= i << a & 67108863, this.words[n + 1] |= i >>> 26 - a & 4194303, (a += 24) >= 26 && (a -= 26, n++); - r + 6 !== t && (i = o(e, t, r + 6), this.words[n] |= i << a & 67108863, this.words[n + 1] |= i >>> 26 - a & 4194303), this.strip() - }, a.prototype._parseBase = function (e, t, r) { - this.words = [0], this.length = 1; - for (var n = 0, i = 1; i <= 67108863; i *= t) n++; - n--, i = i / t | 0; - for (var a = e.length - r, s = a % n, o = Math.min(a, a - s) + r, f = 0, c = r; c < o; c += n) f = u(e, c, c + n, t), this.imuln(i), this.words[0] + f < 67108864 ? this.words[0] += f : this._iaddn(f); - if (0 !== s) { - var d = 1; - for (f = u(e, c, e.length, t), c = 0; c < s; c++) d *= t; - this.imuln(d), this.words[0] + f < 67108864 ? this.words[0] += f : this._iaddn(f) - } - }, a.prototype.copy = function (e) { - e.words = new Array(this.length); - for (var t = 0; t < this.length; t++) e.words[t] = this.words[t]; - e.length = this.length, e.negative = this.negative, e.red = this.red - }, a.prototype.clone = function () { - var e = new a(null); - return this.copy(e), e - }, a.prototype._expand = function (e) { - for (; this.length < e;) this.words[this.length++] = 0; - return this - }, a.prototype.strip = function () { - for (; this.length > 1 && 0 === this.words[this.length - 1];) this.length--; - return this._normSign() - }, a.prototype._normSign = function () { - return 1 === this.length && 0 === this.words[0] && (this.negative = 0), this - }, a.prototype.inspect = function () { - return (this.red ? "" - }; - var f = ["", "0", "00", "000", "0000", "00000", "000000", "0000000", "00000000", "000000000", "0000000000", "00000000000", "000000000000", "0000000000000", "00000000000000", "000000000000000", "0000000000000000", "00000000000000000", "000000000000000000", "0000000000000000000", "00000000000000000000", "000000000000000000000", "0000000000000000000000", "00000000000000000000000", "000000000000000000000000", "0000000000000000000000000"], - c = [0, 0, 25, 16, 12, 11, 10, 9, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], - d = [0, 0, 33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216, 43046721, 1e7, 19487171, 35831808, 62748517, 7529536, 11390625, 16777216, 24137569, 34012224, 47045881, 64e6, 4084101, 5153632, 6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149, 243e5, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176]; - - function l(e, t, r) { - r.negative = t.negative ^ e.negative; - var n = e.length + t.length | 0; - r.length = n, n = n - 1 | 0; - var i = 0 | e.words[0], a = 0 | t.words[0], s = i * a, o = 67108863 & s, u = s / 67108864 | 0; - r.words[0] = o; - for (var f = 1; f < n; f++) { - for (var c = u >>> 26, d = 67108863 & u, l = Math.min(f, t.length - 1), h = Math.max(0, f - e.length + 1); h <= l; h++) { - var p = f - h | 0; - c += (s = (i = 0 | e.words[p]) * (a = 0 | t.words[h]) + d) / 67108864 | 0, d = 67108863 & s - } - r.words[f] = 0 | d, u = 0 | c - } - return 0 !== u ? r.words[f] = 0 | u : r.length--, r.strip() - } - - a.prototype.toString = function (e, t) { - var r; - if (e = e || 10, t = 0 | t || 1, 16 === e || "hex" === e) { - r = ""; - for (var i = 0, a = 0, s = 0; s < this.length; s++) { - var o = this.words[s], u = (16777215 & (o << i | a)).toString(16); - r = 0 !== (a = o >>> 24 - i & 16777215) || s !== this.length - 1 ? f[6 - u.length] + u + r : u + r, (i += 2) >= 26 && (i -= 26, s--) - } - for (0 !== a && (r = a.toString(16) + r); r.length % t != 0;) r = "0" + r; - return 0 !== this.negative && (r = "-" + r), r - } - if (e === (0 | e) && e >= 2 && e <= 36) { - var l = c[e], h = d[e]; - r = ""; - var p = this.clone(); - for (p.negative = 0; !p.isZero();) { - var y = p.modn(h).toString(e); - r = (p = p.idivn(h)).isZero() ? y + r : f[l - y.length] + y + r - } - for (this.isZero() && (r = "0" + r); r.length % t != 0;) r = "0" + r; - return 0 !== this.negative && (r = "-" + r), r - } - n(!1, "Base should be between 2 and 36") - }, a.prototype.toNumber = function () { - var e = this.words[0]; - return 2 === this.length ? e += 67108864 * this.words[1] : 3 === this.length && 1 === this.words[2] ? e += 4503599627370496 + 67108864 * this.words[1] : this.length > 2 && n(!1, "Number can only safely store up to 53 bits"), 0 !== this.negative ? -e : e - }, a.prototype.toJSON = function () { - return this.toString(16) - }, a.prototype.toBuffer = function (e, t) { - return n(void 0 !== s), this.toArrayLike(s, e, t) - }, a.prototype.toArray = function (e, t) { - return this.toArrayLike(Array, e, t) - }, a.prototype.toArrayLike = function (e, t, r) { - var i = this.byteLength(), a = r || Math.max(1, i); - n(i <= a, "byte array longer than desired length"), n(a > 0, "Requested array length <= 0"), this.strip(); - var s, o, u = "le" === t, f = new e(a), c = this.clone(); - if (u) { - for (o = 0; !c.isZero(); o++) s = c.andln(255), c.iushrn(8), f[o] = s; - for (; o < a; o++) f[o] = 0 - } else { - for (o = 0; o < a - i; o++) f[o] = 0; - for (o = 0; !c.isZero(); o++) s = c.andln(255), c.iushrn(8), f[a - o - 1] = s - } - return f - }, Math.clz32 ? a.prototype._countBits = function (e) { - return 32 - Math.clz32(e) - } : a.prototype._countBits = function (e) { - var t = e, r = 0; - return t >= 4096 && (r += 13, t >>>= 13), t >= 64 && (r += 7, t >>>= 7), t >= 8 && (r += 4, t >>>= 4), t >= 2 && (r += 2, t >>>= 2), r + t - }, a.prototype._zeroBits = function (e) { - if (0 === e) return 26; - var t = e, r = 0; - return 0 == (8191 & t) && (r += 13, t >>>= 13), 0 == (127 & t) && (r += 7, t >>>= 7), 0 == (15 & t) && (r += 4, t >>>= 4), 0 == (3 & t) && (r += 2, t >>>= 2), 0 == (1 & t) && r++, r - }, a.prototype.bitLength = function () { - var e = this.words[this.length - 1], t = this._countBits(e); - return 26 * (this.length - 1) + t - }, a.prototype.zeroBits = function () { - if (this.isZero()) return 0; - for (var e = 0, t = 0; t < this.length; t++) { - var r = this._zeroBits(this.words[t]); - if (e += r, 26 !== r) break - } - return e - }, a.prototype.byteLength = function () { - return Math.ceil(this.bitLength() / 8) - }, a.prototype.toTwos = function (e) { - return 0 !== this.negative ? this.abs().inotn(e).iaddn(1) : this.clone() - }, a.prototype.fromTwos = function (e) { - return this.testn(e - 1) ? this.notn(e).iaddn(1).ineg() : this.clone() - }, a.prototype.isNeg = function () { - return 0 !== this.negative - }, a.prototype.neg = function () { - return this.clone().ineg() - }, a.prototype.ineg = function () { - return this.isZero() || (this.negative ^= 1), this - }, a.prototype.iuor = function (e) { - for (; this.length < e.length;) this.words[this.length++] = 0; - for (var t = 0; t < e.length; t++) this.words[t] = this.words[t] | e.words[t]; - return this.strip() - }, a.prototype.ior = function (e) { - return n(0 == (this.negative | e.negative)), this.iuor(e) - }, a.prototype.or = function (e) { - return this.length > e.length ? this.clone().ior(e) : e.clone().ior(this) - }, a.prototype.uor = function (e) { - return this.length > e.length ? this.clone().iuor(e) : e.clone().iuor(this) - }, a.prototype.iuand = function (e) { - var t; - t = this.length > e.length ? e : this; - for (var r = 0; r < t.length; r++) this.words[r] = this.words[r] & e.words[r]; - return this.length = t.length, this.strip() - }, a.prototype.iand = function (e) { - return n(0 == (this.negative | e.negative)), this.iuand(e) - }, a.prototype.and = function (e) { - return this.length > e.length ? this.clone().iand(e) : e.clone().iand(this) - }, a.prototype.uand = function (e) { - return this.length > e.length ? this.clone().iuand(e) : e.clone().iuand(this) - }, a.prototype.iuxor = function (e) { - var t, r; - this.length > e.length ? (t = this, r = e) : (t = e, r = this); - for (var n = 0; n < r.length; n++) this.words[n] = t.words[n] ^ r.words[n]; - if (this !== t) for (; n < t.length; n++) this.words[n] = t.words[n]; - return this.length = t.length, this.strip() - }, a.prototype.ixor = function (e) { - return n(0 == (this.negative | e.negative)), this.iuxor(e) - }, a.prototype.xor = function (e) { - return this.length > e.length ? this.clone().ixor(e) : e.clone().ixor(this) - }, a.prototype.uxor = function (e) { - return this.length > e.length ? this.clone().iuxor(e) : e.clone().iuxor(this) - }, a.prototype.inotn = function (e) { - n("number" == typeof e && e >= 0); - var t = 0 | Math.ceil(e / 26), r = e % 26; - this._expand(t), r > 0 && t--; - for (var i = 0; i < t; i++) this.words[i] = 67108863 & ~this.words[i]; - return r > 0 && (this.words[i] = ~this.words[i] & 67108863 >> 26 - r), this.strip() - }, a.prototype.notn = function (e) { - return this.clone().inotn(e) - }, a.prototype.setn = function (e, t) { - n("number" == typeof e && e >= 0); - var r = e / 26 | 0, i = e % 26; - return this._expand(r + 1), this.words[r] = t ? this.words[r] | 1 << i : this.words[r] & ~(1 << i), this.strip() - }, a.prototype.iadd = function (e) { - var t, r, n; - if (0 !== this.negative && 0 === e.negative) return this.negative = 0, t = this.isub(e), this.negative ^= 1, this._normSign(); - if (0 === this.negative && 0 !== e.negative) return e.negative = 0, t = this.isub(e), e.negative = 1, t._normSign(); - this.length > e.length ? (r = this, n = e) : (r = e, n = this); - for (var i = 0, a = 0; a < n.length; a++) t = (0 | r.words[a]) + (0 | n.words[a]) + i, this.words[a] = 67108863 & t, i = t >>> 26; - for (; 0 !== i && a < r.length; a++) t = (0 | r.words[a]) + i, this.words[a] = 67108863 & t, i = t >>> 26; - if (this.length = r.length, 0 !== i) this.words[this.length] = i, this.length++; else if (r !== this) for (; a < r.length; a++) this.words[a] = r.words[a]; - return this - }, a.prototype.add = function (e) { - var t; - return 0 !== e.negative && 0 === this.negative ? (e.negative = 0, t = this.sub(e), e.negative ^= 1, t) : 0 === e.negative && 0 !== this.negative ? (this.negative = 0, t = e.sub(this), this.negative = 1, t) : this.length > e.length ? this.clone().iadd(e) : e.clone().iadd(this) - }, a.prototype.isub = function (e) { - if (0 !== e.negative) { - e.negative = 0; - var t = this.iadd(e); - return e.negative = 1, t._normSign() - } - if (0 !== this.negative) return this.negative = 0, this.iadd(e), this.negative = 1, this._normSign(); - var r, n, i = this.cmp(e); - if (0 === i) return this.negative = 0, this.length = 1, this.words[0] = 0, this; - i > 0 ? (r = this, n = e) : (r = e, n = this); - for (var a = 0, s = 0; s < n.length; s++) a = (t = (0 | r.words[s]) - (0 | n.words[s]) + a) >> 26, this.words[s] = 67108863 & t; - for (; 0 !== a && s < r.length; s++) a = (t = (0 | r.words[s]) + a) >> 26, this.words[s] = 67108863 & t; - if (0 === a && s < r.length && r !== this) for (; s < r.length; s++) this.words[s] = r.words[s]; - return this.length = Math.max(this.length, s), r !== this && (this.negative = 1), this.strip() - }, a.prototype.sub = function (e) { - return this.clone().isub(e) - }; - var h = function (e, t, r) { - var n, i, a, s = e.words, o = t.words, u = r.words, f = 0, c = 0 | s[0], d = 8191 & c, l = c >>> 13, - h = 0 | s[1], p = 8191 & h, y = h >>> 13, b = 0 | s[2], m = 8191 & b, g = b >>> 13, - v = 0 | s[3], _ = 8191 & v, w = v >>> 13, k = 0 | s[4], A = 8191 & k, x = k >>> 13, - S = 0 | s[5], E = 8191 & S, M = S >>> 13, C = 0 | s[6], j = 8191 & C, P = C >>> 13, - B = 0 | s[7], U = 8191 & B, K = B >>> 13, I = 0 | s[8], T = 8191 & I, O = I >>> 13, - R = 0 | s[9], D = 8191 & R, z = R >>> 13, L = 0 | o[0], F = 8191 & L, N = L >>> 13, - q = 0 | o[1], G = 8191 & q, H = q >>> 13, Z = 0 | o[2], V = 8191 & Z, W = Z >>> 13, - Y = 0 | o[3], X = 8191 & Y, J = Y >>> 13, $ = 0 | o[4], Q = 8191 & $, ee = $ >>> 13, - te = 0 | o[5], re = 8191 & te, ne = te >>> 13, ie = 0 | o[6], ae = 8191 & ie, se = ie >>> 13, - oe = 0 | o[7], ue = 8191 & oe, fe = oe >>> 13, ce = 0 | o[8], de = 8191 & ce, le = ce >>> 13, - he = 0 | o[9], pe = 8191 & he, ye = he >>> 13; - r.negative = e.negative ^ t.negative, r.length = 19; - var be = (f + (n = Math.imul(d, F)) | 0) + ((8191 & (i = (i = Math.imul(d, N)) + Math.imul(l, F) | 0)) << 13) | 0; - f = ((a = Math.imul(l, N)) + (i >>> 13) | 0) + (be >>> 26) | 0, be &= 67108863, n = Math.imul(p, F), i = (i = Math.imul(p, N)) + Math.imul(y, F) | 0, a = Math.imul(y, N); - var me = (f + (n = n + Math.imul(d, G) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(d, H) | 0) + Math.imul(l, G) | 0)) << 13) | 0; - f = ((a = a + Math.imul(l, H) | 0) + (i >>> 13) | 0) + (me >>> 26) | 0, me &= 67108863, n = Math.imul(m, F), i = (i = Math.imul(m, N)) + Math.imul(g, F) | 0, a = Math.imul(g, N), n = n + Math.imul(p, G) | 0, i = (i = i + Math.imul(p, H) | 0) + Math.imul(y, G) | 0, a = a + Math.imul(y, H) | 0; - var ge = (f + (n = n + Math.imul(d, V) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(d, W) | 0) + Math.imul(l, V) | 0)) << 13) | 0; - f = ((a = a + Math.imul(l, W) | 0) + (i >>> 13) | 0) + (ge >>> 26) | 0, ge &= 67108863, n = Math.imul(_, F), i = (i = Math.imul(_, N)) + Math.imul(w, F) | 0, a = Math.imul(w, N), n = n + Math.imul(m, G) | 0, i = (i = i + Math.imul(m, H) | 0) + Math.imul(g, G) | 0, a = a + Math.imul(g, H) | 0, n = n + Math.imul(p, V) | 0, i = (i = i + Math.imul(p, W) | 0) + Math.imul(y, V) | 0, a = a + Math.imul(y, W) | 0; - var ve = (f + (n = n + Math.imul(d, X) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(d, J) | 0) + Math.imul(l, X) | 0)) << 13) | 0; - f = ((a = a + Math.imul(l, J) | 0) + (i >>> 13) | 0) + (ve >>> 26) | 0, ve &= 67108863, n = Math.imul(A, F), i = (i = Math.imul(A, N)) + Math.imul(x, F) | 0, a = Math.imul(x, N), n = n + Math.imul(_, G) | 0, i = (i = i + Math.imul(_, H) | 0) + Math.imul(w, G) | 0, a = a + Math.imul(w, H) | 0, n = n + Math.imul(m, V) | 0, i = (i = i + Math.imul(m, W) | 0) + Math.imul(g, V) | 0, a = a + Math.imul(g, W) | 0, n = n + Math.imul(p, X) | 0, i = (i = i + Math.imul(p, J) | 0) + Math.imul(y, X) | 0, a = a + Math.imul(y, J) | 0; - var _e = (f + (n = n + Math.imul(d, Q) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(d, ee) | 0) + Math.imul(l, Q) | 0)) << 13) | 0; - f = ((a = a + Math.imul(l, ee) | 0) + (i >>> 13) | 0) + (_e >>> 26) | 0, _e &= 67108863, n = Math.imul(E, F), i = (i = Math.imul(E, N)) + Math.imul(M, F) | 0, a = Math.imul(M, N), n = n + Math.imul(A, G) | 0, i = (i = i + Math.imul(A, H) | 0) + Math.imul(x, G) | 0, a = a + Math.imul(x, H) | 0, n = n + Math.imul(_, V) | 0, i = (i = i + Math.imul(_, W) | 0) + Math.imul(w, V) | 0, a = a + Math.imul(w, W) | 0, n = n + Math.imul(m, X) | 0, i = (i = i + Math.imul(m, J) | 0) + Math.imul(g, X) | 0, a = a + Math.imul(g, J) | 0, n = n + Math.imul(p, Q) | 0, i = (i = i + Math.imul(p, ee) | 0) + Math.imul(y, Q) | 0, a = a + Math.imul(y, ee) | 0; - var we = (f + (n = n + Math.imul(d, re) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(d, ne) | 0) + Math.imul(l, re) | 0)) << 13) | 0; - f = ((a = a + Math.imul(l, ne) | 0) + (i >>> 13) | 0) + (we >>> 26) | 0, we &= 67108863, n = Math.imul(j, F), i = (i = Math.imul(j, N)) + Math.imul(P, F) | 0, a = Math.imul(P, N), n = n + Math.imul(E, G) | 0, i = (i = i + Math.imul(E, H) | 0) + Math.imul(M, G) | 0, a = a + Math.imul(M, H) | 0, n = n + Math.imul(A, V) | 0, i = (i = i + Math.imul(A, W) | 0) + Math.imul(x, V) | 0, a = a + Math.imul(x, W) | 0, n = n + Math.imul(_, X) | 0, i = (i = i + Math.imul(_, J) | 0) + Math.imul(w, X) | 0, a = a + Math.imul(w, J) | 0, n = n + Math.imul(m, Q) | 0, i = (i = i + Math.imul(m, ee) | 0) + Math.imul(g, Q) | 0, a = a + Math.imul(g, ee) | 0, n = n + Math.imul(p, re) | 0, i = (i = i + Math.imul(p, ne) | 0) + Math.imul(y, re) | 0, a = a + Math.imul(y, ne) | 0; - var ke = (f + (n = n + Math.imul(d, ae) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(d, se) | 0) + Math.imul(l, ae) | 0)) << 13) | 0; - f = ((a = a + Math.imul(l, se) | 0) + (i >>> 13) | 0) + (ke >>> 26) | 0, ke &= 67108863, n = Math.imul(U, F), i = (i = Math.imul(U, N)) + Math.imul(K, F) | 0, a = Math.imul(K, N), n = n + Math.imul(j, G) | 0, i = (i = i + Math.imul(j, H) | 0) + Math.imul(P, G) | 0, a = a + Math.imul(P, H) | 0, n = n + Math.imul(E, V) | 0, i = (i = i + Math.imul(E, W) | 0) + Math.imul(M, V) | 0, a = a + Math.imul(M, W) | 0, n = n + Math.imul(A, X) | 0, i = (i = i + Math.imul(A, J) | 0) + Math.imul(x, X) | 0, a = a + Math.imul(x, J) | 0, n = n + Math.imul(_, Q) | 0, i = (i = i + Math.imul(_, ee) | 0) + Math.imul(w, Q) | 0, a = a + Math.imul(w, ee) | 0, n = n + Math.imul(m, re) | 0, i = (i = i + Math.imul(m, ne) | 0) + Math.imul(g, re) | 0, a = a + Math.imul(g, ne) | 0, n = n + Math.imul(p, ae) | 0, i = (i = i + Math.imul(p, se) | 0) + Math.imul(y, ae) | 0, a = a + Math.imul(y, se) | 0; - var Ae = (f + (n = n + Math.imul(d, ue) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(d, fe) | 0) + Math.imul(l, ue) | 0)) << 13) | 0; - f = ((a = a + Math.imul(l, fe) | 0) + (i >>> 13) | 0) + (Ae >>> 26) | 0, Ae &= 67108863, n = Math.imul(T, F), i = (i = Math.imul(T, N)) + Math.imul(O, F) | 0, a = Math.imul(O, N), n = n + Math.imul(U, G) | 0, i = (i = i + Math.imul(U, H) | 0) + Math.imul(K, G) | 0, a = a + Math.imul(K, H) | 0, n = n + Math.imul(j, V) | 0, i = (i = i + Math.imul(j, W) | 0) + Math.imul(P, V) | 0, a = a + Math.imul(P, W) | 0, n = n + Math.imul(E, X) | 0, i = (i = i + Math.imul(E, J) | 0) + Math.imul(M, X) | 0, a = a + Math.imul(M, J) | 0, n = n + Math.imul(A, Q) | 0, i = (i = i + Math.imul(A, ee) | 0) + Math.imul(x, Q) | 0, a = a + Math.imul(x, ee) | 0, n = n + Math.imul(_, re) | 0, i = (i = i + Math.imul(_, ne) | 0) + Math.imul(w, re) | 0, a = a + Math.imul(w, ne) | 0, n = n + Math.imul(m, ae) | 0, i = (i = i + Math.imul(m, se) | 0) + Math.imul(g, ae) | 0, a = a + Math.imul(g, se) | 0, n = n + Math.imul(p, ue) | 0, i = (i = i + Math.imul(p, fe) | 0) + Math.imul(y, ue) | 0, a = a + Math.imul(y, fe) | 0; - var xe = (f + (n = n + Math.imul(d, de) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(d, le) | 0) + Math.imul(l, de) | 0)) << 13) | 0; - f = ((a = a + Math.imul(l, le) | 0) + (i >>> 13) | 0) + (xe >>> 26) | 0, xe &= 67108863, n = Math.imul(D, F), i = (i = Math.imul(D, N)) + Math.imul(z, F) | 0, a = Math.imul(z, N), n = n + Math.imul(T, G) | 0, i = (i = i + Math.imul(T, H) | 0) + Math.imul(O, G) | 0, a = a + Math.imul(O, H) | 0, n = n + Math.imul(U, V) | 0, i = (i = i + Math.imul(U, W) | 0) + Math.imul(K, V) | 0, a = a + Math.imul(K, W) | 0, n = n + Math.imul(j, X) | 0, i = (i = i + Math.imul(j, J) | 0) + Math.imul(P, X) | 0, a = a + Math.imul(P, J) | 0, n = n + Math.imul(E, Q) | 0, i = (i = i + Math.imul(E, ee) | 0) + Math.imul(M, Q) | 0, a = a + Math.imul(M, ee) | 0, n = n + Math.imul(A, re) | 0, i = (i = i + Math.imul(A, ne) | 0) + Math.imul(x, re) | 0, a = a + Math.imul(x, ne) | 0, n = n + Math.imul(_, ae) | 0, i = (i = i + Math.imul(_, se) | 0) + Math.imul(w, ae) | 0, a = a + Math.imul(w, se) | 0, n = n + Math.imul(m, ue) | 0, i = (i = i + Math.imul(m, fe) | 0) + Math.imul(g, ue) | 0, a = a + Math.imul(g, fe) | 0, n = n + Math.imul(p, de) | 0, i = (i = i + Math.imul(p, le) | 0) + Math.imul(y, de) | 0, a = a + Math.imul(y, le) | 0; - var Se = (f + (n = n + Math.imul(d, pe) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(d, ye) | 0) + Math.imul(l, pe) | 0)) << 13) | 0; - f = ((a = a + Math.imul(l, ye) | 0) + (i >>> 13) | 0) + (Se >>> 26) | 0, Se &= 67108863, n = Math.imul(D, G), i = (i = Math.imul(D, H)) + Math.imul(z, G) | 0, a = Math.imul(z, H), n = n + Math.imul(T, V) | 0, i = (i = i + Math.imul(T, W) | 0) + Math.imul(O, V) | 0, a = a + Math.imul(O, W) | 0, n = n + Math.imul(U, X) | 0, i = (i = i + Math.imul(U, J) | 0) + Math.imul(K, X) | 0, a = a + Math.imul(K, J) | 0, n = n + Math.imul(j, Q) | 0, i = (i = i + Math.imul(j, ee) | 0) + Math.imul(P, Q) | 0, a = a + Math.imul(P, ee) | 0, n = n + Math.imul(E, re) | 0, i = (i = i + Math.imul(E, ne) | 0) + Math.imul(M, re) | 0, a = a + Math.imul(M, ne) | 0, n = n + Math.imul(A, ae) | 0, i = (i = i + Math.imul(A, se) | 0) + Math.imul(x, ae) | 0, a = a + Math.imul(x, se) | 0, n = n + Math.imul(_, ue) | 0, i = (i = i + Math.imul(_, fe) | 0) + Math.imul(w, ue) | 0, a = a + Math.imul(w, fe) | 0, n = n + Math.imul(m, de) | 0, i = (i = i + Math.imul(m, le) | 0) + Math.imul(g, de) | 0, a = a + Math.imul(g, le) | 0; - var Ee = (f + (n = n + Math.imul(p, pe) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(p, ye) | 0) + Math.imul(y, pe) | 0)) << 13) | 0; - f = ((a = a + Math.imul(y, ye) | 0) + (i >>> 13) | 0) + (Ee >>> 26) | 0, Ee &= 67108863, n = Math.imul(D, V), i = (i = Math.imul(D, W)) + Math.imul(z, V) | 0, a = Math.imul(z, W), n = n + Math.imul(T, X) | 0, i = (i = i + Math.imul(T, J) | 0) + Math.imul(O, X) | 0, a = a + Math.imul(O, J) | 0, n = n + Math.imul(U, Q) | 0, i = (i = i + Math.imul(U, ee) | 0) + Math.imul(K, Q) | 0, a = a + Math.imul(K, ee) | 0, n = n + Math.imul(j, re) | 0, i = (i = i + Math.imul(j, ne) | 0) + Math.imul(P, re) | 0, a = a + Math.imul(P, ne) | 0, n = n + Math.imul(E, ae) | 0, i = (i = i + Math.imul(E, se) | 0) + Math.imul(M, ae) | 0, a = a + Math.imul(M, se) | 0, n = n + Math.imul(A, ue) | 0, i = (i = i + Math.imul(A, fe) | 0) + Math.imul(x, ue) | 0, a = a + Math.imul(x, fe) | 0, n = n + Math.imul(_, de) | 0, i = (i = i + Math.imul(_, le) | 0) + Math.imul(w, de) | 0, a = a + Math.imul(w, le) | 0; - var Me = (f + (n = n + Math.imul(m, pe) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(m, ye) | 0) + Math.imul(g, pe) | 0)) << 13) | 0; - f = ((a = a + Math.imul(g, ye) | 0) + (i >>> 13) | 0) + (Me >>> 26) | 0, Me &= 67108863, n = Math.imul(D, X), i = (i = Math.imul(D, J)) + Math.imul(z, X) | 0, a = Math.imul(z, J), n = n + Math.imul(T, Q) | 0, i = (i = i + Math.imul(T, ee) | 0) + Math.imul(O, Q) | 0, a = a + Math.imul(O, ee) | 0, n = n + Math.imul(U, re) | 0, i = (i = i + Math.imul(U, ne) | 0) + Math.imul(K, re) | 0, a = a + Math.imul(K, ne) | 0, n = n + Math.imul(j, ae) | 0, i = (i = i + Math.imul(j, se) | 0) + Math.imul(P, ae) | 0, a = a + Math.imul(P, se) | 0, n = n + Math.imul(E, ue) | 0, i = (i = i + Math.imul(E, fe) | 0) + Math.imul(M, ue) | 0, a = a + Math.imul(M, fe) | 0, n = n + Math.imul(A, de) | 0, i = (i = i + Math.imul(A, le) | 0) + Math.imul(x, de) | 0, a = a + Math.imul(x, le) | 0; - var Ce = (f + (n = n + Math.imul(_, pe) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(_, ye) | 0) + Math.imul(w, pe) | 0)) << 13) | 0; - f = ((a = a + Math.imul(w, ye) | 0) + (i >>> 13) | 0) + (Ce >>> 26) | 0, Ce &= 67108863, n = Math.imul(D, Q), i = (i = Math.imul(D, ee)) + Math.imul(z, Q) | 0, a = Math.imul(z, ee), n = n + Math.imul(T, re) | 0, i = (i = i + Math.imul(T, ne) | 0) + Math.imul(O, re) | 0, a = a + Math.imul(O, ne) | 0, n = n + Math.imul(U, ae) | 0, i = (i = i + Math.imul(U, se) | 0) + Math.imul(K, ae) | 0, a = a + Math.imul(K, se) | 0, n = n + Math.imul(j, ue) | 0, i = (i = i + Math.imul(j, fe) | 0) + Math.imul(P, ue) | 0, a = a + Math.imul(P, fe) | 0, n = n + Math.imul(E, de) | 0, i = (i = i + Math.imul(E, le) | 0) + Math.imul(M, de) | 0, a = a + Math.imul(M, le) | 0; - var je = (f + (n = n + Math.imul(A, pe) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(A, ye) | 0) + Math.imul(x, pe) | 0)) << 13) | 0; - f = ((a = a + Math.imul(x, ye) | 0) + (i >>> 13) | 0) + (je >>> 26) | 0, je &= 67108863, n = Math.imul(D, re), i = (i = Math.imul(D, ne)) + Math.imul(z, re) | 0, a = Math.imul(z, ne), n = n + Math.imul(T, ae) | 0, i = (i = i + Math.imul(T, se) | 0) + Math.imul(O, ae) | 0, a = a + Math.imul(O, se) | 0, n = n + Math.imul(U, ue) | 0, i = (i = i + Math.imul(U, fe) | 0) + Math.imul(K, ue) | 0, a = a + Math.imul(K, fe) | 0, n = n + Math.imul(j, de) | 0, i = (i = i + Math.imul(j, le) | 0) + Math.imul(P, de) | 0, a = a + Math.imul(P, le) | 0; - var Pe = (f + (n = n + Math.imul(E, pe) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(E, ye) | 0) + Math.imul(M, pe) | 0)) << 13) | 0; - f = ((a = a + Math.imul(M, ye) | 0) + (i >>> 13) | 0) + (Pe >>> 26) | 0, Pe &= 67108863, n = Math.imul(D, ae), i = (i = Math.imul(D, se)) + Math.imul(z, ae) | 0, a = Math.imul(z, se), n = n + Math.imul(T, ue) | 0, i = (i = i + Math.imul(T, fe) | 0) + Math.imul(O, ue) | 0, a = a + Math.imul(O, fe) | 0, n = n + Math.imul(U, de) | 0, i = (i = i + Math.imul(U, le) | 0) + Math.imul(K, de) | 0, a = a + Math.imul(K, le) | 0; - var Be = (f + (n = n + Math.imul(j, pe) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(j, ye) | 0) + Math.imul(P, pe) | 0)) << 13) | 0; - f = ((a = a + Math.imul(P, ye) | 0) + (i >>> 13) | 0) + (Be >>> 26) | 0, Be &= 67108863, n = Math.imul(D, ue), i = (i = Math.imul(D, fe)) + Math.imul(z, ue) | 0, a = Math.imul(z, fe), n = n + Math.imul(T, de) | 0, i = (i = i + Math.imul(T, le) | 0) + Math.imul(O, de) | 0, a = a + Math.imul(O, le) | 0; - var Ue = (f + (n = n + Math.imul(U, pe) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(U, ye) | 0) + Math.imul(K, pe) | 0)) << 13) | 0; - f = ((a = a + Math.imul(K, ye) | 0) + (i >>> 13) | 0) + (Ue >>> 26) | 0, Ue &= 67108863, n = Math.imul(D, de), i = (i = Math.imul(D, le)) + Math.imul(z, de) | 0, a = Math.imul(z, le); - var Ke = (f + (n = n + Math.imul(T, pe) | 0) | 0) + ((8191 & (i = (i = i + Math.imul(T, ye) | 0) + Math.imul(O, pe) | 0)) << 13) | 0; - f = ((a = a + Math.imul(O, ye) | 0) + (i >>> 13) | 0) + (Ke >>> 26) | 0, Ke &= 67108863; - var Ie = (f + (n = Math.imul(D, pe)) | 0) + ((8191 & (i = (i = Math.imul(D, ye)) + Math.imul(z, pe) | 0)) << 13) | 0; - return f = ((a = Math.imul(z, ye)) + (i >>> 13) | 0) + (Ie >>> 26) | 0, Ie &= 67108863, u[0] = be, u[1] = me, u[2] = ge, u[3] = ve, u[4] = _e, u[5] = we, u[6] = ke, u[7] = Ae, u[8] = xe, u[9] = Se, u[10] = Ee, u[11] = Me, u[12] = Ce, u[13] = je, u[14] = Pe, u[15] = Be, u[16] = Ue, u[17] = Ke, u[18] = Ie, 0 !== f && (u[19] = f, r.length++), r - }; - - function p(e, t, r) { - return (new y).mulp(e, t, r) - } - - function y(e, t) { - this.x = e, this.y = t - } - - Math.imul || (h = l), a.prototype.mulTo = function (e, t) { - var r = this.length + e.length; - return 10 === this.length && 10 === e.length ? h(this, e, t) : r < 63 ? l(this, e, t) : r < 1024 ? function (e, t, r) { - r.negative = t.negative ^ e.negative, r.length = e.length + t.length; - for (var n = 0, i = 0, a = 0; a < r.length - 1; a++) { - var s = i; - i = 0; - for (var o = 67108863 & n, u = Math.min(a, t.length - 1), f = Math.max(0, a - e.length + 1); f <= u; f++) { - var c = a - f, d = (0 | e.words[c]) * (0 | t.words[f]), l = 67108863 & d; - o = 67108863 & (l = l + o | 0), i += (s = (s = s + (d / 67108864 | 0) | 0) + (l >>> 26) | 0) >>> 26, s &= 67108863 - } - r.words[a] = o, n = s, s = i - } - return 0 !== n ? r.words[a] = n : r.length--, r.strip() - }(this, e, t) : p(this, e, t) - }, y.prototype.makeRBT = function (e) { - for (var t = new Array(e), r = a.prototype._countBits(e) - 1, n = 0; n < e; n++) t[n] = this.revBin(n, r, e); - return t - }, y.prototype.revBin = function (e, t, r) { - if (0 === e || e === r - 1) return e; - for (var n = 0, i = 0; i < t; i++) n |= (1 & e) << t - i - 1, e >>= 1; - return n - }, y.prototype.permute = function (e, t, r, n, i, a) { - for (var s = 0; s < a; s++) n[s] = t[e[s]], i[s] = r[e[s]] - }, y.prototype.transform = function (e, t, r, n, i, a) { - this.permute(a, e, t, r, n, i); - for (var s = 1; s < i; s <<= 1) for (var o = s << 1, u = Math.cos(2 * Math.PI / o), f = Math.sin(2 * Math.PI / o), c = 0; c < i; c += o) for (var d = u, l = f, h = 0; h < s; h++) { - var p = r[c + h], y = n[c + h], b = r[c + h + s], m = n[c + h + s], g = d * b - l * m; - m = d * m + l * b, b = g, r[c + h] = p + b, n[c + h] = y + m, r[c + h + s] = p - b, n[c + h + s] = y - m, h !== o && (g = u * d - f * l, l = u * l + f * d, d = g) - } - }, y.prototype.guessLen13b = function (e, t) { - var r = 1 | Math.max(t, e), n = 1 & r, i = 0; - for (r = r / 2 | 0; r; r >>>= 1) i++; - return 1 << i + 1 + n - }, y.prototype.conjugate = function (e, t, r) { - if (!(r <= 1)) for (var n = 0; n < r / 2; n++) { - var i = e[n]; - e[n] = e[r - n - 1], e[r - n - 1] = i, i = t[n], t[n] = -t[r - n - 1], t[r - n - 1] = -i - } - }, y.prototype.normalize13b = function (e, t) { - for (var r = 0, n = 0; n < t / 2; n++) { - var i = 8192 * Math.round(e[2 * n + 1] / t) + Math.round(e[2 * n] / t) + r; - e[n] = 67108863 & i, r = i < 67108864 ? 0 : i / 67108864 | 0 - } - return e - }, y.prototype.convert13b = function (e, t, r, i) { - for (var a = 0, s = 0; s < t; s++) a += 0 | e[s], r[2 * s] = 8191 & a, a >>>= 13, r[2 * s + 1] = 8191 & a, a >>>= 13; - for (s = 2 * t; s < i; ++s) r[s] = 0; - n(0 === a), n(0 == (-8192 & a)) - }, y.prototype.stub = function (e) { - for (var t = new Array(e), r = 0; r < e; r++) t[r] = 0; - return t - }, y.prototype.mulp = function (e, t, r) { - var n = 2 * this.guessLen13b(e.length, t.length), i = this.makeRBT(n), a = this.stub(n), - s = new Array(n), o = new Array(n), u = new Array(n), f = new Array(n), c = new Array(n), - d = new Array(n), l = r.words; - l.length = n, this.convert13b(e.words, e.length, s, n), this.convert13b(t.words, t.length, f, n), this.transform(s, a, o, u, n, i), this.transform(f, a, c, d, n, i); - for (var h = 0; h < n; h++) { - var p = o[h] * c[h] - u[h] * d[h]; - u[h] = o[h] * d[h] + u[h] * c[h], o[h] = p - } - return this.conjugate(o, u, n), this.transform(o, u, l, a, n, i), this.conjugate(l, a, n), this.normalize13b(l, n), r.negative = e.negative ^ t.negative, r.length = e.length + t.length, r.strip() - }, a.prototype.mul = function (e) { - var t = new a(null); - return t.words = new Array(this.length + e.length), this.mulTo(e, t) - }, a.prototype.mulf = function (e) { - var t = new a(null); - return t.words = new Array(this.length + e.length), p(this, e, t) - }, a.prototype.imul = function (e) { - return this.clone().mulTo(e, this) - }, a.prototype.imuln = function (e) { - n("number" == typeof e), n(e < 67108864); - for (var t = 0, r = 0; r < this.length; r++) { - var i = (0 | this.words[r]) * e, a = (67108863 & i) + (67108863 & t); - t >>= 26, t += i / 67108864 | 0, t += a >>> 26, this.words[r] = 67108863 & a - } - return 0 !== t && (this.words[r] = t, this.length++), this - }, a.prototype.muln = function (e) { - return this.clone().imuln(e) - }, a.prototype.sqr = function () { - return this.mul(this) - }, a.prototype.isqr = function () { - return this.imul(this.clone()) - }, a.prototype.pow = function (e) { - var t = function (e) { - for (var t = new Array(e.bitLength()), r = 0; r < t.length; r++) { - var n = r / 26 | 0, i = r % 26; - t[r] = (e.words[n] & 1 << i) >>> i - } - return t - }(e); - if (0 === t.length) return new a(1); - for (var r = this, n = 0; n < t.length && 0 === t[n]; n++, r = r.sqr()) ; - if (++n < t.length) for (var i = r.sqr(); n < t.length; n++, i = i.sqr()) 0 !== t[n] && (r = r.mul(i)); - return r - }, a.prototype.iushln = function (e) { - n("number" == typeof e && e >= 0); - var t, r = e % 26, i = (e - r) / 26, a = 67108863 >>> 26 - r << 26 - r; - if (0 !== r) { - var s = 0; - for (t = 0; t < this.length; t++) { - var o = this.words[t] & a, u = (0 | this.words[t]) - o << r; - this.words[t] = u | s, s = o >>> 26 - r - } - s && (this.words[t] = s, this.length++) - } - if (0 !== i) { - for (t = this.length - 1; t >= 0; t--) this.words[t + i] = this.words[t]; - for (t = 0; t < i; t++) this.words[t] = 0; - this.length += i - } - return this.strip() - }, a.prototype.ishln = function (e) { - return n(0 === this.negative), this.iushln(e) - }, a.prototype.iushrn = function (e, t, r) { - var i; - n("number" == typeof e && e >= 0), i = t ? (t - t % 26) / 26 : 0; - var a = e % 26, s = Math.min((e - a) / 26, this.length), o = 67108863 ^ 67108863 >>> a << a, u = r; - if (i -= s, i = Math.max(0, i), u) { - for (var f = 0; f < s; f++) u.words[f] = this.words[f]; - u.length = s - } - if (0 === s) ; else if (this.length > s) for (this.length -= s, f = 0; f < this.length; f++) this.words[f] = this.words[f + s]; else this.words[0] = 0, this.length = 1; - var c = 0; - for (f = this.length - 1; f >= 0 && (0 !== c || f >= i); f--) { - var d = 0 | this.words[f]; - this.words[f] = c << 26 - a | d >>> a, c = d & o - } - return u && 0 !== c && (u.words[u.length++] = c), 0 === this.length && (this.words[0] = 0, this.length = 1), this.strip() - }, a.prototype.ishrn = function (e, t, r) { - return n(0 === this.negative), this.iushrn(e, t, r) - }, a.prototype.shln = function (e) { - return this.clone().ishln(e) - }, a.prototype.ushln = function (e) { - return this.clone().iushln(e) - }, a.prototype.shrn = function (e) { - return this.clone().ishrn(e) - }, a.prototype.ushrn = function (e) { - return this.clone().iushrn(e) - }, a.prototype.testn = function (e) { - n("number" == typeof e && e >= 0); - var t = e % 26, r = (e - t) / 26, i = 1 << t; - return !(this.length <= r) && !!(this.words[r] & i) - }, a.prototype.imaskn = function (e) { - n("number" == typeof e && e >= 0); - var t = e % 26, r = (e - t) / 26; - if (n(0 === this.negative, "imaskn works only with positive numbers"), this.length <= r) return this; - if (0 !== t && r++, this.length = Math.min(r, this.length), 0 !== t) { - var i = 67108863 ^ 67108863 >>> t << t; - this.words[this.length - 1] &= i - } - return this.strip() - }, a.prototype.maskn = function (e) { - return this.clone().imaskn(e) - }, a.prototype.iaddn = function (e) { - return n("number" == typeof e), n(e < 67108864), e < 0 ? this.isubn(-e) : 0 !== this.negative ? 1 === this.length && (0 | this.words[0]) < e ? (this.words[0] = e - (0 | this.words[0]), this.negative = 0, this) : (this.negative = 0, this.isubn(e), this.negative = 1, this) : this._iaddn(e) - }, a.prototype._iaddn = function (e) { - this.words[0] += e; - for (var t = 0; t < this.length && this.words[t] >= 67108864; t++) this.words[t] -= 67108864, t === this.length - 1 ? this.words[t + 1] = 1 : this.words[t + 1]++; - return this.length = Math.max(this.length, t + 1), this - }, a.prototype.isubn = function (e) { - if (n("number" == typeof e), n(e < 67108864), e < 0) return this.iaddn(-e); - if (0 !== this.negative) return this.negative = 0, this.iaddn(e), this.negative = 1, this; - if (this.words[0] -= e, 1 === this.length && this.words[0] < 0) this.words[0] = -this.words[0], this.negative = 1; else for (var t = 0; t < this.length && this.words[t] < 0; t++) this.words[t] += 67108864, this.words[t + 1] -= 1; - return this.strip() - }, a.prototype.addn = function (e) { - return this.clone().iaddn(e) - }, a.prototype.subn = function (e) { - return this.clone().isubn(e) - }, a.prototype.iabs = function () { - return this.negative = 0, this - }, a.prototype.abs = function () { - return this.clone().iabs() - }, a.prototype._ishlnsubmul = function (e, t, r) { - var i, a, s = e.length + r; - this._expand(s); - var o = 0; - for (i = 0; i < e.length; i++) { - a = (0 | this.words[i + r]) + o; - var u = (0 | e.words[i]) * t; - o = ((a -= 67108863 & u) >> 26) - (u / 67108864 | 0), this.words[i + r] = 67108863 & a - } - for (; i < this.length - r; i++) o = (a = (0 | this.words[i + r]) + o) >> 26, this.words[i + r] = 67108863 & a; - if (0 === o) return this.strip(); - for (n(-1 === o), o = 0, i = 0; i < this.length; i++) o = (a = -(0 | this.words[i]) + o) >> 26, this.words[i] = 67108863 & a; - return this.negative = 1, this.strip() - }, a.prototype._wordDiv = function (e, t) { - var r = (this.length, e.length), n = this.clone(), i = e, s = 0 | i.words[i.length - 1]; - 0 !== (r = 26 - this._countBits(s)) && (i = i.ushln(r), n.iushln(r), s = 0 | i.words[i.length - 1]); - var o, u = n.length - i.length; - if ("mod" !== t) { - (o = new a(null)).length = u + 1, o.words = new Array(o.length); - for (var f = 0; f < o.length; f++) o.words[f] = 0 - } - var c = n.clone()._ishlnsubmul(i, 1, u); - 0 === c.negative && (n = c, o && (o.words[u] = 1)); - for (var d = u - 1; d >= 0; d--) { - var l = 67108864 * (0 | n.words[i.length + d]) + (0 | n.words[i.length + d - 1]); - for (l = Math.min(l / s | 0, 67108863), n._ishlnsubmul(i, l, d); 0 !== n.negative;) l--, n.negative = 0, n._ishlnsubmul(i, 1, d), n.isZero() || (n.negative ^= 1); - o && (o.words[d] = l) - } - return o && o.strip(), n.strip(), "div" !== t && 0 !== r && n.iushrn(r), {div: o || null, mod: n} - }, a.prototype.divmod = function (e, t, r) { - return n(!e.isZero()), this.isZero() ? { - div: new a(0), - mod: new a(0) - } : 0 !== this.negative && 0 === e.negative ? (o = this.neg().divmod(e, t), "mod" !== t && (i = o.div.neg()), "div" !== t && (s = o.mod.neg(), r && 0 !== s.negative && s.iadd(e)), { - div: i, - mod: s - }) : 0 === this.negative && 0 !== e.negative ? (o = this.divmod(e.neg(), t), "mod" !== t && (i = o.div.neg()), { - div: i, - mod: o.mod - }) : 0 != (this.negative & e.negative) ? (o = this.neg().divmod(e.neg(), t), "div" !== t && (s = o.mod.neg(), r && 0 !== s.negative && s.isub(e)), { - div: o.div, - mod: s - }) : e.length > this.length || this.cmp(e) < 0 ? { - div: new a(0), - mod: this - } : 1 === e.length ? "div" === t ? { - div: this.divn(e.words[0]), - mod: null - } : "mod" === t ? {div: null, mod: new a(this.modn(e.words[0]))} : { - div: this.divn(e.words[0]), - mod: new a(this.modn(e.words[0])) - } : this._wordDiv(e, t); - var i, s, o - }, a.prototype.div = function (e) { - return this.divmod(e, "div", !1).div - }, a.prototype.mod = function (e) { - return this.divmod(e, "mod", !1).mod - }, a.prototype.umod = function (e) { - return this.divmod(e, "mod", !0).mod - }, a.prototype.divRound = function (e) { - var t = this.divmod(e); - if (t.mod.isZero()) return t.div; - var r = 0 !== t.div.negative ? t.mod.isub(e) : t.mod, n = e.ushrn(1), i = e.andln(1), a = r.cmp(n); - return a < 0 || 1 === i && 0 === a ? t.div : 0 !== t.div.negative ? t.div.isubn(1) : t.div.iaddn(1) - }, a.prototype.modn = function (e) { - n(e <= 67108863); - for (var t = (1 << 26) % e, r = 0, i = this.length - 1; i >= 0; i--) r = (t * r + (0 | this.words[i])) % e; - return r - }, a.prototype.idivn = function (e) { - n(e <= 67108863); - for (var t = 0, r = this.length - 1; r >= 0; r--) { - var i = (0 | this.words[r]) + 67108864 * t; - this.words[r] = i / e | 0, t = i % e - } - return this.strip() - }, a.prototype.divn = function (e) { - return this.clone().idivn(e) - }, a.prototype.egcd = function (e) { - n(0 === e.negative), n(!e.isZero()); - var t = this, r = e.clone(); - t = 0 !== t.negative ? t.umod(e) : t.clone(); - for (var i = new a(1), s = new a(0), o = new a(0), u = new a(1), f = 0; t.isEven() && r.isEven();) t.iushrn(1), r.iushrn(1), ++f; - for (var c = r.clone(), d = t.clone(); !t.isZero();) { - for (var l = 0, h = 1; 0 == (t.words[0] & h) && l < 26; ++l, h <<= 1) ; - if (l > 0) for (t.iushrn(l); l-- > 0;) (i.isOdd() || s.isOdd()) && (i.iadd(c), s.isub(d)), i.iushrn(1), s.iushrn(1); - for (var p = 0, y = 1; 0 == (r.words[0] & y) && p < 26; ++p, y <<= 1) ; - if (p > 0) for (r.iushrn(p); p-- > 0;) (o.isOdd() || u.isOdd()) && (o.iadd(c), u.isub(d)), o.iushrn(1), u.iushrn(1); - t.cmp(r) >= 0 ? (t.isub(r), i.isub(o), s.isub(u)) : (r.isub(t), o.isub(i), u.isub(s)) - } - return {a: o, b: u, gcd: r.iushln(f)} - }, a.prototype._invmp = function (e) { - n(0 === e.negative), n(!e.isZero()); - var t = this, r = e.clone(); - t = 0 !== t.negative ? t.umod(e) : t.clone(); - for (var i, s = new a(1), o = new a(0), u = r.clone(); t.cmpn(1) > 0 && r.cmpn(1) > 0;) { - for (var f = 0, c = 1; 0 == (t.words[0] & c) && f < 26; ++f, c <<= 1) ; - if (f > 0) for (t.iushrn(f); f-- > 0;) s.isOdd() && s.iadd(u), s.iushrn(1); - for (var d = 0, l = 1; 0 == (r.words[0] & l) && d < 26; ++d, l <<= 1) ; - if (d > 0) for (r.iushrn(d); d-- > 0;) o.isOdd() && o.iadd(u), o.iushrn(1); - t.cmp(r) >= 0 ? (t.isub(r), s.isub(o)) : (r.isub(t), o.isub(s)) - } - return (i = 0 === t.cmpn(1) ? s : o).cmpn(0) < 0 && i.iadd(e), i - }, a.prototype.gcd = function (e) { - if (this.isZero()) return e.abs(); - if (e.isZero()) return this.abs(); - var t = this.clone(), r = e.clone(); - t.negative = 0, r.negative = 0; - for (var n = 0; t.isEven() && r.isEven(); n++) t.iushrn(1), r.iushrn(1); - for (; ;) { - for (; t.isEven();) t.iushrn(1); - for (; r.isEven();) r.iushrn(1); - var i = t.cmp(r); - if (i < 0) { - var a = t; - t = r, r = a - } else if (0 === i || 0 === r.cmpn(1)) break; - t.isub(r) - } - return r.iushln(n) - }, a.prototype.invm = function (e) { - return this.egcd(e).a.umod(e) - }, a.prototype.isEven = function () { - return 0 == (1 & this.words[0]) - }, a.prototype.isOdd = function () { - return 1 == (1 & this.words[0]) - }, a.prototype.andln = function (e) { - return this.words[0] & e - }, a.prototype.bincn = function (e) { - n("number" == typeof e); - var t = e % 26, r = (e - t) / 26, i = 1 << t; - if (this.length <= r) return this._expand(r + 1), this.words[r] |= i, this; - for (var a = i, s = r; 0 !== a && s < this.length; s++) { - var o = 0 | this.words[s]; - a = (o += a) >>> 26, o &= 67108863, this.words[s] = o - } - return 0 !== a && (this.words[s] = a, this.length++), this - }, a.prototype.isZero = function () { - return 1 === this.length && 0 === this.words[0] - }, a.prototype.cmpn = function (e) { - var t, r = e < 0; - if (0 !== this.negative && !r) return -1; - if (0 === this.negative && r) return 1; - if (this.strip(), this.length > 1) t = 1; else { - r && (e = -e), n(e <= 67108863, "Number is too big"); - var i = 0 | this.words[0]; - t = i === e ? 0 : i < e ? -1 : 1 - } - return 0 !== this.negative ? 0 | -t : t - }, a.prototype.cmp = function (e) { - if (0 !== this.negative && 0 === e.negative) return -1; - if (0 === this.negative && 0 !== e.negative) return 1; - var t = this.ucmp(e); - return 0 !== this.negative ? 0 | -t : t - }, a.prototype.ucmp = function (e) { - if (this.length > e.length) return 1; - if (this.length < e.length) return -1; - for (var t = 0, r = this.length - 1; r >= 0; r--) { - var n = 0 | this.words[r], i = 0 | e.words[r]; - if (n !== i) { - n < i ? t = -1 : n > i && (t = 1); - break - } - } - return t - }, a.prototype.gtn = function (e) { - return 1 === this.cmpn(e) - }, a.prototype.gt = function (e) { - return 1 === this.cmp(e) - }, a.prototype.gten = function (e) { - return this.cmpn(e) >= 0 - }, a.prototype.gte = function (e) { - return this.cmp(e) >= 0 - }, a.prototype.ltn = function (e) { - return -1 === this.cmpn(e) - }, a.prototype.lt = function (e) { - return -1 === this.cmp(e) - }, a.prototype.lten = function (e) { - return this.cmpn(e) <= 0 - }, a.prototype.lte = function (e) { - return this.cmp(e) <= 0 - }, a.prototype.eqn = function (e) { - return 0 === this.cmpn(e) - }, a.prototype.eq = function (e) { - return 0 === this.cmp(e) - }, a.red = function (e) { - return new k(e) - }, a.prototype.toRed = function (e) { - return n(!this.red, "Already a number in reduction context"), n(0 === this.negative, "red works only with positives"), e.convertTo(this)._forceRed(e) - }, a.prototype.fromRed = function () { - return n(this.red, "fromRed works only with numbers in reduction context"), this.red.convertFrom(this) - }, a.prototype._forceRed = function (e) { - return this.red = e, this - }, a.prototype.forceRed = function (e) { - return n(!this.red, "Already a number in reduction context"), this._forceRed(e) - }, a.prototype.redAdd = function (e) { - return n(this.red, "redAdd works only with red numbers"), this.red.add(this, e) - }, a.prototype.redIAdd = function (e) { - return n(this.red, "redIAdd works only with red numbers"), this.red.iadd(this, e) - }, a.prototype.redSub = function (e) { - return n(this.red, "redSub works only with red numbers"), this.red.sub(this, e) - }, a.prototype.redISub = function (e) { - return n(this.red, "redISub works only with red numbers"), this.red.isub(this, e) - }, a.prototype.redShl = function (e) { - return n(this.red, "redShl works only with red numbers"), this.red.shl(this, e) - }, a.prototype.redMul = function (e) { - return n(this.red, "redMul works only with red numbers"), this.red._verify2(this, e), this.red.mul(this, e) - }, a.prototype.redIMul = function (e) { - return n(this.red, "redMul works only with red numbers"), this.red._verify2(this, e), this.red.imul(this, e) - }, a.prototype.redSqr = function () { - return n(this.red, "redSqr works only with red numbers"), this.red._verify1(this), this.red.sqr(this) - }, a.prototype.redISqr = function () { - return n(this.red, "redISqr works only with red numbers"), this.red._verify1(this), this.red.isqr(this) - }, a.prototype.redSqrt = function () { - return n(this.red, "redSqrt works only with red numbers"), this.red._verify1(this), this.red.sqrt(this) - }, a.prototype.redInvm = function () { - return n(this.red, "redInvm works only with red numbers"), this.red._verify1(this), this.red.invm(this) - }, a.prototype.redNeg = function () { - return n(this.red, "redNeg works only with red numbers"), this.red._verify1(this), this.red.neg(this) - }, a.prototype.redPow = function (e) { - return n(this.red && !e.red, "redPow(normalNum)"), this.red._verify1(this), this.red.pow(this, e) - }; - var b = {k256: null, p224: null, p192: null, p25519: null}; - - function m(e, t) { - this.name = e, this.p = new a(t, 16), this.n = this.p.bitLength(), this.k = new a(1).iushln(this.n).isub(this.p), this.tmp = this._tmp() - } - - function g() { - m.call(this, "k256", "ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f") - } - - function v() { - m.call(this, "p224", "ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001") - } - - function _() { - m.call(this, "p192", "ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff") - } - - function w() { - m.call(this, "25519", "7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed") - } - - function k(e) { - if ("string" == typeof e) { - var t = a._prime(e); - this.m = t.p, this.prime = t - } else n(e.gtn(1), "modulus must be greater than 1"), this.m = e, this.prime = null - } - - function A(e) { - k.call(this, e), this.shift = this.m.bitLength(), this.shift % 26 != 0 && (this.shift += 26 - this.shift % 26), this.r = new a(1).iushln(this.shift), this.r2 = this.imod(this.r.sqr()), this.rinv = this.r._invmp(this.m), this.minv = this.rinv.mul(this.r).isubn(1).div(this.m), this.minv = this.minv.umod(this.r), this.minv = this.r.sub(this.minv) - } - - m.prototype._tmp = function () { - var e = new a(null); - return e.words = new Array(Math.ceil(this.n / 13)), e - }, m.prototype.ireduce = function (e) { - var t, r = e; - do { - this.split(r, this.tmp), t = (r = (r = this.imulK(r)).iadd(this.tmp)).bitLength() - } while (t > this.n); - var n = t < this.n ? -1 : r.ucmp(this.p); - return 0 === n ? (r.words[0] = 0, r.length = 1) : n > 0 ? r.isub(this.p) : r.strip(), r - }, m.prototype.split = function (e, t) { - e.iushrn(this.n, 0, t) - }, m.prototype.imulK = function (e) { - return e.imul(this.k) - }, i(g, m), g.prototype.split = function (e, t) { - for (var r = Math.min(e.length, 9), n = 0; n < r; n++) t.words[n] = e.words[n]; - if (t.length = r, e.length <= 9) return e.words[0] = 0, void(e.length = 1); - var i = e.words[9]; - for (t.words[t.length++] = 4194303 & i, n = 10; n < e.length; n++) { - var a = 0 | e.words[n]; - e.words[n - 10] = (4194303 & a) << 4 | i >>> 22, i = a - } - i >>>= 22, e.words[n - 10] = i, 0 === i && e.length > 10 ? e.length -= 10 : e.length -= 9 - }, g.prototype.imulK = function (e) { - e.words[e.length] = 0, e.words[e.length + 1] = 0, e.length += 2; - for (var t = 0, r = 0; r < e.length; r++) { - var n = 0 | e.words[r]; - t += 977 * n, e.words[r] = 67108863 & t, t = 64 * n + (t / 67108864 | 0) - } - return 0 === e.words[e.length - 1] && (e.length--, 0 === e.words[e.length - 1] && e.length--), e - }, i(v, m), i(_, m), i(w, m), w.prototype.imulK = function (e) { - for (var t = 0, r = 0; r < e.length; r++) { - var n = 19 * (0 | e.words[r]) + t, i = 67108863 & n; - n >>>= 26, e.words[r] = i, t = n - } - return 0 !== t && (e.words[e.length++] = t), e - }, a._prime = function (e) { - if (b[e]) return b[e]; - var t; - if ("k256" === e) t = new g; else if ("p224" === e) t = new v; else if ("p192" === e) t = new _; else { - if ("p25519" !== e) throw new Error("Unknown prime " + e); - t = new w - } - return b[e] = t, t - }, k.prototype._verify1 = function (e) { - n(0 === e.negative, "red works only with positives"), n(e.red, "red works only with red numbers") - }, k.prototype._verify2 = function (e, t) { - n(0 == (e.negative | t.negative), "red works only with positives"), n(e.red && e.red === t.red, "red works only with red numbers") - }, k.prototype.imod = function (e) { - return this.prime ? this.prime.ireduce(e)._forceRed(this) : e.umod(this.m)._forceRed(this) - }, k.prototype.neg = function (e) { - return e.isZero() ? e.clone() : this.m.sub(e)._forceRed(this) - }, k.prototype.add = function (e, t) { - this._verify2(e, t); - var r = e.add(t); - return r.cmp(this.m) >= 0 && r.isub(this.m), r._forceRed(this) - }, k.prototype.iadd = function (e, t) { - this._verify2(e, t); - var r = e.iadd(t); - return r.cmp(this.m) >= 0 && r.isub(this.m), r - }, k.prototype.sub = function (e, t) { - this._verify2(e, t); - var r = e.sub(t); - return r.cmpn(0) < 0 && r.iadd(this.m), r._forceRed(this) - }, k.prototype.isub = function (e, t) { - this._verify2(e, t); - var r = e.isub(t); - return r.cmpn(0) < 0 && r.iadd(this.m), r - }, k.prototype.shl = function (e, t) { - return this._verify1(e), this.imod(e.ushln(t)) - }, k.prototype.imul = function (e, t) { - return this._verify2(e, t), this.imod(e.imul(t)) - }, k.prototype.mul = function (e, t) { - return this._verify2(e, t), this.imod(e.mul(t)) - }, k.prototype.isqr = function (e) { - return this.imul(e, e.clone()) - }, k.prototype.sqr = function (e) { - return this.mul(e, e) - }, k.prototype.sqrt = function (e) { - if (e.isZero()) return e.clone(); - var t = this.m.andln(3); - if (n(t % 2 == 1), 3 === t) { - var r = this.m.add(new a(1)).iushrn(2); - return this.pow(e, r) - } - for (var i = this.m.subn(1), s = 0; !i.isZero() && 0 === i.andln(1);) s++, i.iushrn(1); - n(!i.isZero()); - var o = new a(1).toRed(this), u = o.redNeg(), f = this.m.subn(1).iushrn(1), c = this.m.bitLength(); - for (c = new a(2 * c * c).toRed(this); 0 !== this.pow(c, f).cmp(u);) c.redIAdd(u); - for (var d = this.pow(c, i), l = this.pow(e, i.addn(1).iushrn(1)), h = this.pow(e, i), p = s; 0 !== h.cmp(o);) { - for (var y = h, b = 0; 0 !== y.cmp(o); b++) y = y.redSqr(); - n(b < p); - var m = this.pow(d, new a(1).iushln(p - b - 1)); - l = l.redMul(m), d = m.redSqr(), h = h.redMul(d), p = b - } - return l - }, k.prototype.invm = function (e) { - var t = e._invmp(this.m); - return 0 !== t.negative ? (t.negative = 0, this.imod(t).redNeg()) : this.imod(t) - }, k.prototype.pow = function (e, t) { - if (t.isZero()) return new a(1).toRed(this); - if (0 === t.cmpn(1)) return e.clone(); - var r = new Array(16); - r[0] = new a(1).toRed(this), r[1] = e; - for (var n = 2; n < r.length; n++) r[n] = this.mul(r[n - 1], e); - var i = r[0], s = 0, o = 0, u = t.bitLength() % 26; - for (0 === u && (u = 26), n = t.length - 1; n >= 0; n--) { - for (var f = t.words[n], c = u - 1; c >= 0; c--) { - var d = f >> c & 1; - i !== r[0] && (i = this.sqr(i)), 0 !== d || 0 !== s ? (s <<= 1, s |= d, (4 === ++o || 0 === n && 0 === c) && (i = this.mul(i, r[s]), o = 0, s = 0)) : o = 0 - } - u = 26 - } - return i - }, k.prototype.convertTo = function (e) { - var t = e.umod(this.m); - return t === e ? t.clone() : t - }, k.prototype.convertFrom = function (e) { - var t = e.clone(); - return t.red = null, t - }, a.mont = function (e) { - return new A(e) - }, i(A, k), A.prototype.convertTo = function (e) { - return this.imod(e.ushln(this.shift)) - }, A.prototype.convertFrom = function (e) { - var t = this.imod(e.mul(this.rinv)); - return t.red = null, t - }, A.prototype.imul = function (e, t) { - if (e.isZero() || t.isZero()) return e.words[0] = 0, e.length = 1, e; - var r = e.imul(t), n = r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m), - i = r.isub(n).iushrn(this.shift), a = i; - return i.cmp(this.m) >= 0 ? a = i.isub(this.m) : i.cmpn(0) < 0 && (a = i.iadd(this.m)), a._forceRed(this) - }, A.prototype.mul = function (e, t) { - if (e.isZero() || t.isZero()) return new a(0)._forceRed(this); - var r = e.mul(t), n = r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m), - i = r.isub(n).iushrn(this.shift), s = i; - return i.cmp(this.m) >= 0 ? s = i.isub(this.m) : i.cmpn(0) < 0 && (s = i.iadd(this.m)), s._forceRed(this) - }, A.prototype.invm = function (e) { - return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this) - } - }(void 0 === t || t, this) - }, {buffer: 42}], - 41: [function (e, t, r) { - var n; - - function i(e) { - this.rand = e - } - - if (t.exports = function (e) { - return n || (n = new i(null)), n.generate(e) - }, t.exports.Rand = i, i.prototype.generate = function (e) { - return this._rand(e) - }, i.prototype._rand = function (e) { - if (this.rand.getBytes) return this.rand.getBytes(e); - for (var t = new Uint8Array(e), r = 0; r < t.length; r++) t[r] = this.rand.getByte(); - return t - }, "object" == typeof self) self.crypto && self.crypto.getRandomValues ? i.prototype._rand = function (e) { - var t = new Uint8Array(e); - return self.crypto.getRandomValues(t), t - } : self.msCrypto && self.msCrypto.getRandomValues ? i.prototype._rand = function (e) { - var t = new Uint8Array(e); - return self.msCrypto.getRandomValues(t), t - } : "object" == typeof window && (i.prototype._rand = function () { - throw new Error("Not implemented yet") - }); else try { - var a = e("crypto"); - if ("function" != typeof a.randomBytes) throw new Error("Not supported"); - i.prototype._rand = function (e) { - return a.randomBytes(e) - } - } catch (e) { - } - }, {crypto: "crypto"}], - 42: [function (e, t, r) { - }, {}], - 43: [function (e, t, r) { - "use strict"; - var n = e("base64-js"), i = e("ieee754"); - r.Buffer = o, r.SlowBuffer = function (e) { - +e != e && (e = 0); - return o.alloc(+e) - }, r.INSPECT_MAX_BYTES = 50; - var a = 2147483647; - - function s(e) { - if (e > a) throw new RangeError("Invalid typed array length"); - var t = new Uint8Array(e); - return t.__proto__ = o.prototype, t - } - - function o(e, t, r) { - if ("number" == typeof e) { - if ("string" == typeof t) throw new Error("If encoding is specified then the first argument must be a string"); - return c(e) - } - return u(e, t, r) - } - - function u(e, t, r) { - if ("number" == typeof e) throw new TypeError('"value" argument must not be a number'); - return L(e) ? function (e, t, r) { - if (t < 0 || e.byteLength < t) throw new RangeError("'offset' is out of bounds"); - if (e.byteLength < t + (r || 0)) throw new RangeError("'length' is out of bounds"); - var n; - n = void 0 === t && void 0 === r ? new Uint8Array(e) : void 0 === r ? new Uint8Array(e, t) : new Uint8Array(e, t, r); - return n.__proto__ = o.prototype, n - }(e, t, r) : "string" == typeof e ? function (e, t) { - "string" == typeof t && "" !== t || (t = "utf8"); - if (!o.isEncoding(t)) throw new TypeError('"encoding" must be a valid string encoding'); - var r = 0 | h(e, t), n = s(r), i = n.write(e, t); - i !== r && (n = n.slice(0, i)); - return n - }(e, t) : function (e) { - if (o.isBuffer(e)) { - var t = 0 | l(e.length), r = s(t); - return 0 === r.length ? r : (e.copy(r, 0, 0, t), r) - } - if (e) { - if (F(e) || "length" in e) return "number" != typeof e.length || N(e.length) ? s(0) : d(e); - if ("Buffer" === e.type && Array.isArray(e.data)) return d(e.data) - } - throw new TypeError("First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.") - }(e) - } - - function f(e) { - if ("number" != typeof e) throw new TypeError('"size" argument must be a number'); - if (e < 0) throw new RangeError('"size" argument must not be negative') - } - - function c(e) { - return f(e), s(e < 0 ? 0 : 0 | l(e)) - } - - function d(e) { - for (var t = e.length < 0 ? 0 : 0 | l(e.length), r = s(t), n = 0; n < t; n += 1) r[n] = 255 & e[n]; - return r - } - - function l(e) { - if (e >= a) throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x" + a.toString(16) + " bytes"); - return 0 | e - } - - function h(e, t) { - if (o.isBuffer(e)) return e.length; - if (F(e) || L(e)) return e.byteLength; - "string" != typeof e && (e = "" + e); - var r = e.length; - if (0 === r) return 0; - for (var n = !1; ;) switch (t) { - case"ascii": - case"latin1": - case"binary": - return r; - case"utf8": - case"utf-8": - case void 0: - return R(e).length; - case"ucs2": - case"ucs-2": - case"utf16le": - case"utf-16le": - return 2 * r; - case"hex": - return r >>> 1; - case"base64": - return D(e).length; - default: - if (n) return R(e).length; - t = ("" + t).toLowerCase(), n = !0 - } - } - - function p(e, t, r) { - var n = e[t]; - e[t] = e[r], e[r] = n - } - - function y(e, t, r, n, i) { - if (0 === e.length) return -1; - if ("string" == typeof r ? (n = r, r = 0) : r > 2147483647 ? r = 2147483647 : r < -2147483648 && (r = -2147483648), N(r = +r) && (r = i ? 0 : e.length - 1), r < 0 && (r = e.length + r), r >= e.length) { - if (i) return -1; - r = e.length - 1 - } else if (r < 0) { - if (!i) return -1; - r = 0 - } - if ("string" == typeof t && (t = o.from(t, n)), o.isBuffer(t)) return 0 === t.length ? -1 : b(e, t, r, n, i); - if ("number" == typeof t) return t &= 255, "function" == typeof Uint8Array.prototype.indexOf ? i ? Uint8Array.prototype.indexOf.call(e, t, r) : Uint8Array.prototype.lastIndexOf.call(e, t, r) : b(e, [t], r, n, i); - throw new TypeError("val must be string, number or Buffer") - } - - function b(e, t, r, n, i) { - var a, s = 1, o = e.length, u = t.length; - if (void 0 !== n && ("ucs2" === (n = String(n).toLowerCase()) || "ucs-2" === n || "utf16le" === n || "utf-16le" === n)) { - if (e.length < 2 || t.length < 2) return -1; - s = 2, o /= 2, u /= 2, r /= 2 - } - - function f(e, t) { - return 1 === s ? e[t] : e.readUInt16BE(t * s) - } - - if (i) { - var c = -1; - for (a = r; a < o; a++) if (f(e, a) === f(t, -1 === c ? 0 : a - c)) { - if (-1 === c && (c = a), a - c + 1 === u) return c * s - } else -1 !== c && (a -= a - c), c = -1 - } else for (r + u > o && (r = o - u), a = r; a >= 0; a--) { - for (var d = !0, l = 0; l < u; l++) if (f(e, a + l) !== f(t, l)) { - d = !1; - break - } - if (d) return a - } - return -1 - } - - function m(e, t, r, n) { - r = Number(r) || 0; - var i = e.length - r; - n ? (n = Number(n)) > i && (n = i) : n = i; - var a = t.length; - if (a % 2 != 0) throw new TypeError("Invalid hex string"); - n > a / 2 && (n = a / 2); - for (var s = 0; s < n; ++s) { - var o = parseInt(t.substr(2 * s, 2), 16); - if (N(o)) return s; - e[r + s] = o - } - return s - } - - function g(e, t, r, n) { - return z(R(t, e.length - r), e, r, n) - } - - function v(e, t, r, n) { - return z(function (e) { - for (var t = [], r = 0; r < e.length; ++r) t.push(255 & e.charCodeAt(r)); - return t - }(t), e, r, n) - } - - function _(e, t, r, n) { - return v(e, t, r, n) - } - - function w(e, t, r, n) { - return z(D(t), e, r, n) - } - - function k(e, t, r, n) { - return z(function (e, t) { - for (var r, n, i, a = [], s = 0; s < e.length && !((t -= 2) < 0); ++s) r = e.charCodeAt(s), n = r >> 8, i = r % 256, a.push(i), a.push(n); - return a - }(t, e.length - r), e, r, n) - } - - function A(e, t, r) { - return 0 === t && r === e.length ? n.fromByteArray(e) : n.fromByteArray(e.slice(t, r)) - } - - function x(e, t, r) { - r = Math.min(e.length, r); - for (var n = [], i = t; i < r;) { - var a, s, o, u, f = e[i], c = null, d = f > 239 ? 4 : f > 223 ? 3 : f > 191 ? 2 : 1; - if (i + d <= r) switch (d) { - case 1: - f < 128 && (c = f); - break; - case 2: - 128 == (192 & (a = e[i + 1])) && (u = (31 & f) << 6 | 63 & a) > 127 && (c = u); - break; - case 3: - a = e[i + 1], s = e[i + 2], 128 == (192 & a) && 128 == (192 & s) && (u = (15 & f) << 12 | (63 & a) << 6 | 63 & s) > 2047 && (u < 55296 || u > 57343) && (c = u); - break; - case 4: - a = e[i + 1], s = e[i + 2], o = e[i + 3], 128 == (192 & a) && 128 == (192 & s) && 128 == (192 & o) && (u = (15 & f) << 18 | (63 & a) << 12 | (63 & s) << 6 | 63 & o) > 65535 && u < 1114112 && (c = u) - } - null === c ? (c = 65533, d = 1) : c > 65535 && (c -= 65536, n.push(c >>> 10 & 1023 | 55296), c = 56320 | 1023 & c), n.push(c), i += d - } - return function (e) { - var t = e.length; - if (t <= S) return String.fromCharCode.apply(String, e); - var r = "", n = 0; - for (; n < t;) r += String.fromCharCode.apply(String, e.slice(n, n += S)); - return r - }(n) - } - - r.kMaxLength = a, o.TYPED_ARRAY_SUPPORT = function () { - try { - var e = new Uint8Array(1); - return e.__proto__ = { - __proto__: Uint8Array.prototype, foo: function () { - return 42 - } - }, 42 === e.foo() - } catch (e) { - return !1 - } - }(), o.TYPED_ARRAY_SUPPORT || "undefined" == typeof console || "function" != typeof console.error || console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support."), "undefined" != typeof Symbol && Symbol.species && o[Symbol.species] === o && Object.defineProperty(o, Symbol.species, { - value: null, - configurable: !0, - enumerable: !1, - writable: !1 - }), o.poolSize = 8192, o.from = function (e, t, r) { - return u(e, t, r) - }, o.prototype.__proto__ = Uint8Array.prototype, o.__proto__ = Uint8Array, o.alloc = function (e, t, r) { - return function (e, t, r) { - return f(e), e <= 0 ? s(e) : void 0 !== t ? "string" == typeof r ? s(e).fill(t, r) : s(e).fill(t) : s(e) - }(e, t, r) - }, o.allocUnsafe = function (e) { - return c(e) - }, o.allocUnsafeSlow = function (e) { - return c(e) - }, o.isBuffer = function (e) { - return null != e && !0 === e._isBuffer - }, o.compare = function (e, t) { - if (!o.isBuffer(e) || !o.isBuffer(t)) throw new TypeError("Arguments must be Buffers"); - if (e === t) return 0; - for (var r = e.length, n = t.length, i = 0, a = Math.min(r, n); i < a; ++i) if (e[i] !== t[i]) { - r = e[i], n = t[i]; - break - } - return r < n ? -1 : n < r ? 1 : 0 - }, o.isEncoding = function (e) { - switch (String(e).toLowerCase()) { - case"hex": - case"utf8": - case"utf-8": - case"ascii": - case"latin1": - case"binary": - case"base64": - case"ucs2": - case"ucs-2": - case"utf16le": - case"utf-16le": - return !0; - default: - return !1 - } - }, o.concat = function (e, t) { - if (!Array.isArray(e)) throw new TypeError('"list" argument must be an Array of Buffers'); - if (0 === e.length) return o.alloc(0); - var r; - if (void 0 === t) for (t = 0, r = 0; r < e.length; ++r) t += e[r].length; - var n = o.allocUnsafe(t), i = 0; - for (r = 0; r < e.length; ++r) { - var a = e[r]; - if (!o.isBuffer(a)) throw new TypeError('"list" argument must be an Array of Buffers'); - a.copy(n, i), i += a.length - } - return n - }, o.byteLength = h, o.prototype._isBuffer = !0, o.prototype.swap16 = function () { - var e = this.length; - if (e % 2 != 0) throw new RangeError("Buffer size must be a multiple of 16-bits"); - for (var t = 0; t < e; t += 2) p(this, t, t + 1); - return this - }, o.prototype.swap32 = function () { - var e = this.length; - if (e % 4 != 0) throw new RangeError("Buffer size must be a multiple of 32-bits"); - for (var t = 0; t < e; t += 4) p(this, t, t + 3), p(this, t + 1, t + 2); - return this - }, o.prototype.swap64 = function () { - var e = this.length; - if (e % 8 != 0) throw new RangeError("Buffer size must be a multiple of 64-bits"); - for (var t = 0; t < e; t += 8) p(this, t, t + 7), p(this, t + 1, t + 6), p(this, t + 2, t + 5), p(this, t + 3, t + 4); - return this - }, o.prototype.toString = function () { - var e = this.length; - return 0 === e ? "" : 0 === arguments.length ? x(this, 0, e) : function (e, t, r) { - var n = !1; - if ((void 0 === t || t < 0) && (t = 0), t > this.length) return ""; - if ((void 0 === r || r > this.length) && (r = this.length), r <= 0) return ""; - if ((r >>>= 0) <= (t >>>= 0)) return ""; - for (e || (e = "utf8"); ;) switch (e) { - case"hex": - return C(this, t, r); - case"utf8": - case"utf-8": - return x(this, t, r); - case"ascii": - return E(this, t, r); - case"latin1": - case"binary": - return M(this, t, r); - case"base64": - return A(this, t, r); - case"ucs2": - case"ucs-2": - case"utf16le": - case"utf-16le": - return j(this, t, r); - default: - if (n) throw new TypeError("Unknown encoding: " + e); - e = (e + "").toLowerCase(), n = !0 - } - }.apply(this, arguments) - }, o.prototype.equals = function (e) { - if (!o.isBuffer(e)) throw new TypeError("Argument must be a Buffer"); - return this === e || 0 === o.compare(this, e) - }, o.prototype.inspect = function () { - var e = "", t = r.INSPECT_MAX_BYTES; - return this.length > 0 && (e = this.toString("hex", 0, t).match(/.{2}/g).join(" "), this.length > t && (e += " ... ")), "" - }, o.prototype.compare = function (e, t, r, n, i) { - if (!o.isBuffer(e)) throw new TypeError("Argument must be a Buffer"); - if (void 0 === t && (t = 0), void 0 === r && (r = e ? e.length : 0), void 0 === n && (n = 0), void 0 === i && (i = this.length), t < 0 || r > e.length || n < 0 || i > this.length) throw new RangeError("out of range index"); - if (n >= i && t >= r) return 0; - if (n >= i) return -1; - if (t >= r) return 1; - if (t >>>= 0, r >>>= 0, n >>>= 0, i >>>= 0, this === e) return 0; - for (var a = i - n, s = r - t, u = Math.min(a, s), f = this.slice(n, i), c = e.slice(t, r), d = 0; d < u; ++d) if (f[d] !== c[d]) { - a = f[d], s = c[d]; - break - } - return a < s ? -1 : s < a ? 1 : 0 - }, o.prototype.includes = function (e, t, r) { - return -1 !== this.indexOf(e, t, r) - }, o.prototype.indexOf = function (e, t, r) { - return y(this, e, t, r, !0) - }, o.prototype.lastIndexOf = function (e, t, r) { - return y(this, e, t, r, !1) - }, o.prototype.write = function (e, t, r, n) { - if (void 0 === t) n = "utf8", r = this.length, t = 0; else if (void 0 === r && "string" == typeof t) n = t, r = this.length, t = 0; else { - if (!isFinite(t)) throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported"); - t >>>= 0, isFinite(r) ? (r >>>= 0, void 0 === n && (n = "utf8")) : (n = r, r = void 0) - } - var i = this.length - t; - if ((void 0 === r || r > i) && (r = i), e.length > 0 && (r < 0 || t < 0) || t > this.length) throw new RangeError("Attempt to write outside buffer bounds"); - n || (n = "utf8"); - for (var a = !1; ;) switch (n) { - case"hex": - return m(this, e, t, r); - case"utf8": - case"utf-8": - return g(this, e, t, r); - case"ascii": - return v(this, e, t, r); - case"latin1": - case"binary": - return _(this, e, t, r); - case"base64": - return w(this, e, t, r); - case"ucs2": - case"ucs-2": - case"utf16le": - case"utf-16le": - return k(this, e, t, r); - default: - if (a) throw new TypeError("Unknown encoding: " + n); - n = ("" + n).toLowerCase(), a = !0 - } - }, o.prototype.toJSON = function () { - return {type: "Buffer", data: Array.prototype.slice.call(this._arr || this, 0)} - }; - var S = 4096; - - function E(e, t, r) { - var n = ""; - r = Math.min(e.length, r); - for (var i = t; i < r; ++i) n += String.fromCharCode(127 & e[i]); - return n - } - - function M(e, t, r) { - var n = ""; - r = Math.min(e.length, r); - for (var i = t; i < r; ++i) n += String.fromCharCode(e[i]); - return n - } - - function C(e, t, r) { - var n = e.length; - (!t || t < 0) && (t = 0), (!r || r < 0 || r > n) && (r = n); - for (var i = "", a = t; a < r; ++a) i += O(e[a]); - return i - } - - function j(e, t, r) { - for (var n = e.slice(t, r), i = "", a = 0; a < n.length; a += 2) i += String.fromCharCode(n[a] + 256 * n[a + 1]); - return i - } - - function P(e, t, r) { - if (e % 1 != 0 || e < 0) throw new RangeError("offset is not uint"); - if (e + t > r) throw new RangeError("Trying to access beyond buffer length") - } - - function B(e, t, r, n, i, a) { - if (!o.isBuffer(e)) throw new TypeError('"buffer" argument must be a Buffer instance'); - if (t > i || t < a) throw new RangeError('"value" argument is out of bounds'); - if (r + n > e.length) throw new RangeError("Index out of range") - } - - function U(e, t, r, n, i, a) { - if (r + n > e.length) throw new RangeError("Index out of range"); - if (r < 0) throw new RangeError("Index out of range") - } - - function K(e, t, r, n, a) { - return t = +t, r >>>= 0, a || U(e, 0, r, 4), i.write(e, t, r, n, 23, 4), r + 4 - } - - function I(e, t, r, n, a) { - return t = +t, r >>>= 0, a || U(e, 0, r, 8), i.write(e, t, r, n, 52, 8), r + 8 - } - - o.prototype.slice = function (e, t) { - var r = this.length; - e = ~~e, t = void 0 === t ? r : ~~t, e < 0 ? (e += r) < 0 && (e = 0) : e > r && (e = r), t < 0 ? (t += r) < 0 && (t = 0) : t > r && (t = r), t < e && (t = e); - var n = this.subarray(e, t); - return n.__proto__ = o.prototype, n - }, o.prototype.readUIntLE = function (e, t, r) { - e >>>= 0, t >>>= 0, r || P(e, t, this.length); - for (var n = this[e], i = 1, a = 0; ++a < t && (i *= 256);) n += this[e + a] * i; - return n - }, o.prototype.readUIntBE = function (e, t, r) { - e >>>= 0, t >>>= 0, r || P(e, t, this.length); - for (var n = this[e + --t], i = 1; t > 0 && (i *= 256);) n += this[e + --t] * i; - return n - }, o.prototype.readUInt8 = function (e, t) { - return e >>>= 0, t || P(e, 1, this.length), this[e] - }, o.prototype.readUInt16LE = function (e, t) { - return e >>>= 0, t || P(e, 2, this.length), this[e] | this[e + 1] << 8 - }, o.prototype.readUInt16BE = function (e, t) { - return e >>>= 0, t || P(e, 2, this.length), this[e] << 8 | this[e + 1] - }, o.prototype.readUInt32LE = function (e, t) { - return e >>>= 0, t || P(e, 4, this.length), (this[e] | this[e + 1] << 8 | this[e + 2] << 16) + 16777216 * this[e + 3] - }, o.prototype.readUInt32BE = function (e, t) { - return e >>>= 0, t || P(e, 4, this.length), 16777216 * this[e] + (this[e + 1] << 16 | this[e + 2] << 8 | this[e + 3]) - }, o.prototype.readIntLE = function (e, t, r) { - e >>>= 0, t >>>= 0, r || P(e, t, this.length); - for (var n = this[e], i = 1, a = 0; ++a < t && (i *= 256);) n += this[e + a] * i; - return n >= (i *= 128) && (n -= Math.pow(2, 8 * t)), n - }, o.prototype.readIntBE = function (e, t, r) { - e >>>= 0, t >>>= 0, r || P(e, t, this.length); - for (var n = t, i = 1, a = this[e + --n]; n > 0 && (i *= 256);) a += this[e + --n] * i; - return a >= (i *= 128) && (a -= Math.pow(2, 8 * t)), a - }, o.prototype.readInt8 = function (e, t) { - return e >>>= 0, t || P(e, 1, this.length), 128 & this[e] ? -1 * (255 - this[e] + 1) : this[e] - }, o.prototype.readInt16LE = function (e, t) { - e >>>= 0, t || P(e, 2, this.length); - var r = this[e] | this[e + 1] << 8; - return 32768 & r ? 4294901760 | r : r - }, o.prototype.readInt16BE = function (e, t) { - e >>>= 0, t || P(e, 2, this.length); - var r = this[e + 1] | this[e] << 8; - return 32768 & r ? 4294901760 | r : r - }, o.prototype.readInt32LE = function (e, t) { - return e >>>= 0, t || P(e, 4, this.length), this[e] | this[e + 1] << 8 | this[e + 2] << 16 | this[e + 3] << 24 - }, o.prototype.readInt32BE = function (e, t) { - return e >>>= 0, t || P(e, 4, this.length), this[e] << 24 | this[e + 1] << 16 | this[e + 2] << 8 | this[e + 3] - }, o.prototype.readFloatLE = function (e, t) { - return e >>>= 0, t || P(e, 4, this.length), i.read(this, e, !0, 23, 4) - }, o.prototype.readFloatBE = function (e, t) { - return e >>>= 0, t || P(e, 4, this.length), i.read(this, e, !1, 23, 4) - }, o.prototype.readDoubleLE = function (e, t) { - return e >>>= 0, t || P(e, 8, this.length), i.read(this, e, !0, 52, 8) - }, o.prototype.readDoubleBE = function (e, t) { - return e >>>= 0, t || P(e, 8, this.length), i.read(this, e, !1, 52, 8) - }, o.prototype.writeUIntLE = function (e, t, r, n) { - (e = +e, t >>>= 0, r >>>= 0, n) || B(this, e, t, r, Math.pow(2, 8 * r) - 1, 0); - var i = 1, a = 0; - for (this[t] = 255 & e; ++a < r && (i *= 256);) this[t + a] = e / i & 255; - return t + r - }, o.prototype.writeUIntBE = function (e, t, r, n) { - (e = +e, t >>>= 0, r >>>= 0, n) || B(this, e, t, r, Math.pow(2, 8 * r) - 1, 0); - var i = r - 1, a = 1; - for (this[t + i] = 255 & e; --i >= 0 && (a *= 256);) this[t + i] = e / a & 255; - return t + r - }, o.prototype.writeUInt8 = function (e, t, r) { - return e = +e, t >>>= 0, r || B(this, e, t, 1, 255, 0), this[t] = 255 & e, t + 1 - }, o.prototype.writeUInt16LE = function (e, t, r) { - return e = +e, t >>>= 0, r || B(this, e, t, 2, 65535, 0), this[t] = 255 & e, this[t + 1] = e >>> 8, t + 2 - }, o.prototype.writeUInt16BE = function (e, t, r) { - return e = +e, t >>>= 0, r || B(this, e, t, 2, 65535, 0), this[t] = e >>> 8, this[t + 1] = 255 & e, t + 2 - }, o.prototype.writeUInt32LE = function (e, t, r) { - return e = +e, t >>>= 0, r || B(this, e, t, 4, 4294967295, 0), this[t + 3] = e >>> 24, this[t + 2] = e >>> 16, this[t + 1] = e >>> 8, this[t] = 255 & e, t + 4 - }, o.prototype.writeUInt32BE = function (e, t, r) { - return e = +e, t >>>= 0, r || B(this, e, t, 4, 4294967295, 0), this[t] = e >>> 24, this[t + 1] = e >>> 16, this[t + 2] = e >>> 8, this[t + 3] = 255 & e, t + 4 - }, o.prototype.writeIntLE = function (e, t, r, n) { - if (e = +e, t >>>= 0, !n) { - var i = Math.pow(2, 8 * r - 1); - B(this, e, t, r, i - 1, -i) - } - var a = 0, s = 1, o = 0; - for (this[t] = 255 & e; ++a < r && (s *= 256);) e < 0 && 0 === o && 0 !== this[t + a - 1] && (o = 1), this[t + a] = (e / s >> 0) - o & 255; - return t + r - }, o.prototype.writeIntBE = function (e, t, r, n) { - if (e = +e, t >>>= 0, !n) { - var i = Math.pow(2, 8 * r - 1); - B(this, e, t, r, i - 1, -i) - } - var a = r - 1, s = 1, o = 0; - for (this[t + a] = 255 & e; --a >= 0 && (s *= 256);) e < 0 && 0 === o && 0 !== this[t + a + 1] && (o = 1), this[t + a] = (e / s >> 0) - o & 255; - return t + r - }, o.prototype.writeInt8 = function (e, t, r) { - return e = +e, t >>>= 0, r || B(this, e, t, 1, 127, -128), e < 0 && (e = 255 + e + 1), this[t] = 255 & e, t + 1 - }, o.prototype.writeInt16LE = function (e, t, r) { - return e = +e, t >>>= 0, r || B(this, e, t, 2, 32767, -32768), this[t] = 255 & e, this[t + 1] = e >>> 8, t + 2 - }, o.prototype.writeInt16BE = function (e, t, r) { - return e = +e, t >>>= 0, r || B(this, e, t, 2, 32767, -32768), this[t] = e >>> 8, this[t + 1] = 255 & e, t + 2 - }, o.prototype.writeInt32LE = function (e, t, r) { - return e = +e, t >>>= 0, r || B(this, e, t, 4, 2147483647, -2147483648), this[t] = 255 & e, this[t + 1] = e >>> 8, this[t + 2] = e >>> 16, this[t + 3] = e >>> 24, t + 4 - }, o.prototype.writeInt32BE = function (e, t, r) { - return e = +e, t >>>= 0, r || B(this, e, t, 4, 2147483647, -2147483648), e < 0 && (e = 4294967295 + e + 1), this[t] = e >>> 24, this[t + 1] = e >>> 16, this[t + 2] = e >>> 8, this[t + 3] = 255 & e, t + 4 - }, o.prototype.writeFloatLE = function (e, t, r) { - return K(this, e, t, !0, r) - }, o.prototype.writeFloatBE = function (e, t, r) { - return K(this, e, t, !1, r) - }, o.prototype.writeDoubleLE = function (e, t, r) { - return I(this, e, t, !0, r) - }, o.prototype.writeDoubleBE = function (e, t, r) { - return I(this, e, t, !1, r) - }, o.prototype.copy = function (e, t, r, n) { - if (r || (r = 0), n || 0 === n || (n = this.length), t >= e.length && (t = e.length), t || (t = 0), n > 0 && n < r && (n = r), n === r) return 0; - if (0 === e.length || 0 === this.length) return 0; - if (t < 0) throw new RangeError("targetStart out of bounds"); - if (r < 0 || r >= this.length) throw new RangeError("sourceStart out of bounds"); - if (n < 0) throw new RangeError("sourceEnd out of bounds"); - n > this.length && (n = this.length), e.length - t < n - r && (n = e.length - t + r); - var i, a = n - r; - if (this === e && r < t && t < n) for (i = a - 1; i >= 0; --i) e[i + t] = this[i + r]; else if (a < 1e3) for (i = 0; i < a; ++i) e[i + t] = this[i + r]; else Uint8Array.prototype.set.call(e, this.subarray(r, r + a), t); - return a - }, o.prototype.fill = function (e, t, r, n) { - if ("string" == typeof e) { - if ("string" == typeof t ? (n = t, t = 0, r = this.length) : "string" == typeof r && (n = r, r = this.length), 1 === e.length) { - var i = e.charCodeAt(0); - i < 256 && (e = i) - } - if (void 0 !== n && "string" != typeof n) throw new TypeError("encoding must be a string"); - if ("string" == typeof n && !o.isEncoding(n)) throw new TypeError("Unknown encoding: " + n) - } else "number" == typeof e && (e &= 255); - if (t < 0 || this.length < t || this.length < r) throw new RangeError("Out of range index"); - if (r <= t) return this; - var a; - if (t >>>= 0, r = void 0 === r ? this.length : r >>> 0, e || (e = 0), "number" == typeof e) for (a = t; a < r; ++a) this[a] = e; else { - var s = o.isBuffer(e) ? e : new o(e, n), u = s.length; - for (a = 0; a < r - t; ++a) this[a + t] = s[a % u] - } - return this - }; - var T = /[^+/0-9A-Za-z-_]/g; - - function O(e) { - return e < 16 ? "0" + e.toString(16) : e.toString(16) - } - - function R(e, t) { - var r; - t = t || 1 / 0; - for (var n = e.length, i = null, a = [], s = 0; s < n; ++s) { - if ((r = e.charCodeAt(s)) > 55295 && r < 57344) { - if (!i) { - if (r > 56319) { - (t -= 3) > -1 && a.push(239, 191, 189); - continue - } - if (s + 1 === n) { - (t -= 3) > -1 && a.push(239, 191, 189); - continue - } - i = r; - continue - } - if (r < 56320) { - (t -= 3) > -1 && a.push(239, 191, 189), i = r; - continue - } - r = 65536 + (i - 55296 << 10 | r - 56320) - } else i && (t -= 3) > -1 && a.push(239, 191, 189); - if (i = null, r < 128) { - if ((t -= 1) < 0) break; - a.push(r) - } else if (r < 2048) { - if ((t -= 2) < 0) break; - a.push(r >> 6 | 192, 63 & r | 128) - } else if (r < 65536) { - if ((t -= 3) < 0) break; - a.push(r >> 12 | 224, r >> 6 & 63 | 128, 63 & r | 128) - } else { - if (!(r < 1114112)) throw new Error("Invalid code point"); - if ((t -= 4) < 0) break; - a.push(r >> 18 | 240, r >> 12 & 63 | 128, r >> 6 & 63 | 128, 63 & r | 128) - } - } - return a - } - - function D(e) { - return n.toByteArray(function (e) { - if ((e = e.trim().replace(T, "")).length < 2) return ""; - for (; e.length % 4 != 0;) e += "="; - return e - }(e)) - } - - function z(e, t, r, n) { - for (var i = 0; i < n && !(i + r >= t.length || i >= e.length); ++i) t[i + r] = e[i]; - return i - } - - function L(e) { - return e instanceof ArrayBuffer || null != e && null != e.constructor && "ArrayBuffer" === e.constructor.name && "number" == typeof e.byteLength - } - - function F(e) { - return "function" == typeof ArrayBuffer.isView && ArrayBuffer.isView(e) - } - - function N(e) { - return e != e - } - }, {"base64-js": 39, ieee754: 281}], - 44: [function (e, t, r) { - e("../../modules/es6.array.fill"), t.exports = e("../../modules/_core").Array.fill - }, {"../../modules/_core": 167, "../../modules/es6.array.fill": 237}], - 45: [function (e, t, r) { - e("../../modules/es6.array.find"), t.exports = e("../../modules/_core").Array.find - }, {"../../modules/_core": 167, "../../modules/es6.array.find": 238}], - 46: [function (e, t, r) { - e("../../modules/es6.string.iterator"), e("../../modules/es6.array.from"), t.exports = e("../../modules/_core").Array.from - }, {"../../modules/_core": 167, "../../modules/es6.array.from": 239, "../../modules/es6.string.iterator": 243}], - 47: [function (e, t, r) { - e("../modules/es6.object.to-string"), e("../modules/es6.string.iterator"), e("../modules/web.dom.iterable"), e("../modules/es6.promise"), e("../modules/es7.promise.finally"), e("../modules/es7.promise.try"), t.exports = e("../modules/_core").Promise - }, { - "../modules/_core": 167, - "../modules/es6.object.to-string": 241, - "../modules/es6.promise": 242, - "../modules/es6.string.iterator": 243, - "../modules/es7.promise.finally": 247, - "../modules/es7.promise.try": 248, - "../modules/web.dom.iterable": 251 - }], - 48: [function (e, t, r) { - e("../../modules/es6.string.repeat"), t.exports = e("../../modules/_core").String.repeat - }, {"../../modules/_core": 167, "../../modules/es6.string.repeat": 244}], - 49: [function (e, t, r) { - e("../../modules/es6.symbol"), e("../../modules/es6.object.to-string"), e("../../modules/es7.symbol.async-iterator"), e("../../modules/es7.symbol.observable"), t.exports = e("../../modules/_core").Symbol - }, { - "../../modules/_core": 167, - "../../modules/es6.object.to-string": 241, - "../../modules/es6.symbol": 245, - "../../modules/es7.symbol.async-iterator": 249, - "../../modules/es7.symbol.observable": 250 - }], - 50: [function (e, t, r) { - e("../../modules/es6.typed.uint8-array"), t.exports = e("../../modules/_core").Uint8Array - }, {"../../modules/_core": 167, "../../modules/es6.typed.uint8-array": 246}], - 51: [function (e, t, r) { - arguments[4][46][0].apply(r, arguments) - }, { - "../../modules/_core": 70, - "../../modules/es6.array.from": 139, - "../../modules/es6.string.iterator": 148, - dup: 46 - }], - 52: [function (e, t, r) { - e("../modules/web.dom.iterable"), e("../modules/es6.string.iterator"), t.exports = e("../modules/core.get-iterator") - }, { - "../modules/core.get-iterator": 137, - "../modules/es6.string.iterator": 148, - "../modules/web.dom.iterable": 154 - }], - 53: [function (e, t, r) { - e("../modules/web.dom.iterable"), e("../modules/es6.string.iterator"), t.exports = e("../modules/core.is-iterable") - }, { - "../modules/core.is-iterable": 138, - "../modules/es6.string.iterator": 148, - "../modules/web.dom.iterable": 154 - }], - 54: [function (e, t, r) { - var n = e("../../modules/_core"), i = n.JSON || (n.JSON = {stringify: JSON.stringify}); - t.exports = function (e) { - return i.stringify.apply(i, arguments) - } - }, {"../../modules/_core": 70}], - 55: [function (e, t, r) { - e("../../modules/es6.object.create"); - var n = e("../../modules/_core").Object; - t.exports = function (e, t) { - return n.create(e, t) - } - }, {"../../modules/_core": 70, "../../modules/es6.object.create": 141}], - 56: [function (e, t, r) { - e("../../modules/es6.object.define-property"); - var n = e("../../modules/_core").Object; - t.exports = function (e, t, r) { - return n.defineProperty(e, t, r) - } - }, {"../../modules/_core": 70, "../../modules/es6.object.define-property": 142}], - 57: [function (e, t, r) { - e("../../modules/es6.object.freeze"), t.exports = e("../../modules/_core").Object.freeze - }, {"../../modules/_core": 70, "../../modules/es6.object.freeze": 143}], - 58: [function (e, t, r) { - e("../../modules/es6.object.get-prototype-of"), t.exports = e("../../modules/_core").Object.getPrototypeOf - }, {"../../modules/_core": 70, "../../modules/es6.object.get-prototype-of": 144}], - 59: [function (e, t, r) { - e("../../modules/es6.object.set-prototype-of"), t.exports = e("../../modules/_core").Object.setPrototypeOf - }, {"../../modules/_core": 70, "../../modules/es6.object.set-prototype-of": 145}], - 60: [function (e, t, r) { - arguments[4][47][0].apply(r, arguments) - }, { - "../modules/_core": 70, - "../modules/es6.object.to-string": 146, - "../modules/es6.promise": 147, - "../modules/es6.string.iterator": 148, - "../modules/es7.promise.finally": 150, - "../modules/es7.promise.try": 151, - "../modules/web.dom.iterable": 154, - dup: 47 - }], - 61: [function (e, t, r) { - arguments[4][49][0].apply(r, arguments) - }, { - "../../modules/_core": 70, - "../../modules/es6.object.to-string": 146, - "../../modules/es6.symbol": 149, - "../../modules/es7.symbol.async-iterator": 152, - "../../modules/es7.symbol.observable": 153, - dup: 49 - }], - 62: [function (e, t, r) { - e("../../modules/es6.string.iterator"), e("../../modules/web.dom.iterable"), t.exports = e("../../modules/_wks-ext").f("iterator") - }, { - "../../modules/_wks-ext": 134, - "../../modules/es6.string.iterator": 148, - "../../modules/web.dom.iterable": 154 - }], - 63: [function (e, t, r) { - t.exports = function (e) { - if ("function" != typeof e) throw TypeError(e + " is not a function!"); - return e - } - }, {}], - 64: [function (e, t, r) { - t.exports = function () { - } - }, {}], - 65: [function (e, t, r) { - t.exports = function (e, t, r, n) { - if (!(e instanceof t) || void 0 !== n && n in e) throw TypeError(r + ": incorrect invocation!"); - return e - } - }, {}], - 66: [function (e, t, r) { - var n = e("./_is-object"); - t.exports = function (e) { - if (!n(e)) throw TypeError(e + " is not an object!"); - return e - } - }, {"./_is-object": 90}], - 67: [function (e, t, r) { - var n = e("./_to-iobject"), i = e("./_to-length"), a = e("./_to-absolute-index"); - t.exports = function (e) { - return function (t, r, s) { - var o, u = n(t), f = i(u.length), c = a(s, f); - if (e && r != r) { - for (; f > c;) if ((o = u[c++]) != o) return !0 - } else for (; f > c; c++) if ((e || c in u) && u[c] === r) return e || c || 0; - return !e && -1 - } - } - }, {"./_to-absolute-index": 126, "./_to-iobject": 128, "./_to-length": 129}], - 68: [function (e, t, r) { - var n = e("./_cof"), i = e("./_wks")("toStringTag"), a = "Arguments" == n(function () { - return arguments - }()); - t.exports = function (e) { - var t, r, s; - return void 0 === e ? "Undefined" : null === e ? "Null" : "string" == typeof(r = function (e, t) { - try { - return e[t] - } catch (e) { - } - }(t = Object(e), i)) ? r : a ? n(t) : "Object" == (s = n(t)) && "function" == typeof t.callee ? "Arguments" : s - } - }, {"./_cof": 69, "./_wks": 135}], - 69: [function (e, t, r) { - var n = {}.toString; - t.exports = function (e) { - return n.call(e).slice(8, -1) - } - }, {}], - 70: [function (e, t, r) { - var n = t.exports = {version: "2.5.3"}; - "number" == typeof __e && (__e = n) - }, {}], - 71: [function (e, t, r) { - "use strict"; - var n = e("./_object-dp"), i = e("./_property-desc"); - t.exports = function (e, t, r) { - t in e ? n.f(e, t, i(0, r)) : e[t] = r - } - }, {"./_object-dp": 102, "./_property-desc": 115}], - 72: [function (e, t, r) { - var n = e("./_a-function"); - t.exports = function (e, t, r) { - if (n(e), void 0 === t) return e; - switch (r) { - case 1: - return function (r) { - return e.call(t, r) - }; - case 2: - return function (r, n) { - return e.call(t, r, n) - }; - case 3: - return function (r, n, i) { - return e.call(t, r, n, i) - } - } - return function () { - return e.apply(t, arguments) - } - } - }, {"./_a-function": 63}], - 73: [function (e, t, r) { - t.exports = function (e) { - if (void 0 == e) throw TypeError("Can't call method on " + e); - return e - } - }, {}], - 74: [function (e, t, r) { - t.exports = !e("./_fails")(function () { - return 7 != Object.defineProperty({}, "a", { - get: function () { - return 7 - } - }).a - }) - }, {"./_fails": 79}], - 75: [function (e, t, r) { - var n = e("./_is-object"), i = e("./_global").document, a = n(i) && n(i.createElement); - t.exports = function (e) { - return a ? i.createElement(e) : {} - } - }, {"./_global": 81, "./_is-object": 90}], - 76: [function (e, t, r) { - t.exports = "constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",") - }, {}], - 77: [function (e, t, r) { - var n = e("./_object-keys"), i = e("./_object-gops"), a = e("./_object-pie"); - t.exports = function (e) { - var t = n(e), r = i.f; - if (r) for (var s, o = r(e), u = a.f, f = 0; o.length > f;) u.call(e, s = o[f++]) && t.push(s); - return t - } - }, {"./_object-gops": 107, "./_object-keys": 110, "./_object-pie": 111}], - 78: [function (e, t, r) { - var n = e("./_global"), i = e("./_core"), a = e("./_ctx"), s = e("./_hide"), o = function (e, t, r) { - var u, f, c, d = e & o.F, l = e & o.G, h = e & o.S, p = e & o.P, y = e & o.B, b = e & o.W, - m = l ? i : i[t] || (i[t] = {}), g = m.prototype, v = l ? n : h ? n[t] : (n[t] || {}).prototype; - for (u in l && (r = t), r) (f = !d && v && void 0 !== v[u]) && u in m || (c = f ? v[u] : r[u], m[u] = l && "function" != typeof v[u] ? r[u] : y && f ? a(c, n) : b && v[u] == c ? function (e) { - var t = function (t, r, n) { - if (this instanceof e) { - switch (arguments.length) { - case 0: - return new e; - case 1: - return new e(t); - case 2: - return new e(t, r) - } - return new e(t, r, n) - } - return e.apply(this, arguments) - }; - return t.prototype = e.prototype, t - }(c) : p && "function" == typeof c ? a(Function.call, c) : c, p && ((m.virtual || (m.virtual = {}))[u] = c, e & o.R && g && !g[u] && s(g, u, c))) - }; - o.F = 1, o.G = 2, o.S = 4, o.P = 8, o.B = 16, o.W = 32, o.U = 64, o.R = 128, t.exports = o - }, {"./_core": 70, "./_ctx": 72, "./_global": 81, "./_hide": 83}], - 79: [function (e, t, r) { - t.exports = function (e) { - try { - return !!e() - } catch (e) { - return !0 - } - } - }, {}], - 80: [function (e, t, r) { - var n = e("./_ctx"), i = e("./_iter-call"), a = e("./_is-array-iter"), s = e("./_an-object"), - o = e("./_to-length"), u = e("./core.get-iterator-method"), f = {}, c = {}; - (r = t.exports = function (e, t, r, d, l) { - var h, p, y, b, m = l ? function () { - return e - } : u(e), g = n(r, d, t ? 2 : 1), v = 0; - if ("function" != typeof m) throw TypeError(e + " is not iterable!"); - if (a(m)) { - for (h = o(e.length); h > v; v++) if ((b = t ? g(s(p = e[v])[0], p[1]) : g(e[v])) === f || b === c) return b - } else for (y = m.call(e); !(p = y.next()).done;) if ((b = i(y, g, p.value, t)) === f || b === c) return b - }).BREAK = f, r.RETURN = c - }, { - "./_an-object": 66, - "./_ctx": 72, - "./_is-array-iter": 88, - "./_iter-call": 91, - "./_to-length": 129, - "./core.get-iterator-method": 136 - }], - 81: [function (e, t, r) { - var n = t.exports = "undefined" != typeof window && window.Math == Math ? window : "undefined" != typeof self && self.Math == Math ? self : Function("return this")(); - "number" == typeof __g && (__g = n) - }, {}], - 82: [function (e, t, r) { - var n = {}.hasOwnProperty; - t.exports = function (e, t) { - return n.call(e, t) - } - }, {}], - 83: [function (e, t, r) { - var n = e("./_object-dp"), i = e("./_property-desc"); - t.exports = e("./_descriptors") ? function (e, t, r) { - return n.f(e, t, i(1, r)) - } : function (e, t, r) { - return e[t] = r, e - } - }, {"./_descriptors": 74, "./_object-dp": 102, "./_property-desc": 115}], - 84: [function (e, t, r) { - var n = e("./_global").document; - t.exports = n && n.documentElement - }, {"./_global": 81}], - 85: [function (e, t, r) { - t.exports = !e("./_descriptors") && !e("./_fails")(function () { - return 7 != Object.defineProperty(e("./_dom-create")("div"), "a", { - get: function () { - return 7 - } - }).a - }) - }, {"./_descriptors": 74, "./_dom-create": 75, "./_fails": 79}], - 86: [function (e, t, r) { - t.exports = function (e, t, r) { - var n = void 0 === r; - switch (t.length) { - case 0: - return n ? e() : e.call(r); - case 1: - return n ? e(t[0]) : e.call(r, t[0]); - case 2: - return n ? e(t[0], t[1]) : e.call(r, t[0], t[1]); - case 3: - return n ? e(t[0], t[1], t[2]) : e.call(r, t[0], t[1], t[2]); - case 4: - return n ? e(t[0], t[1], t[2], t[3]) : e.call(r, t[0], t[1], t[2], t[3]) - } - return e.apply(r, t) - } - }, {}], - 87: [function (e, t, r) { - var n = e("./_cof"); - t.exports = Object("z").propertyIsEnumerable(0) ? Object : function (e) { - return "String" == n(e) ? e.split("") : Object(e) - } - }, {"./_cof": 69}], - 88: [function (e, t, r) { - var n = e("./_iterators"), i = e("./_wks")("iterator"), a = Array.prototype; - t.exports = function (e) { - return void 0 !== e && (n.Array === e || a[i] === e) - } - }, {"./_iterators": 96, "./_wks": 135}], - 89: [function (e, t, r) { - var n = e("./_cof"); - t.exports = Array.isArray || function (e) { - return "Array" == n(e) - } - }, {"./_cof": 69}], - 90: [function (e, t, r) { - t.exports = function (e) { - return "object" == typeof e ? null !== e : "function" == typeof e - } - }, {}], - 91: [function (e, t, r) { - var n = e("./_an-object"); - t.exports = function (e, t, r, i) { - try { - return i ? t(n(r)[0], r[1]) : t(r) - } catch (t) { - var a = e.return; - throw void 0 !== a && n(a.call(e)), t - } - } - }, {"./_an-object": 66}], - 92: [function (e, t, r) { - "use strict"; - var n = e("./_object-create"), i = e("./_property-desc"), a = e("./_set-to-string-tag"), s = {}; - e("./_hide")(s, e("./_wks")("iterator"), function () { - return this - }), t.exports = function (e, t, r) { - e.prototype = n(s, {next: i(1, r)}), a(e, t + " Iterator") - } - }, { - "./_hide": 83, - "./_object-create": 101, - "./_property-desc": 115, - "./_set-to-string-tag": 120, - "./_wks": 135 - }], - 93: [function (e, t, r) { - "use strict"; - var n = e("./_library"), i = e("./_export"), a = e("./_redefine"), s = e("./_hide"), o = e("./_has"), - u = e("./_iterators"), f = e("./_iter-create"), c = e("./_set-to-string-tag"), d = e("./_object-gpo"), - l = e("./_wks")("iterator"), h = !([].keys && "next" in [].keys()), p = function () { - return this - }; - t.exports = function (e, t, r, y, b, m, g) { - f(r, t, y); - var v, _, w, k = function (e) { - if (!h && e in E) return E[e]; - switch (e) { - case"keys": - case"values": - return function () { - return new r(this, e) - } - } - return function () { - return new r(this, e) - } - }, A = t + " Iterator", x = "values" == b, S = !1, E = e.prototype, - M = E[l] || E["@@iterator"] || b && E[b], C = !h && M || k(b), - j = b ? x ? k("entries") : C : void 0, P = "Array" == t && E.entries || M; - if (P && (w = d(P.call(new e))) !== Object.prototype && w.next && (c(w, A, !0), n || o(w, l) || s(w, l, p)), x && M && "values" !== M.name && (S = !0, C = function () { - return M.call(this) - }), n && !g || !h && !S && E[l] || s(E, l, C), u[t] = C, u[A] = p, b) if (v = { - values: x ? C : k("values"), - keys: m ? C : k("keys"), - entries: j - }, g) for (_ in v) _ in E || a(E, _, v[_]); else i(i.P + i.F * (h || S), t, v); - return v - } - }, { - "./_export": 78, - "./_has": 82, - "./_hide": 83, - "./_iter-create": 92, - "./_iterators": 96, - "./_library": 97, - "./_object-gpo": 108, - "./_redefine": 117, - "./_set-to-string-tag": 120, - "./_wks": 135 - }], - 94: [function (e, t, r) { - var n = e("./_wks")("iterator"), i = !1; - try { - var a = [7][n](); - a.return = function () { - i = !0 - }, Array.from(a, function () { - throw 2 - }) - } catch (e) { - } - t.exports = function (e, t) { - if (!t && !i) return !1; - var r = !1; - try { - var a = [7], s = a[n](); - s.next = function () { - return {done: r = !0} - }, a[n] = function () { - return s - }, e(a) - } catch (e) { - } - return r - } - }, {"./_wks": 135}], - 95: [function (e, t, r) { - t.exports = function (e, t) { - return {value: t, done: !!e} - } - }, {}], - 96: [function (e, t, r) { - t.exports = {} - }, {}], - 97: [function (e, t, r) { - t.exports = !0 - }, {}], - 98: [function (e, t, r) { - var n = e("./_uid")("meta"), i = e("./_is-object"), a = e("./_has"), s = e("./_object-dp").f, o = 0, - u = Object.isExtensible || function () { - return !0 - }, f = !e("./_fails")(function () { - return u(Object.preventExtensions({})) - }), c = function (e) { - s(e, n, {value: {i: "O" + ++o, w: {}}}) - }, d = t.exports = { - KEY: n, NEED: !1, fastKey: function (e, t) { - if (!i(e)) return "symbol" == typeof e ? e : ("string" == typeof e ? "S" : "P") + e; - if (!a(e, n)) { - if (!u(e)) return "F"; - if (!t) return "E"; - c(e) - } - return e[n].i - }, getWeak: function (e, t) { - if (!a(e, n)) { - if (!u(e)) return !0; - if (!t) return !1; - c(e) - } - return e[n].w - }, onFreeze: function (e) { - return f && d.NEED && u(e) && !a(e, n) && c(e), e - } - } - }, {"./_fails": 79, "./_has": 82, "./_is-object": 90, "./_object-dp": 102, "./_uid": 132}], - 99: [function (e, t, r) { - var n = e("./_global"), i = e("./_task").set, a = n.MutationObserver || n.WebKitMutationObserver, - s = n.process, o = n.Promise, u = "process" == e("./_cof")(s); - t.exports = function () { - var e, t, r, f = function () { - var n, i; - for (u && (n = s.domain) && n.exit(); e;) { - i = e.fn, e = e.next; - try { - i() - } catch (n) { - throw e ? r() : t = void 0, n - } - } - t = void 0, n && n.enter() - }; - if (u) r = function () { - s.nextTick(f) - }; else if (!a || n.navigator && n.navigator.standalone) if (o && o.resolve) { - var c = o.resolve(); - r = function () { - c.then(f) - } - } else r = function () { - i.call(n, f) - }; else { - var d = !0, l = document.createTextNode(""); - new a(f).observe(l, {characterData: !0}), r = function () { - l.data = d = !d - } - } - return function (n) { - var i = {fn: n, next: void 0}; - t && (t.next = i), e || (e = i, r()), t = i - } - } - }, {"./_cof": 69, "./_global": 81, "./_task": 125}], - 100: [function (e, t, r) { - "use strict"; - var n = e("./_a-function"); - t.exports.f = function (e) { - return new function (e) { - var t, r; - this.promise = new e(function (e, n) { - if (void 0 !== t || void 0 !== r) throw TypeError("Bad Promise constructor"); - t = e, r = n - }), this.resolve = n(t), this.reject = n(r) - }(e) - } - }, {"./_a-function": 63}], - 101: [function (e, t, r) { - var n = e("./_an-object"), i = e("./_object-dps"), a = e("./_enum-bug-keys"), - s = e("./_shared-key")("IE_PROTO"), o = function () { - }, u = function () { - var t, r = e("./_dom-create")("iframe"), n = a.length; - for (r.style.display = "none", e("./_html").appendChild(r), r.src = "javascript:", (t = r.contentWindow.document).open(), t.write(" - - - -
- - - - - -

- Jump to Page: • Show: - -
- - - - * - * Initialize ufTable on your container object: - * - * $("#widget-users").ufTable(options); - * - * `options` is an object containing any of the following parameters: - * @param {string} dataUrl The absolute URL from which to fetch table data. - * @param {mixed} addParams An object containing any additional key-value pairs that you want appended to the AJAX requests. - * @param {mixed} tablesorter An object containing tablesorter's configuration options (https://mottie.github.io/tablesorter/docs/#Configuration) - * @param {mixed} pager An object containing tablesorter's paging options (https://mottie.github.io/tablesorter/docs/#pager) - * - * == EVENTS == - * - * ufTable triggers the following events: - * - * `pagerComplete.ufTable`: triggered when the tablesorter pager plugin has completed rendering of the table. - * - * == METHODS == - * - * `getTableStateVars( table )`: fetches the current page size, page number, sort order, sort field, and column filters. - * - * UserFrosting https://www.userfrosting.com - * @author Alexander Weissman - */ -;(function ($, window, document, undefined) { - 'use strict'; - - // Define plugin name and defaults. - var pluginName = 'ufTable', - defaults = { - DEBUG: false, - site: site, // global site variables - dataUrl: '', - msgTarget: $('#alerts-page'), - addParams: {}, - filterAllField: '_all', - useLoadingTransition: true, - rowTemplate: null, - columnTemplates: {}, - tablesorter: { - debug: false, - theme: 'bootstrap', - widthFixed: true, - // Set up pagination of data via an AJAX source - // See http://jsfiddle.net/Mottie/uwZc2/ - // Also see https://mottie.github.io/tablesorter/docs/example-pager-ajax.html - widgets: ['saveSort', 'sort2Hash', 'filter', 'pager', 'columnSelector', 'reflow2'], - widgetOptions: { - columnSelector_layout: '', - filter_cssFilter: 'form-control', - filter_saveFilters: true, - filter_serversideFiltering: true, - filter_selectSource: { - '.filter-select': function () { - return null; - } - }, - - // apply disabled classname to the pager arrows when the rows at either extreme is visible - pager_updateArrows: true, - - // starting page of the pager (zero based index) - pager_startPage: 0, - - // Number of visible rows - pager_size: 10, - - // Save pager page & size if the storage script is loaded (requires $.tablesorter.storage in jquery.tablesorter.widgets.js) - pager_savePages: true, - - // if true, the table will remain the same height no matter how many records are displayed. The space is made up by an empty - // table row set to a height to compensate; default is false - pager_fixedHeight: false, - - // remove rows from the table to speed up the sort of large tables. - // setting this to false, only hides the non-visible rows; needed if you plan to add/remove rows with the pager enabled. - pager_removeRows: false, // removing rows in larger tables speeds up the sort - - // target the pager markup - see the HTML block below - pager_css: { - errorRow: 'uf-table-error-row', // error information row - disabled: 'disabled' // Note there is no period "." in front of this class name - }, - - // Must be initialized with a 'data' key - pager_ajaxObject: { - data: {}, - dataType: 'json' - }, - - // hash prefix - sort2Hash_hash: '#', - // don't '#' or '=' here - sort2Hash_separator: '|', - // this option > table ID > table index on page - sort2Hash_tableId: null, - // if true, show header cell text instead of a zero-based column index - sort2Hash_headerTextAttr: 'data-column-name', - // direction text shown in the URL e.g. [ 'asc', 'desc' ] - sort2Hash_directionText: ['asc', 'desc'], // default values - // if true, override saveSort widget sort, if used & stored sort is available - sort2Hash_overrideSaveSort: true, // default = false - } - } - }; - - // Constructor - function Plugin(element, options) { - this.element = element[0]; - this.$element = $(this.element); - - var lateDefaults = { - download: { - button: this.$element.find('.js-uf-table-download'), - callback: $.proxy(this._onDownload, this) - }, - info: { - container: this.$element.find('.js-uf-table-info'), - callback: $.proxy(this._renderInfoMessages, this) - }, - overlay: { - container: this.$element.find('.js-uf-table-overlay') - }, - tableElement: this.$element.find('.tablesorter'), - tablesorter: { - widgetOptions: { - columnSelector_container: this.$element.find('.js-uf-table-cs-options'), - filter_external: this.$element.find('.js-uf-table-search input'), - - // Pager selectors - pager_selectors: { - container: this.$element.find('.js-uf-table-pager'), - first: '.first', // go to first page arrow - prev: '.prev', // previous page arrow - next: '.next', // next page arrow - last: '.last', // go to last page arrow - gotoPage: '.gotoPage', // go to page selector - select dropdown that sets the current page - pageDisplay: '.pagedisplay', // location of where the "output" is displayed - pageSize: '.pagesize' // page size selector - select dropdown that sets the "size" option - }, - // We need to use $.proxy to properly bind the context for callbacks that will be called by Tablesorter - - // Generate the URL for the AJAX request, with the relevant parameters - pager_customAjaxUrl: $.proxy(this._generateUrl, this), - - // Callback to process the response from the AJAX request - pager_ajaxProcessing: $.proxy(this._processAjax, this), - - // Callback to display errors - pager_ajaxError: $.proxy(this._pagerAjaxError, this), - - sort2Hash_encodeHash: $.proxy(this._encodeHash, this), - - sort2Hash_decodeHash: $.proxy(this._decodeHash, this), - - sort2Hash_cleanHash: $.proxy(this._cleanHash, this) - } - } - }; - this.settings = $.extend(true, {}, defaults, lateDefaults, options); - this._defaults = defaults; - this._name = pluginName; - this._debugAjax = (typeof this.settings.site !== 'undefined') && this.settings.site.debug.ajax; - - // Fall back to attributes from data-*, default values if not specified in options - var pagerContainer = this.settings.tablesorter.widgetOptions.pager_selectors.container; - var infoContainer = this.settings.info.container; - var dataAttributeDefaults = { - info: { - messageEmptyRows: infoContainer.data('message-empty-rows') ? - infoContainer.data('message-empty-rows') : - "Sorry, we've got nothing here." - }, - tablesorter: { - widgetOptions: { - // possible variables: {size}, {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} - // also {page:input} & {startRow:input} will add a modifiable input in place of the value - pager_output: pagerContainer.data('output-template') ? - pagerContainer.data('output-template') : - '{startRow} to {endRow} of {filteredRows} ({totalRows})' // default if not set on data-* attribute - } - } - }; - - this.settings = $.extend(true, {}, dataAttributeDefaults, this.settings); - - // Check that tableElement exists - var tableElement = this.settings.tableElement; - if (!tableElement.length) { - if (window.console && console.error) { - console.error('ufTable could not be initialized: wrapper element does not exist, or does not contain a matched tableElement (see https://learn.userfrosting.com/client-side-code/components/tables )'); - } - return; - } - - // Copy over dataUrl to pager_ajaxUrl - this.settings.tablesorter.widgetOptions.pager_ajaxUrl = this.settings.dataUrl; - - // Set up 'loading' overlays - if (this.settings.useLoadingTransition) { - var overlay = this.settings.overlay.container; - tableElement.bind('sortStart filterStart pageMoved', function () { - overlay.removeClass('hidden'); - }).bind('pagerComplete updateComplete', function () { - overlay.addClass('hidden'); - }); - } - - // Set up tablesorter and pager - this.ts = tableElement.tablesorter(this.settings.tablesorter); - - // Map default column template selectors based on data-column-template attribute in each column header - var columns = this.ts[0].config.$headerIndexed; - var columnTemplates = {}; - for (var col = 0; col < columns.length; col++) { - var columnName = columns[col].data('column-name'); - if (!columnName && this.settings.DEBUG) { - console.error('Column number ' + col + ' is missing a data-column-name attribute.'); - } - columnTemplates[columnName] = columns[col].data('column-template'); - } - - // Merge in any column template selectors that were set in the ctor options - columnTemplates = $.extend(true, columnTemplates, this.settings.columnTemplates); - - // Locate and compile templates for any string-identified column renderers - // At the same time, build out a numerically indexed array of templates - this.columnTemplatesIndexed = []; - for (var col = 0; col < columns.length; col++) { - var columnName = columns[col].data('column-name'); - if (!columnTemplates[columnName] && this.settings.DEBUG) { - console.error("No template found for column '" + columnName + "'."); - } - var columnTemplate = columnTemplates[columnName]; - if (typeof columnTemplate === 'string') { - this.columnTemplatesIndexed.push(Handlebars.compile($(columnTemplate).html())); - } else { - this.columnTemplatesIndexed.push(columnTemplate); - } - } - - // Locate and compile row template - this.rowTemplate = Handlebars.compile(''); - // If rowTemplateSelector is set, then find the DOM element that it references, which contains the template - if (this.settings.rowTemplate) { - var rowTemplate = this.settings.rowTemplate; - if (typeof rowTemplate === 'string') { - this.rowTemplate = Handlebars.compile($(this.settings.rowTemplate).html()); - } else { - this.rowTemplate = rowTemplate; - } - } - - // Link CSV download button - this.settings.download.button.on('click', this.settings.download.callback); - - // Allow clicking on the labels in the table menu without closing the menu - $(this.settings.tablesorter.widgetOptions.columnSelector_container).find('label').on('click', function (e) { - e.stopPropagation(); - }); - - // Propagate our own pagerComplete event - this.ts.on('pagerComplete', $.proxy(function () { - this.$element.trigger('pagerComplete.ufTable'); - }, this)); - - // Show info messages when there are no rows/no results - this.ts.on('filterEnd filterReset pagerComplete', this.settings.info.callback); - - // Detect changes to element attributes - this.$element.attrchange({ - callback: function (event) { - this.element = event.target; - }.bind(this) - }); - - return this; - } - - /** - * Get state variables for this table, as required by the AJAX data source: sorts, filters, size, page - */ - Plugin.prototype.getTableStateVars = function (table) { - var base = this; - - // Get sort column and order - var sortOrders = { - '0': 'asc', - '1': 'desc' - }; - - // Set sorts in URL. Assumes each th has a data-column-name attribute that corresponds to the name in the API - var sortList = table.config.sortList; - var sorts = {}; - for (var i = 0; i < sortList.length; i++) { - var columnIndex = sortList[i][0]; - var columnDirection = sortOrders[sortList[i][1]]; // Converts to 'asc' or 'desc' - if (sortList[i]) { - var columnName = table.config.$headerIndexed[columnIndex].data('column-name'); - sorts[columnName] = columnDirection; - } - } - - // Set filters in URL. Assumes each th has a data-column-name attribute that corresponds to the name in the API - var filterList = base.getSavedFilters(table); - var filters = {}; - for (i = 0; i < filterList.length; i++) { - if (filterList[i]) { - var columnName = base.settings.filterAllField; - - if (table.config.$headerIndexed[i]) { - columnName = table.config.$headerIndexed[i].data('column-name'); - } - - filters[columnName] = filterList[i]; - } - } - - var state = { - size: table.config.pager.size, - page: table.config.pager.page, - sorts: sorts, - filters: filters - }; - - return state; - }; - - /** - * Get saved filters from the browser local storage. Those should always be up to date - */ - Plugin.prototype.getSavedFilters = function (table) { - - // Fallback to `getFilters` or empty in case of failure - var filterList = $.tablesorter.getFilters(table) || []; - - // Overwrite list with saved filter for filter-select not setup by ts - var isArray, saved, - wo = table.config.widgetOptions; - if (wo.filter_saveFilters && $.tablesorter.storage) { - saved = $.tablesorter.storage(table, 'tablesorter-filters') || []; - isArray = $.isArray(saved); - // make sure we're not just getting an empty array - if (!(isArray && saved.join('') === '' || !isArray)) { - filterList = $.tablesorter.filter.processFilters(saved); - } - } - - return filterList; - }; - - /** - * Generate the AJAX url. - * Used as the default callback for pager_customAjaxUrl - * @private - */ - Plugin.prototype._generateUrl = function (table, url) { - var tableState = this.getTableStateVars(table); - - if (this.settings.DEBUG) { - console.log(tableState); - } - - $.extend(table.config.pager.ajaxObject.data, tableState); - - // Merge in any additional parameters - $.extend(table.config.pager.ajaxObject.data, this.settings.addParams); - - return url; - }; - /** - * Process data returned from the AJAX request and rendering the table cells. - * Used as the default callback for pager_ajaxProcessing - * @private - */ - Plugin.prototype._processAjax = function (data) { - var ts = this.ts[0]; - var json = {}, - rows = ''; - - if (data) { - var size = data.rows.length; - - // Render table rows and cells via Handlebars - for (var row = 0; row < size; row++) { - var cellData = { - rownum: row, - row: data.rows[row], // It is safe to use the data from the API because Handlebars escapes HTML - site: this.settings.site - }; - - rows += this.rowTemplate(cellData); - - for (var col = 0; col < this.columnTemplatesIndexed.length; col++) { - rows += this.columnTemplatesIndexed[col](cellData); - } - - rows += ''; - } - - // Initialize any dropdown filters - var columns = ts.config.$headerIndexed; - this._ajaxInitFilterSelects(columns, data.listable); - - json.total = data.count; // Get total rows without pagination - json.filteredRows = data.count_filtered; // no filtering - json.rows = $(rows); - json.output = data.output; - } else { - json.total = 0; - json.filteredRows = 0; - json.rows = ''; - } - - return json; - }; - - /** - * Initialize filter select menus using the ajax `listable` values - * @private - */ - Plugin.prototype._ajaxInitFilterSelects = function (columns, listable) { - var ts = this.ts[0]; - var filters = this.getSavedFilters(ts); - // Find columns with `.filter-select` and match them to column numbers based on their data-column-name - for (var col = 0; col < columns.length; col++) { - var column = columns[col]; - // If the column is designated for filter-select, get the listables from the data and recreate it - if (column.hasClass('filter-select')) { - var columnName = column.data('column-name'); - if (listable[columnName]) { - $.tablesorter.filter.buildSelect(ts, col, listable[columnName], true); - // If there is a filter actually set for this column, update the selected option. - if (filters[col]) { - var selectControl = $(ts).find(".tablesorter-filter[data-column='" + col + "']"); - selectControl.val(filters[col]); - } - } - } - } - }; - - /** - * Implements handler for the "download CSV" button. - * Default callback for download.callback - * @private - */ - Plugin.prototype._onDownload = function () { - var tableState = this.getTableStateVars(this.ts[0]); - tableState.format = 'csv'; - delete tableState.page; - delete tableState.size; - - // Merge in any additional request parameters - $.extend(tableState, this.settings.addParams); - - // Causes download to begin - window.location = this.settings.dataUrl + '?' + $.param(tableState); - }; - - /** - * Handle pager ajax errors. - * @private - */ - Plugin.prototype._pagerAjaxError = function (c, jqXHR, settings, exception) { - this._ajaxError(jqXHR); - - // Let TS handle the in-table error message - return ''; - }; - - /** - * Handle ajax error - * @private - */ - Plugin.prototype._ajaxError = function (jqXHR) { - if (typeof jqXHR === 'object') { - // Error messages - if (this._debugAjax && jqXHR.responseText) { - document.write(jqXHR.responseText); - document.close(); - } else { - if (this.settings.DEBUG) { - console.log('Error (' + jqXHR.status + '): ' + jqXHR.responseText); - } - // Display errors on failure - // ufAlerts widget should have a 'destroy' method - if (!this.settings.msgTarget.data('ufAlerts')) { - this.settings.msgTarget.ufAlerts(); - } else { - this.settings.msgTarget.ufAlerts('clear'); - } - - this.settings.msgTarget.ufAlerts('fetch').ufAlerts('render'); - } - } - }; - - /** - * Render info messages, such as when there are no results. - * Default callback for info.callback - * @private - */ - Plugin.prototype._renderInfoMessages = function () { - var table = this.ts[0]; - var infoMessages = this.settings.info.container; - if (table.config.pager) { - infoMessages.html(''); - var fr = table.config.pager.filteredRows; - if (fr === 0) { - infoMessages.html(this.settings.info.messageEmptyRows); - } - } - }; - - /** - * Encode the current table state variables into a URL hash. - * Default callback for sort2Hash_encodeHash - * @private - */ - Plugin.prototype._encodeHash = function (config, tableId, component, value, rawValue) { - var wo = config.widgetOptions; - if (component === 'filter') { - // rawValue is an array of filter values, numerically indexed - var encodedFilters = ''; - var len = rawValue.length; - for (var index = 0; index < len; index++) { - if (rawValue[index]) { - var columnName = this.settings.filterAllField; - if (config.$headerIndexed[index]) { - columnName = $(config.$headerIndexed[index][0]).attr(wo.sort2Hash_headerTextAttr); - } - encodedFilters += '&filter[' + tableId + '][' + columnName + ']=' + encodeURIComponent(rawValue[index]); - } - } - return encodedFilters; - } else if (component === 'sort') { - // rawValue is an array of sort pairs [columnNum, sortDirection] - var encodedFilters = ''; - var len = rawValue.length; - for (var index = 0; index < len; index++) { - var columnNum = rawValue[index][0]; - var sortDirection = rawValue[index][1]; - var columnName = $(config.$headerIndexed[columnNum][0]).attr(wo.sort2Hash_headerTextAttr); - encodedFilters += '&sort[' + tableId + '][' + columnName + ']=' + wo.sort2Hash_directionText[sortDirection]; - } - return encodedFilters; - } - return false; - }; - - /** - * Decode the current table state variables from the URL hash. - * Default callback for sort2Hash_decodeHash - * @private - */ - Plugin.prototype._decodeHash = function (config, tableId, component) { - var wo = config.widgetOptions; - var result; - // Convert hash into JSON object - var urlObject = $.String.deparam(window.location.hash); - delete urlObject[wo.sort2Hash_hash]; // Remove hash character - if (component === 'filter') { - var decodedFilters = []; - // Extract filter names and values for the specified table - var pageFilters = urlObject.filter ? urlObject.filter : []; - if (pageFilters[tableId]) { - var tableFilters = pageFilters[tableId]; - // Build a numerically indexed array of filter values - var len = config.$headerIndexed.length; - for (var index = 0; index < len; index++) { - var columnName = $(config.$headerIndexed[index][0]).attr(wo.sort2Hash_headerTextAttr); - if (tableFilters[columnName] && tableFilters[columnName] != this.settings.filterAllField) { - decodedFilters.push(tableFilters[columnName]); - } else { - decodedFilters.push(''); - } - } - // Convert array of filter values to a delimited string - result = decodedFilters.join(wo.sort2Hash_separator); - // make sure to use decodeURIComponent on the result - return decodeURIComponent(result); - } else { - return ''; - } - } - return false; - }; - - /** - * Clean up URL hash. - * Default callback for sort2Hash_cleanHash - * @private - */ - Plugin.prototype._cleanHash = function (config, tableId, component, hash) { - var wo = config.widgetOptions; - // Convert hash to JSON object - var urlObject = $.String.deparam(hash); - delete urlObject[wo.sort2Hash_hash]; // Remove hash character - // Remove specified component for specified table - if (urlObject[component]) { - if (urlObject[component][tableId]) { - delete urlObject[component][tableId]; - } - // Delete entire component if no other tables remaining - if (jQuery.isEmptyObject(urlObject[component])) { - delete urlObject[component]; - } - } - // Convert modified JSON object back into serialized representation - var result = decodeURIComponent(jQuery.param(urlObject)); - return result.length ? result : ''; - }; - - // Handles instantiation and access to non-private methods. - $.fn[pluginName] = function (methodOrOptions) { - // Grab plugin instance - var instance = $(this).data(pluginName); - // If undefined or object, initalise plugin. - if (methodOrOptions === undefined || typeof methodOrOptions === 'object') { - // Only initalise if not previously done. - if (!instance) { - $(this).data(pluginName, new Plugin(this, methodOrOptions)); - } - return this; - // Otherwise ensure first parameter is a valid string, and is the name of an actual function. - } else if (typeof methodOrOptions === 'string' && typeof instance[methodOrOptions] === 'function') { - // Ensure not a private function - if (methodOrOptions.indexOf('_') !== 0) { - return instance[methodOrOptions](Array.prototype.slice.call(arguments, 1)); - } - else { - console.warn('Method ' + methodOrOptions + ' is private!'); - } - } else { - console.warn('Method ' + methodOrOptions + ' does not exist.'); - } - }; -})(jQuery, window, document); +/** + * uf-table plugin. Sets up a Tablesorter table with sorting, pagination, and search, and fetches data from a JSON API. + * + * This plugin depends on query-string.js, which is used to convert a query string into a JSON object. + * + * jQuery plugin template adapted from https://gist.github.com/Air-Craft/1300890 + * + * === USAGE === + * + * Create a container element, and within it place your table, paging controls, and Handlebars templates for rendering the cells. + * + * - Your table should have a unique id, and your paging controls should be wrapped in an element with the `.js-uf-table-pager` class. + * - Create a button with the `.js-uf-table-download` class, and it will be automatically bound to trigger an AJAX request for downloading the table (CSV, etc). + * +
+ + + + + + + + + +
User Last Activity
+ + + + + +
+ + + + + +

+ Jump to Page: • Show: + +
+ + +
+ * + * Initialize ufTable on your container object: + * + * $("#widget-users").ufTable(options); + * + * `options` is an object containing any of the following parameters: + * @param {string} dataUrl The absolute URL from which to fetch table data. + * @param {mixed} addParams An object containing any additional key-value pairs that you want appended to the AJAX requests. + * @param {mixed} tablesorter An object containing tablesorter's configuration options (https://mottie.github.io/tablesorter/docs/#Configuration) + * @param {mixed} pager An object containing tablesorter's paging options (https://mottie.github.io/tablesorter/docs/#pager) + * + * == EVENTS == + * + * ufTable triggers the following events: + * + * `pagerComplete.ufTable`: triggered when the tablesorter pager plugin has completed rendering of the table. + * + * == METHODS == + * + * `getTableStateVars( table )`: fetches the current page size, page number, sort order, sort field, and column filters. + * + * UserFrosting https://www.userfrosting.com + * @author Alexander Weissman + */ +;(function ($, window, document, undefined) { + 'use strict'; + + // Define plugin name and defaults. + var pluginName = 'ufTable', + defaults = { + DEBUG: false, + site: site, // global site variables + dataUrl: '', + msgTarget: $('#alerts-page'), + addParams: {}, + filterAllField: '_all', + useLoadingTransition: true, + rowTemplate: null, + columnTemplates: {}, + tablesorter: { + debug: false, + theme: 'bootstrap', + widthFixed: true, + // Set up pagination of data via an AJAX source + // See http://jsfiddle.net/Mottie/uwZc2/ + // Also see https://mottie.github.io/tablesorter/docs/example-pager-ajax.html + widgets: ['saveSort', 'sort2Hash', 'filter', 'pager', 'columnSelector', 'reflow2'], + widgetOptions: { + columnSelector_layout: '', + filter_cssFilter: 'form-control', + filter_saveFilters: true, + filter_serversideFiltering: true, + filter_selectSource: { + '.filter-select': function () { + return null; + } + }, + + // apply disabled classname to the pager arrows when the rows at either extreme is visible + pager_updateArrows: true, + + // starting page of the pager (zero based index) + pager_startPage: 0, + + // Number of visible rows + pager_size: 10, + + // Save pager page & size if the storage script is loaded (requires $.tablesorter.storage in jquery.tablesorter.widgets.js) + pager_savePages: true, + + // if true, the table will remain the same height no matter how many records are displayed. The space is made up by an empty + // table row set to a height to compensate; default is false + pager_fixedHeight: false, + + // remove rows from the table to speed up the sort of large tables. + // setting this to false, only hides the non-visible rows; needed if you plan to add/remove rows with the pager enabled. + pager_removeRows: false, // removing rows in larger tables speeds up the sort + + // target the pager markup - see the HTML block below + pager_css: { + errorRow: 'uf-table-error-row', // error information row + disabled: 'disabled' // Note there is no period "." in front of this class name + }, + + // Must be initialized with a 'data' key + pager_ajaxObject: { + data: {}, + dataType: 'json' + }, + + // hash prefix + sort2Hash_hash: '#', + // don't '#' or '=' here + sort2Hash_separator: '|', + // this option > table ID > table index on page + sort2Hash_tableId: null, + // if true, show header cell text instead of a zero-based column index + sort2Hash_headerTextAttr: 'data-column-name', + // direction text shown in the URL e.g. [ 'asc', 'desc' ] + sort2Hash_directionText: ['asc', 'desc'], // default values + // if true, override saveSort widget sort, if used & stored sort is available + sort2Hash_overrideSaveSort: true, // default = false + } + } + }; + + // Constructor + function Plugin(element, options) { + this.element = element[0]; + this.$element = $(this.element); + + var lateDefaults = { + download: { + button: this.$element.find('.js-uf-table-download'), + callback: $.proxy(this._onDownload, this) + }, + info: { + container: this.$element.find('.js-uf-table-info'), + callback: $.proxy(this._renderInfoMessages, this) + }, + overlay: { + container: this.$element.find('.js-uf-table-overlay') + }, + tableElement: this.$element.find('.tablesorter'), + tablesorter: { + widgetOptions: { + columnSelector_container: this.$element.find('.js-uf-table-cs-options'), + filter_external: this.$element.find('.js-uf-table-search input'), + + // Pager selectors + pager_selectors: { + container: this.$element.find('.js-uf-table-pager'), + first: '.first', // go to first page arrow + prev: '.prev', // previous page arrow + next: '.next', // next page arrow + last: '.last', // go to last page arrow + gotoPage: '.gotoPage', // go to page selector - select dropdown that sets the current page + pageDisplay: '.pagedisplay', // location of where the "output" is displayed + pageSize: '.pagesize' // page size selector - select dropdown that sets the "size" option + }, + // We need to use $.proxy to properly bind the context for callbacks that will be called by Tablesorter + + // Generate the URL for the AJAX request, with the relevant parameters + pager_customAjaxUrl: $.proxy(this._generateUrl, this), + + // Callback to process the response from the AJAX request + pager_ajaxProcessing: $.proxy(this._processAjax, this), + + // Callback to display errors + pager_ajaxError: $.proxy(this._pagerAjaxError, this), + + sort2Hash_encodeHash: $.proxy(this._encodeHash, this), + + sort2Hash_decodeHash: $.proxy(this._decodeHash, this), + + sort2Hash_cleanHash: $.proxy(this._cleanHash, this) + } + } + }; + this.settings = $.extend(true, {}, defaults, lateDefaults, options); + this._defaults = defaults; + this._name = pluginName; + this._debugAjax = (typeof this.settings.site !== 'undefined') && this.settings.site.debug.ajax; + + // Fall back to attributes from data-*, default values if not specified in options + var pagerContainer = this.settings.tablesorter.widgetOptions.pager_selectors.container; + var infoContainer = this.settings.info.container; + var dataAttributeDefaults = { + info: { + messageEmptyRows: infoContainer.data('message-empty-rows') ? + infoContainer.data('message-empty-rows') : + "Sorry, we've got nothing here." + }, + tablesorter: { + widgetOptions: { + // possible variables: {size}, {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} + // also {page:input} & {startRow:input} will add a modifiable input in place of the value + pager_output: pagerContainer.data('output-template') ? + pagerContainer.data('output-template') : + '{startRow} to {endRow} of {filteredRows} ({totalRows})' // default if not set on data-* attribute + } + } + }; + + this.settings = $.extend(true, {}, dataAttributeDefaults, this.settings); + + // Check that tableElement exists + var tableElement = this.settings.tableElement; + if (!tableElement.length) { + if (window.console && console.error) { + console.error('ufTable could not be initialized: wrapper element does not exist, or does not contain a matched tableElement (see https://learn.userfrosting.com/client-side-code/components/tables )'); + } + return; + } + + // Copy over dataUrl to pager_ajaxUrl + this.settings.tablesorter.widgetOptions.pager_ajaxUrl = this.settings.dataUrl; + + // Set up 'loading' overlays + if (this.settings.useLoadingTransition) { + var overlay = this.settings.overlay.container; + tableElement.bind('sortStart filterStart pageMoved', function () { + overlay.removeClass('hidden'); + }).bind('pagerComplete updateComplete', function () { + overlay.addClass('hidden'); + }); + } + + // Set up tablesorter and pager + this.ts = tableElement.tablesorter(this.settings.tablesorter); + + // Map default column template selectors based on data-column-template attribute in each column header + var columns = this.ts[0].config.$headerIndexed; + var columnTemplates = {}; + for (var col = 0; col < columns.length; col++) { + var columnName = columns[col].data('column-name'); + if (!columnName && this.settings.DEBUG) { + console.error('Column number ' + col + ' is missing a data-column-name attribute.'); + } + columnTemplates[columnName] = columns[col].data('column-template'); + } + + // Merge in any column template selectors that were set in the ctor options + columnTemplates = $.extend(true, columnTemplates, this.settings.columnTemplates); + + // Locate and compile templates for any string-identified column renderers + // At the same time, build out a numerically indexed array of templates + this.columnTemplatesIndexed = []; + for (var col = 0; col < columns.length; col++) { + var columnName = columns[col].data('column-name'); + if (!columnTemplates[columnName] && this.settings.DEBUG) { + console.error("No template found for column '" + columnName + "'."); + } + var columnTemplate = columnTemplates[columnName]; + if (typeof columnTemplate === 'string') { + this.columnTemplatesIndexed.push(Handlebars.compile($(columnTemplate).html())); + } else { + this.columnTemplatesIndexed.push(columnTemplate); + } + } + + // Locate and compile row template + this.rowTemplate = Handlebars.compile(''); + // If rowTemplateSelector is set, then find the DOM element that it references, which contains the template + if (this.settings.rowTemplate) { + var rowTemplate = this.settings.rowTemplate; + if (typeof rowTemplate === 'string') { + this.rowTemplate = Handlebars.compile($(this.settings.rowTemplate).html()); + } else { + this.rowTemplate = rowTemplate; + } + } + + // Link CSV download button + this.settings.download.button.on('click', this.settings.download.callback); + + // Allow clicking on the labels in the table menu without closing the menu + $(this.settings.tablesorter.widgetOptions.columnSelector_container).find('label').on('click', function (e) { + e.stopPropagation(); + }); + + // Propagate our own pagerComplete event + this.ts.on('pagerComplete', $.proxy(function () { + this.$element.trigger('pagerComplete.ufTable'); + }, this)); + + // Show info messages when there are no rows/no results + this.ts.on('filterEnd filterReset pagerComplete', this.settings.info.callback); + + // Detect changes to element attributes + this.$element.attrchange({ + callback: function (event) { + this.element = event.target; + }.bind(this) + }); + + return this; + } + + /** + * Get state variables for this table, as required by the AJAX data source: sorts, filters, size, page + */ + Plugin.prototype.getTableStateVars = function (table) { + var base = this; + + // Get sort column and order + var sortOrders = { + '0': 'asc', + '1': 'desc' + }; + + // Set sorts in URL. Assumes each th has a data-column-name attribute that corresponds to the name in the API + var sortList = table.config.sortList; + var sorts = {}; + for (var i = 0; i < sortList.length; i++) { + var columnIndex = sortList[i][0]; + var columnDirection = sortOrders[sortList[i][1]]; // Converts to 'asc' or 'desc' + if (sortList[i]) { + var columnName = table.config.$headerIndexed[columnIndex].data('column-name'); + sorts[columnName] = columnDirection; + } + } + + // Set filters in URL. Assumes each th has a data-column-name attribute that corresponds to the name in the API + var filterList = base.getSavedFilters(table); + var filters = {}; + for (i = 0; i < filterList.length; i++) { + if (filterList[i]) { + var columnName = base.settings.filterAllField; + + if (table.config.$headerIndexed[i]) { + columnName = table.config.$headerIndexed[i].data('column-name'); + } + + filters[columnName] = filterList[i]; + } + } + + var state = { + size: table.config.pager.size, + page: table.config.pager.page, + sorts: sorts, + filters: filters + }; + + return state; + }; + + /** + * Get saved filters from the browser local storage. Those should always be up to date + */ + Plugin.prototype.getSavedFilters = function (table) { + + // Fallback to `getFilters` or empty in case of failure + var filterList = $.tablesorter.getFilters(table) || []; + + // Overwrite list with saved filter for filter-select not setup by ts + var isArray, saved, + wo = table.config.widgetOptions; + if (wo.filter_saveFilters && $.tablesorter.storage) { + saved = $.tablesorter.storage(table, 'tablesorter-filters') || []; + isArray = $.isArray(saved); + // make sure we're not just getting an empty array + if (!(isArray && saved.join('') === '' || !isArray)) { + filterList = $.tablesorter.filter.processFilters(saved); + } + } + + return filterList; + }; + + /** + * Generate the AJAX url. + * Used as the default callback for pager_customAjaxUrl + * @private + */ + Plugin.prototype._generateUrl = function (table, url) { + var tableState = this.getTableStateVars(table); + + if (this.settings.DEBUG) { + console.log(tableState); + } + + $.extend(table.config.pager.ajaxObject.data, tableState); + + // Merge in any additional parameters + $.extend(table.config.pager.ajaxObject.data, this.settings.addParams); + + return url; + }; + /** + * Process data returned from the AJAX request and rendering the table cells. + * Used as the default callback for pager_ajaxProcessing + * @private + */ + Plugin.prototype._processAjax = function (data) { + var ts = this.ts[0]; + var json = {}, + rows = ''; + + if (data) { + var size = data.rows.length; + + // Render table rows and cells via Handlebars + for (var row = 0; row < size; row++) { + var cellData = { + rownum: row, + row: data.rows[row], // It is safe to use the data from the API because Handlebars escapes HTML + site: this.settings.site + }; + + rows += this.rowTemplate(cellData); + + for (var col = 0; col < this.columnTemplatesIndexed.length; col++) { + rows += this.columnTemplatesIndexed[col](cellData); + } + + rows += ''; + } + + // Initialize any dropdown filters + var columns = ts.config.$headerIndexed; + this._ajaxInitFilterSelects(columns, data.listable); + + json.total = data.count; // Get total rows without pagination + json.filteredRows = data.count_filtered; // no filtering + json.rows = $(rows); + json.output = data.output; + } else { + json.total = 0; + json.filteredRows = 0; + json.rows = ''; + } + + return json; + }; + + /** + * Initialize filter select menus using the ajax `listable` values + * @private + */ + Plugin.prototype._ajaxInitFilterSelects = function (columns, listable) { + var ts = this.ts[0]; + var filters = this.getSavedFilters(ts); + // Find columns with `.filter-select` and match them to column numbers based on their data-column-name + for (var col = 0; col < columns.length; col++) { + var column = columns[col]; + // If the column is designated for filter-select, get the listables from the data and recreate it + if (column.hasClass('filter-select')) { + var columnName = column.data('column-name'); + if (listable[columnName]) { + $.tablesorter.filter.buildSelect(ts, col, listable[columnName], true); + // If there is a filter actually set for this column, update the selected option. + if (filters[col]) { + var selectControl = $(ts).find(".tablesorter-filter[data-column='" + col + "']"); + selectControl.val(filters[col]); + } + } + } + } + }; + + /** + * Implements handler for the "download CSV" button. + * Default callback for download.callback + * @private + */ + Plugin.prototype._onDownload = function () { + var tableState = this.getTableStateVars(this.ts[0]); + tableState.format = 'csv'; + delete tableState.page; + delete tableState.size; + + // Merge in any additional request parameters + $.extend(tableState, this.settings.addParams); + + // Causes download to begin + window.location = this.settings.dataUrl + '?' + $.param(tableState); + }; + + /** + * Handle pager ajax errors. + * @private + */ + Plugin.prototype._pagerAjaxError = function (c, jqXHR, settings, exception) { + this._ajaxError(jqXHR); + + // Let TS handle the in-table error message + return ''; + }; + + /** + * Handle ajax error + * @private + */ + Plugin.prototype._ajaxError = function (jqXHR) { + if (typeof jqXHR === 'object') { + // Error messages + if (this._debugAjax && jqXHR.responseText) { + document.write(jqXHR.responseText); + document.close(); + } else { + if (this.settings.DEBUG) { + console.log('Error (' + jqXHR.status + '): ' + jqXHR.responseText); + } + // Display errors on failure + // ufAlerts widget should have a 'destroy' method + if (!this.settings.msgTarget.data('ufAlerts')) { + this.settings.msgTarget.ufAlerts(); + } else { + this.settings.msgTarget.ufAlerts('clear'); + } + + this.settings.msgTarget.ufAlerts('fetch').ufAlerts('render'); + } + } + }; + + /** + * Render info messages, such as when there are no results. + * Default callback for info.callback + * @private + */ + Plugin.prototype._renderInfoMessages = function () { + var table = this.ts[0]; + var infoMessages = this.settings.info.container; + if (table.config.pager) { + infoMessages.html(''); + var fr = table.config.pager.filteredRows; + if (fr === 0) { + infoMessages.html(this.settings.info.messageEmptyRows); + } + } + }; + + /** + * Encode the current table state variables into a URL hash. + * Default callback for sort2Hash_encodeHash + * @private + */ + Plugin.prototype._encodeHash = function (config, tableId, component, value, rawValue) { + var wo = config.widgetOptions; + if (component === 'filter') { + // rawValue is an array of filter values, numerically indexed + var encodedFilters = ''; + var len = rawValue.length; + for (var index = 0; index < len; index++) { + if (rawValue[index]) { + var columnName = this.settings.filterAllField; + if (config.$headerIndexed[index]) { + columnName = $(config.$headerIndexed[index][0]).attr(wo.sort2Hash_headerTextAttr); + } + encodedFilters += '&filter[' + tableId + '][' + columnName + ']=' + encodeURIComponent(rawValue[index]); + } + } + return encodedFilters; + } else if (component === 'sort') { + // rawValue is an array of sort pairs [columnNum, sortDirection] + var encodedFilters = ''; + var len = rawValue.length; + for (var index = 0; index < len; index++) { + var columnNum = rawValue[index][0]; + var sortDirection = rawValue[index][1]; + var columnName = $(config.$headerIndexed[columnNum][0]).attr(wo.sort2Hash_headerTextAttr); + encodedFilters += '&sort[' + tableId + '][' + columnName + ']=' + wo.sort2Hash_directionText[sortDirection]; + } + return encodedFilters; + } + return false; + }; + + /** + * Decode the current table state variables from the URL hash. + * Default callback for sort2Hash_decodeHash + * @private + */ + Plugin.prototype._decodeHash = function (config, tableId, component) { + var wo = config.widgetOptions; + var result; + // Convert hash into JSON object + var urlObject = $.String.deparam(window.location.hash); + delete urlObject[wo.sort2Hash_hash]; // Remove hash character + if (component === 'filter') { + var decodedFilters = []; + // Extract filter names and values for the specified table + var pageFilters = urlObject.filter ? urlObject.filter : []; + if (pageFilters[tableId]) { + var tableFilters = pageFilters[tableId]; + // Build a numerically indexed array of filter values + var len = config.$headerIndexed.length; + for (var index = 0; index < len; index++) { + var columnName = $(config.$headerIndexed[index][0]).attr(wo.sort2Hash_headerTextAttr); + if (tableFilters[columnName] && tableFilters[columnName] != this.settings.filterAllField) { + decodedFilters.push(tableFilters[columnName]); + } else { + decodedFilters.push(''); + } + } + // Convert array of filter values to a delimited string + result = decodedFilters.join(wo.sort2Hash_separator); + // make sure to use decodeURIComponent on the result + return decodeURIComponent(result); + } else { + return ''; + } + } + return false; + }; + + /** + * Clean up URL hash. + * Default callback for sort2Hash_cleanHash + * @private + */ + Plugin.prototype._cleanHash = function (config, tableId, component, hash) { + var wo = config.widgetOptions; + // Convert hash to JSON object + var urlObject = $.String.deparam(hash); + delete urlObject[wo.sort2Hash_hash]; // Remove hash character + // Remove specified component for specified table + if (urlObject[component]) { + if (urlObject[component][tableId]) { + delete urlObject[component][tableId]; + } + // Delete entire component if no other tables remaining + if (jQuery.isEmptyObject(urlObject[component])) { + delete urlObject[component]; + } + } + // Convert modified JSON object back into serialized representation + var result = decodeURIComponent(jQuery.param(urlObject)); + return result.length ? result : ''; + }; + + // Handles instantiation and access to non-private methods. + $.fn[pluginName] = function (methodOrOptions) { + // Grab plugin instance + var instance = $(this).data(pluginName); + // If undefined or object, initalise plugin. + if (methodOrOptions === undefined || typeof methodOrOptions === 'object') { + // Only initalise if not previously done. + if (!instance) { + $(this).data(pluginName, new Plugin(this, methodOrOptions)); + } + return this; + // Otherwise ensure first parameter is a valid string, and is the name of an actual function. + } else if (typeof methodOrOptions === 'string' && typeof instance[methodOrOptions] === 'function') { + // Ensure not a private function + if (methodOrOptions.indexOf('_') !== 0) { + return instance[methodOrOptions](Array.prototype.slice.call(arguments, 1)); + } + else { + console.warn('Method ' + methodOrOptions + ' is private!'); + } + } else { + console.warn('Method ' + methodOrOptions + ' does not exist.'); + } + }; +})(jQuery, window, document); diff --git a/main/app/sprinkles/core/assets/userfrosting/js/uf-tablesorter-parsers.js b/main/app/sprinkles/core/assets/userfrosting/js/uf-tablesorter-parsers.js index 02901c5..e720a47 100644 --- a/main/app/sprinkles/core/assets/userfrosting/js/uf-tablesorter-parsers.js +++ b/main/app/sprinkles/core/assets/userfrosting/js/uf-tablesorter-parsers.js @@ -1,53 +1,53 @@ -// Parser for sorting integers, timestamps, etc based on metadata from attributes -// Adapted from http://mottie.github.io/tablesorter/docs/example-parsers-advanced.html -$.tablesorter.addParser({ - // set a unique id - id: 'metanum', - is: function (s) { - // return false so this parser is not auto detected - return false; - }, - format: function (s, table, cell, cellIndex) { - var $cell = $(cell); - // returns metadata, or cell text (s) if it doesn't exist - return $cell.attr('data-num') || s; - - }, - // set type to numeric - type: 'numeric' -}); - -$.tablesorter.addParser({ - // set a unique id - id: 'metatext', - is: function (s) { - // return false so this parser is not auto detected - return false; - }, - format: function (s, table, cell, cellIndex) { - var $cell = $(cell); - // returns metadata, or cell text (s) if it doesn't exist - return $cell.attr('data-text') || s; - - }, - - type: 'text' -}); - -$.tablesorter.addParser({ - // set a unique id - id: 'isblank', - is: function (s) { - // return false so this parser is not auto detected - return false; - }, - format: function (s, table, cell, cellIndex) { - var $cell = $(cell); - // returns 1 if blank (whitespace), 0 otherwise - var isBlank = $cell.html().trim() == " " ? 1 : 0; - return isBlank; - - }, - - type: 'numeric' -}); +// Parser for sorting integers, timestamps, etc based on metadata from attributes +// Adapted from http://mottie.github.io/tablesorter/docs/example-parsers-advanced.html +$.tablesorter.addParser({ + // set a unique id + id: 'metanum', + is: function (s) { + // return false so this parser is not auto detected + return false; + }, + format: function (s, table, cell, cellIndex) { + var $cell = $(cell); + // returns metadata, or cell text (s) if it doesn't exist + return $cell.attr('data-num') || s; + + }, + // set type to numeric + type: 'numeric' +}); + +$.tablesorter.addParser({ + // set a unique id + id: 'metatext', + is: function (s) { + // return false so this parser is not auto detected + return false; + }, + format: function (s, table, cell, cellIndex) { + var $cell = $(cell); + // returns metadata, or cell text (s) if it doesn't exist + return $cell.attr('data-text') || s; + + }, + + type: 'text' +}); + +$.tablesorter.addParser({ + // set a unique id + id: 'isblank', + is: function (s) { + // return false so this parser is not auto detected + return false; + }, + format: function (s, table, cell, cellIndex) { + var $cell = $(cell); + // returns 1 if blank (whitespace), 0 otherwise + var isBlank = $cell.html().trim() == " " ? 1 : 0; + return isBlank; + + }, + + type: 'numeric' +}); diff --git a/main/app/sprinkles/core/bower.json b/main/app/sprinkles/core/bower.json index 82509b3..0a6ad00 100644 --- a/main/app/sprinkles/core/bower.json +++ b/main/app/sprinkles/core/bower.json @@ -1,47 +1,47 @@ -{ - "name": "userfrosting-sprinkle-core", - "description": "Core module for UserFrosting.", - "homepage": "https://github.com/userfrosting", - "license": "MIT", - "authors": [ - { - "name": "Alexander Weissman", - "homepage": "https://alexanderweissman.com" - }, - "ssnukala" - ], - "dependencies": { - "jquery": ">= 2.2.4", - "bootstrap": "^3.3.6", - "font-awesome": "^4.7", - "handlebars": "^3.0", - "clipboard": "^1.5", - "ionicons": "^2.0", - "icheck": "^1.0", - "speakingurl": "^11.0", - "urijs": "^1.18", - "fastclick": "^1.0.6", - "moment": "^2.17", - "jquery-slimscroll": "^1.3", - "jquery-validation": "~1.14.0", - "select2": "~4.0.5", - "tablesorter": "jquery.tablesorter#2.28" - }, - "resolutions": { - "jquery": ">= 2.2.4" - }, - "moduleType": [ - "node" - ], - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "assets/vendor", - "examples", - "demo-resources", - "demo", - "test", - "tests" - ] -} +{ + "name": "userfrosting-sprinkle-core", + "description": "Core module for UserFrosting.", + "homepage": "https://github.com/userfrosting", + "license": "MIT", + "authors": [ + { + "name": "Alexander Weissman", + "homepage": "https://alexanderweissman.com" + }, + "ssnukala" + ], + "dependencies": { + "jquery": ">= 2.2.4", + "bootstrap": "^3.3.6", + "font-awesome": "^4.7", + "handlebars": "^3.0", + "clipboard": "^1.5", + "ionicons": "^2.0", + "icheck": "^1.0", + "speakingurl": "^11.0", + "urijs": "^1.18", + "fastclick": "^1.0.6", + "moment": "^2.17", + "jquery-slimscroll": "^1.3", + "jquery-validation": "~1.14.0", + "select2": "~4.0.5", + "tablesorter": "jquery.tablesorter#2.28" + }, + "resolutions": { + "jquery": ">= 2.2.4" + }, + "moduleType": [ + "node" + ], + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "assets/vendor", + "examples", + "demo-resources", + "demo", + "test", + "tests" + ] +} diff --git a/main/app/sprinkles/core/composer.json b/main/app/sprinkles/core/composer.json index 017e56b..d34888b 100644 --- a/main/app/sprinkles/core/composer.json +++ b/main/app/sprinkles/core/composer.json @@ -1,48 +1,48 @@ -{ - "name": "userfrosting/sprinkle-core", - "type": "userfrosting-sprinkle", - "description": "Core module for UserFrosting.", - "keywords": [ - "php user management", - "usercake", - "bootstrap" - ], - "homepage": "https://github.com/userfrosting/UserFrosting", - "license": "MIT", - "authors": [ - { - "name": "Alexander Weissman", - "homepage": "https://alexanderweissman.com" - } - ], - "require": { - "doctrine/dbal": "^2.5", - "filp/whoops": "^2.1", - "illuminate/cache": "5.4.*", - "illuminate/database": "5.4.*", - "illuminate/events": "5.4.*", - "illuminate/filesystem": "5.4.*", - "league/csv": "^8.1", - "monolog/monolog": "^1", - "phpmailer/phpmailer": "5.2.10", - "rockettheme/toolbox": "1.3.1", - "slim/csrf": "^0.8", - "slim/slim": "^3", - "slim/twig-view": "^1.2", - "symfony/http-foundation": "*", - "twig/twig": "^1.18", - "userfrosting/assets": "~4.1.0", - "userfrosting/config": "~4.1.0", - "userfrosting/cache": "~4.1.0", - "userfrosting/fortress": "~4.1.1", - "userfrosting/i18n": "~4.1.0", - "userfrosting/session": "~4.1.0", - "userfrosting/support": "~4.1.1", - "vlucas/phpdotenv": "^2" - }, - "autoload": { - "psr-4": { - "UserFrosting\\Sprinkle\\Core\\": "src/" - } - } -} +{ + "name": "userfrosting/sprinkle-core", + "type": "userfrosting-sprinkle", + "description": "Core module for UserFrosting.", + "keywords": [ + "php user management", + "usercake", + "bootstrap" + ], + "homepage": "https://github.com/userfrosting/UserFrosting", + "license": "MIT", + "authors": [ + { + "name": "Alexander Weissman", + "homepage": "https://alexanderweissman.com" + } + ], + "require": { + "doctrine/dbal": "^2.5", + "filp/whoops": "^2.1", + "illuminate/cache": "5.4.*", + "illuminate/database": "5.4.*", + "illuminate/events": "5.4.*", + "illuminate/filesystem": "5.4.*", + "league/csv": "^8.1", + "monolog/monolog": "^1", + "phpmailer/phpmailer": "5.2.10", + "rockettheme/toolbox": "1.3.1", + "slim/csrf": "^0.8", + "slim/slim": "^3", + "slim/twig-view": "^1.2", + "symfony/http-foundation": "*", + "twig/twig": "^1.18", + "userfrosting/assets": "~4.1.0", + "userfrosting/config": "~4.1.0", + "userfrosting/cache": "~4.1.0", + "userfrosting/fortress": "~4.1.1", + "userfrosting/i18n": "~4.1.0", + "userfrosting/session": "~4.1.0", + "userfrosting/support": "~4.1.1", + "vlucas/phpdotenv": "^2" + }, + "autoload": { + "psr-4": { + "UserFrosting\\Sprinkle\\Core\\": "src/" + } + } +} diff --git a/main/app/sprinkles/core/config/default.php b/main/app/sprinkles/core/config/default.php index 7e861df..1a80538 100644 --- a/main/app/sprinkles/core/config/default.php +++ b/main/app/sprinkles/core/config/default.php @@ -1,183 +1,183 @@ - [ - 'admin' => [ - 'email' => getenv('SMTP_USER') ?: NULL, - 'name' => 'Site Administrator' - ] - ], - 'alert' => [ - 'storage' => 'session', // Set to one of `cache` or `session` - 'key' => 'site.alerts', // the key to use to store flash messages - ], - 'assets' => [ - 'compiled' => [ - 'path' => 'assets', - 'schema' => 'bundle.result.json' - ], - 'raw' => [ - 'path' => 'assets-raw', - 'schema' => 'asset-bundles.json' - ], - 'use_raw' => TRUE - ], - 'cache' => [ - 'driver' => 'file', // Set to one of `file`, `memcached`, `redis` - 'prefix' => 'userfrosting', // Edit prefix to something unique when multiple instance of memcached/redis are used on the same server - 'memcached' => [ - 'host' => '127.0.0.1', - 'port' => 11211, - 'weight' => 100 - ], - 'redis' => [ - 'host' => '127.0.0.1', - 'password' => NULL, - 'port' => 6379, - 'database' => 0 - ], - 'twig' => FALSE - ], - // CSRF middleware settings (see https://github.com/slimphp/Slim-Csrf) - 'csrf' => [ - 'name' => 'csrf', - 'storage_limit' => 200, - 'strength' => 16, - 'persistent_token' => TRUE, - // A list of url paths to ignore CSRF checks on - 'blacklist' => [ - // URL paths will be matched against each regular expression in this list. - // Each regular expression should map to an array of methods. - // Regular expressions will be delimited with ~ in preg_match, so if you - // have routes with ~ in them, you must escape this character in your regex. - // Also, remember to use ^ when you only want to match the beginning of a URL path! - ] - ], - 'db' => [ - 'default' => [ - 'driver' => getenv('DB_DRIVER') ?: 'mysql', - 'host' => getenv('DB_HOST') ?: NULL, - 'port' => getenv('DB_PORT') ?: NULL, - 'database' => getenv('DB_NAME') ?: NULL, - 'username' => getenv('DB_USER') ?: NULL, - 'password' => getenv('DB_PASSWORD') ?: NULL, - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', - 'prefix' => '' - ] - ], - 'debug' => [ - 'queries' => FALSE, - 'smtp' => FALSE, - 'twig' => FALSE - ], - 'mail' => [ - 'mailer' => 'smtp', // Set to one of 'smtp', 'mail', 'qmail', 'sendmail' - 'host' => getenv('SMTP_HOST') ?: NULL, - 'port' => 465, - 'auth' => TRUE, - 'secure' => 'ssl', - 'username' => getenv('SMTP_USER') ?: NULL, - 'password' => getenv('SMTP_PASSWORD') ?: NULL, - 'smtp_debug' => 4, - 'message_options' => [ - 'CharSet' => 'UTF-8', - 'isHtml' => TRUE, - 'Timeout' => 15 - ] - ], - // Filesystem paths - 'path' => [ - 'document_root' => str_replace(DIRECTORY_SEPARATOR, \UserFrosting\DS, $_SERVER['DOCUMENT_ROOT']), - 'public_relative' => dirname($_SERVER['SCRIPT_NAME']) // The location of `index.php` relative to the document root. Use for sites installed in subdirectories of your web server's document root. - ], - 'session' => [ - 'handler' => 'file', - // Config values for when using db-based sessions - 'database' => [ - 'table' => 'sessions' - ], - 'name' => 'uf4', - 'minutes' => 120, - 'cache_limiter' => FALSE, - // Decouples the session keys used to store certain session info - 'keys' => [ - 'csrf' => 'site.csrf', // the key (prefix) used to store an ArrayObject of CSRF tokens. - ] - ], - // Slim settings - see http://www.slimframework.com/docs/objects/application.html#slim-default-settings - 'settings' => [ - 'displayErrorDetails' => TRUE - ], - // "Site" settings that are automatically passed to Twig - 'site' => [ - 'AdminLTE' => [ - 'skin' => 'blue' - ], - 'analytics' => [ - 'google' => [ - 'code' => 'UA-109245179-2', - 'enabled' => TRUE - ] - ], - 'author' => 'Author', - 'csrf' => NULL, // Do not set this variable. The core Twig extension will override it with values from the CSRF service. - 'debug' => [ - 'ajax' => FALSE, - 'info' => TRUE - ], - 'locales' => [ - // Should be ordered according to https://en.wikipedia.org/wiki/List_of_languages_by_total_number_of_speakers, - // with the exception of English, which as the default language comes first. - 'available' => [ - 'en_US' => 'English', - 'zh_CN' => '中文', - 'es_ES' => 'Español', - 'ar' => 'العربية', - 'pt_PT' => 'Português', - 'ru_RU' => 'русский', - 'tlh' => 'tlhIngan Hol', - 'de_DE' => 'Deutsch', - 'fr_FR' => 'Français', - 'tr' => 'Türk', - 'it_IT' => 'Italiano', - 'th_TH' => 'ภาษาไทย', - 'fa' => 'فارسی' - ], - // This can be a comma-separated list, to load multiple fallback locales - 'default' => 'en_US' - ], - 'title' => 'BEAM-Messenger', - // Global ufTable settings - 'uf_table' => [ - 'use_loading_transition' => TRUE - ], - // URLs - 'uri' => [ - 'base' => [ - 'host' => isset($_SERVER['SERVER_NAME']) ? trim($_SERVER['SERVER_NAME'], '/') : 'localhost', - 'scheme' => empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off' ? 'http' : 'https', - 'port' => isset($_SERVER['SERVER_PORT']) ? (int)$_SERVER['SERVER_PORT'] : NULL, - 'path' => isset($_SERVER['SCRIPT_NAME']) ? trim(dirname($_SERVER['SCRIPT_NAME']), '/\\') : '' - ], - 'author' => 'https://marvinborner.me', - 'publisher' => 'https://marvinborner.me' - ] - ], - 'php' => [ - 'timezone' => 'Europe/Berlin', - 'error_reporting' => E_ALL, // Development - report all errors and suggestions - 'display_errors' => 'true', - 'log_errors' => 'true', - // Let PHP itself render errors natively. Useful if a fatal error is raised in our custom shutdown handler. - 'display_errors_native' => 'true' - ] -]; + [ + 'admin' => [ + 'email' => getenv('SMTP_USER') ?: NULL, + 'name' => 'Site Administrator' + ] + ], + 'alert' => [ + 'storage' => 'session', // Set to one of `cache` or `session` + 'key' => 'site.alerts', // the key to use to store flash messages + ], + 'assets' => [ + 'compiled' => [ + 'path' => 'assets', + 'schema' => 'bundle.result.json' + ], + 'raw' => [ + 'path' => 'assets-raw', + 'schema' => 'asset-bundles.json' + ], + 'use_raw' => TRUE + ], + 'cache' => [ + 'driver' => 'file', // Set to one of `file`, `memcached`, `redis` + 'prefix' => 'userfrosting', // Edit prefix to something unique when multiple instance of memcached/redis are used on the same server + 'memcached' => [ + 'host' => '127.0.0.1', + 'port' => 11211, + 'weight' => 100 + ], + 'redis' => [ + 'host' => '127.0.0.1', + 'password' => NULL, + 'port' => 6379, + 'database' => 0 + ], + 'twig' => FALSE + ], + // CSRF middleware settings (see https://github.com/slimphp/Slim-Csrf) + 'csrf' => [ + 'name' => 'csrf', + 'storage_limit' => 200, + 'strength' => 16, + 'persistent_token' => TRUE, + // A list of url paths to ignore CSRF checks on + 'blacklist' => [ + // URL paths will be matched against each regular expression in this list. + // Each regular expression should map to an array of methods. + // Regular expressions will be delimited with ~ in preg_match, so if you + // have routes with ~ in them, you must escape this character in your regex. + // Also, remember to use ^ when you only want to match the beginning of a URL path! + ] + ], + 'db' => [ + 'default' => [ + 'driver' => getenv('DB_DRIVER') ?: 'mysql', + 'host' => getenv('DB_HOST') ?: NULL, + 'port' => getenv('DB_PORT') ?: NULL, + 'database' => getenv('DB_NAME') ?: NULL, + 'username' => getenv('DB_USER') ?: NULL, + 'password' => getenv('DB_PASSWORD') ?: NULL, + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', + 'prefix' => '' + ] + ], + 'debug' => [ + 'queries' => FALSE, + 'smtp' => FALSE, + 'twig' => FALSE + ], + 'mail' => [ + 'mailer' => 'smtp', // Set to one of 'smtp', 'mail', 'qmail', 'sendmail' + 'host' => getenv('SMTP_HOST') ?: NULL, + 'port' => 465, + 'auth' => TRUE, + 'secure' => 'ssl', + 'username' => getenv('SMTP_USER') ?: NULL, + 'password' => getenv('SMTP_PASSWORD') ?: NULL, + 'smtp_debug' => 4, + 'message_options' => [ + 'CharSet' => 'UTF-8', + 'isHtml' => TRUE, + 'Timeout' => 15 + ] + ], + // Filesystem paths + 'path' => [ + 'document_root' => str_replace(DIRECTORY_SEPARATOR, \UserFrosting\DS, $_SERVER['DOCUMENT_ROOT']), + 'public_relative' => dirname($_SERVER['SCRIPT_NAME']) // The location of `index.php` relative to the document root. Use for sites installed in subdirectories of your web server's document root. + ], + 'session' => [ + 'handler' => 'file', + // Config values for when using db-based sessions + 'database' => [ + 'table' => 'sessions' + ], + 'name' => 'uf4', + 'minutes' => 120, + 'cache_limiter' => FALSE, + // Decouples the session keys used to store certain session info + 'keys' => [ + 'csrf' => 'site.csrf', // the key (prefix) used to store an ArrayObject of CSRF tokens. + ] + ], + // Slim settings - see http://www.slimframework.com/docs/objects/application.html#slim-default-settings + 'settings' => [ + 'displayErrorDetails' => TRUE + ], + // "Site" settings that are automatically passed to Twig + 'site' => [ + 'AdminLTE' => [ + 'skin' => 'blue' + ], + 'analytics' => [ + 'google' => [ + 'code' => 'UA-109245179-2', + 'enabled' => TRUE + ] + ], + 'author' => 'Author', + 'csrf' => NULL, // Do not set this variable. The core Twig extension will override it with values from the CSRF service. + 'debug' => [ + 'ajax' => FALSE, + 'info' => TRUE + ], + 'locales' => [ + // Should be ordered according to https://en.wikipedia.org/wiki/List_of_languages_by_total_number_of_speakers, + // with the exception of English, which as the default language comes first. + 'available' => [ + 'en_US' => 'English', + 'zh_CN' => '中文', + 'es_ES' => 'Español', + 'ar' => 'العربية', + 'pt_PT' => 'Português', + 'ru_RU' => 'русский', + 'tlh' => 'tlhIngan Hol', + 'de_DE' => 'Deutsch', + 'fr_FR' => 'Français', + 'tr' => 'Türk', + 'it_IT' => 'Italiano', + 'th_TH' => 'ภาษาไทย', + 'fa' => 'فارسی' + ], + // This can be a comma-separated list, to load multiple fallback locales + 'default' => 'en_US' + ], + 'title' => 'BEAM-Messenger', + // Global ufTable settings + 'uf_table' => [ + 'use_loading_transition' => TRUE + ], + // URLs + 'uri' => [ + 'base' => [ + 'host' => isset($_SERVER['SERVER_NAME']) ? trim($_SERVER['SERVER_NAME'], '/') : 'localhost', + 'scheme' => empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off' ? 'http' : 'https', + 'port' => isset($_SERVER['SERVER_PORT']) ? (int)$_SERVER['SERVER_PORT'] : NULL, + 'path' => isset($_SERVER['SCRIPT_NAME']) ? trim(dirname($_SERVER['SCRIPT_NAME']), '/\\') : '' + ], + 'author' => 'https://marvinborner.me', + 'publisher' => 'https://marvinborner.me' + ] + ], + 'php' => [ + 'timezone' => 'Europe/Berlin', + 'error_reporting' => E_ALL, // Development - report all errors and suggestions + 'display_errors' => 'true', + 'log_errors' => 'true', + // Let PHP itself render errors natively. Useful if a fatal error is raised in our custom shutdown handler. + 'display_errors_native' => 'true' + ] +]; diff --git a/main/app/sprinkles/core/config/dev.php b/main/app/sprinkles/core/config/dev.php index 63aeeab..a4429ae 100644 --- a/main/app/sprinkles/core/config/dev.php +++ b/main/app/sprinkles/core/config/dev.php @@ -1,30 +1,30 @@ - [ - 'use_raw' => TRUE - ], - 'cache' => [ - 'twig' => FALSE - ], - 'debug' => [ - 'twig' => TRUE, - 'auth' => TRUE, - 'smtp' => TRUE - ], - // Slim settings - see http://www.slimframework.com/docs/objects/application.html#slim-default-settings - 'settings' => [ - 'displayErrorDetails' => TRUE - ], - 'site' => [ - 'debug' => [ - 'ajax' => TRUE, - 'info' => TRUE - ] - ] + [ + 'use_raw' => TRUE + ], + 'cache' => [ + 'twig' => FALSE + ], + 'debug' => [ + 'twig' => TRUE, + 'auth' => TRUE, + 'smtp' => TRUE + ], + // Slim settings - see http://www.slimframework.com/docs/objects/application.html#slim-default-settings + 'settings' => [ + 'displayErrorDetails' => TRUE + ], + 'site' => [ + 'debug' => [ + 'ajax' => TRUE, + 'info' => TRUE + ] + ] ]; \ No newline at end of file diff --git a/main/app/sprinkles/core/config/production.php b/main/app/sprinkles/core/config/production.php index 8b970a7..1648679 100644 --- a/main/app/sprinkles/core/config/production.php +++ b/main/app/sprinkles/core/config/production.php @@ -1,40 +1,40 @@ - [ - 'use_raw' => FALSE - ], - 'cache' => [ - 'twig' => TRUE - ], - 'debug' => [ - 'twig' => FALSE, - 'auth' => FALSE, - 'smtp' => FALSE - ], - // Slim settings - see http://www.slimframework.com/docs/objects/application.html#slim-default-settings - 'settings' => [ - 'routerCacheFile' => \UserFrosting\ROOT_DIR . '/' . \UserFrosting\APP_DIR_NAME . '/' . \UserFrosting\CACHE_DIR_NAME . '/' . 'routes.cache', - 'displayErrorDetails' => FALSE - ], - 'site' => [ - 'analytics' => [ - 'google' => [ - 'enabled' => TRUE - ] - ], - 'debug' => [ - 'ajax' => FALSE, - 'info' => FALSE - ] - ], - 'php' => [ - 'display_errors' => 'false', - 'log_errors' => 'true' - ] -]; + [ + 'use_raw' => FALSE + ], + 'cache' => [ + 'twig' => TRUE + ], + 'debug' => [ + 'twig' => FALSE, + 'auth' => FALSE, + 'smtp' => FALSE + ], + // Slim settings - see http://www.slimframework.com/docs/objects/application.html#slim-default-settings + 'settings' => [ + 'routerCacheFile' => \UserFrosting\ROOT_DIR . '/' . \UserFrosting\APP_DIR_NAME . '/' . \UserFrosting\CACHE_DIR_NAME . '/' . 'routes.cache', + 'displayErrorDetails' => FALSE + ], + 'site' => [ + 'analytics' => [ + 'google' => [ + 'enabled' => TRUE + ] + ], + 'debug' => [ + 'ajax' => FALSE, + 'info' => FALSE + ] + ], + 'php' => [ + 'display_errors' => 'false', + 'log_errors' => 'true' + ] +]; diff --git a/main/app/sprinkles/core/config/testing.php b/main/app/sprinkles/core/config/testing.php index 4d5bb04..4bae194 100644 --- a/main/app/sprinkles/core/config/testing.php +++ b/main/app/sprinkles/core/config/testing.php @@ -1,23 +1,23 @@ - [ - 'illuminate' => [ - 'default' => 'array', - ] - ], - 'db' => [ - 'test_integration' => [ - 'driver' => 'sqlite', - 'database' => ':memory:', - ] - ], - 'settings' => [ - 'displayErrorDetails' => FALSE - ] -]; + [ + 'illuminate' => [ + 'default' => 'array', + ] + ], + 'db' => [ + 'test_integration' => [ + 'driver' => 'sqlite', + 'database' => ':memory:', + ] + ], + 'settings' => [ + 'displayErrorDetails' => FALSE + ] +]; diff --git a/main/app/sprinkles/core/locale/ar/messages.php b/main/app/sprinkles/core/locale/ar/messages.php index 6a416c2..e44c441 100644 --- a/main/app/sprinkles/core/locale/ar/messages.php +++ b/main/app/sprinkles/core/locale/ar/messages.php @@ -1,112 +1,112 @@ - 1, - - "ABOUT" => "عن", - - "CAPTCHA" => [ - "@TRANSLATION" => "كلمة التحقق", - "FAIL" => "لم تقم بإدخال رمز كلمة التحقق بشكل صحيح", - "SPECIFY" => "أدخل كلمة التحقق", - "VERIFY" => "التحقق من كلمة التحقق" - ], - - "CSRF_MISSING" => "رمز CSRF غير موجود حاول تحديث الصفحة ومن ثم إرساله مرة أخرى", - - "DB_INVALID" => "لا يمكن الاتصال بقاعدة البيانات إذا كنت مسؤولا، يرجى مراجعة سجل خطأ", - "DESCRIPTION" => "وصف", - "DOWNLOAD" => [ - "@TRANSLATION" => "تحميل", - "CSV" => "تحميل CSV" - ], - - "EMAIL" => [ - "@TRANSLATION" => "البريد الإلكتروني", - "YOUR" => "عنوان بريدك الإلكتروني" - ], - - "HOME" => "الصفحة الرئيسية", - - "LEGAL" => [ - "@TRANSLATION" => "السياسة القانونية", - "DESCRIPTION" => "تسري سياستنا القانونية على استخدامك لهذا الموقع وخدماتنا" - ], - - "LOCALE" => [ - "@TRANSLATION" => "اللغه", - ], - - "NAME" => "اسم", - "NAVIGATION" => "التنقل", - - "PAGINATION" => [ - "GOTO" => "انتقال إلى الصفحة", - "SHOW" => "عرض", - "NEXT" => "الصفحة التالية", - "PREVIOUS" => "الصفحة السابقة", - "FIRST" => "الصفحة الأولى", - "LAST" => "آخر صفحة" - ], - "PRIVACY" => [ - "@TRANSLATION" => "سياسة الخصوصية", - "DESCRIPTION" => "تحدد سياسة الخصوصية لدينا نوع المعلومات التي نجمعها منك وكيفية استخدامها." - ], - - "SLUG" => "Slug", - "SLUG_CONDITION" => "Slug/الظروف", - "STATUS" => "الحالة", - - "UNKNOWN" => "غير معروف", - - // Actions words - "ACTIONS" => "الأفعال", - "ACTIVATE" => "تفعيل", - "ACTIVE" => "نشيط", - "ADD" => "إضافة", - "CANCEL" => "إلغاء", - "CONFIRM" => "تؤكد", - "CREATE" => "أنتج", - "DELETE" => "حذف", - "DELETE_CONFIRM" => "هل أنت متأكد أنك تريد حذف هذا", - "DELETE_CONFIRM_YES" => "نعم، احذف", - "DELETE_CONFIRM_NAMED" => "هل أنت متأكد أنك تريد حذف {{name}}?", - "DELETE_CONFIRM_YES_NAMED" => "نعم، احذف {{name}}", - "DELETE_CANNOT_UNDONE" => "لا يمكن التراجع عن هذا الإجراء", - "DELETE_NAMED" => "احذف {{name}}", - "DENY" => "رفض", - "DISABLE" => "تعطيل", - "DISABLED" => "معطل", - "EDIT" => "تصحيح", - "ENABLE" => "تمكين", - "ENABLED" => "مكين", - "OVERRIDE" => "كتب فوق الكتابة", - "RESET" => "إعادة تعيين", - "SAVE" => "احفظ", - "SEARCH" => "ابحث", - "SORT" => "فرز", - "SUBMIT" => "ارسل", - "PRINT" => "اطباعة", - "REMOVE" => "إزالة", - "UNACTIVATED" => "إبطال", - "UPDATE" => "تحديث", - "YES" => "نعم", - "NO" => "لا", - "OPTIONAL" => "اختياري", - - // Misc - "BUILT_WITH_UF" => "بنيت مع UserFrosting", - "ADMINLTE_THEME_BY" => "فكرة رئيسية Almsaeed Studio كل الحقوق محفوظة", - "WELCOME_TO" => "مرحبا بك في {{title}}!" -]; + 1, + + "ABOUT" => "عن", + + "CAPTCHA" => [ + "@TRANSLATION" => "كلمة التحقق", + "FAIL" => "لم تقم بإدخال رمز كلمة التحقق بشكل صحيح", + "SPECIFY" => "أدخل كلمة التحقق", + "VERIFY" => "التحقق من كلمة التحقق" + ], + + "CSRF_MISSING" => "رمز CSRF غير موجود حاول تحديث الصفحة ومن ثم إرساله مرة أخرى", + + "DB_INVALID" => "لا يمكن الاتصال بقاعدة البيانات إذا كنت مسؤولا، يرجى مراجعة سجل خطأ", + "DESCRIPTION" => "وصف", + "DOWNLOAD" => [ + "@TRANSLATION" => "تحميل", + "CSV" => "تحميل CSV" + ], + + "EMAIL" => [ + "@TRANSLATION" => "البريد الإلكتروني", + "YOUR" => "عنوان بريدك الإلكتروني" + ], + + "HOME" => "الصفحة الرئيسية", + + "LEGAL" => [ + "@TRANSLATION" => "السياسة القانونية", + "DESCRIPTION" => "تسري سياستنا القانونية على استخدامك لهذا الموقع وخدماتنا" + ], + + "LOCALE" => [ + "@TRANSLATION" => "اللغه", + ], + + "NAME" => "اسم", + "NAVIGATION" => "التنقل", + + "PAGINATION" => [ + "GOTO" => "انتقال إلى الصفحة", + "SHOW" => "عرض", + "NEXT" => "الصفحة التالية", + "PREVIOUS" => "الصفحة السابقة", + "FIRST" => "الصفحة الأولى", + "LAST" => "آخر صفحة" + ], + "PRIVACY" => [ + "@TRANSLATION" => "سياسة الخصوصية", + "DESCRIPTION" => "تحدد سياسة الخصوصية لدينا نوع المعلومات التي نجمعها منك وكيفية استخدامها." + ], + + "SLUG" => "Slug", + "SLUG_CONDITION" => "Slug/الظروف", + "STATUS" => "الحالة", + + "UNKNOWN" => "غير معروف", + + // Actions words + "ACTIONS" => "الأفعال", + "ACTIVATE" => "تفعيل", + "ACTIVE" => "نشيط", + "ADD" => "إضافة", + "CANCEL" => "إلغاء", + "CONFIRM" => "تؤكد", + "CREATE" => "أنتج", + "DELETE" => "حذف", + "DELETE_CONFIRM" => "هل أنت متأكد أنك تريد حذف هذا", + "DELETE_CONFIRM_YES" => "نعم، احذف", + "DELETE_CONFIRM_NAMED" => "هل أنت متأكد أنك تريد حذف {{name}}?", + "DELETE_CONFIRM_YES_NAMED" => "نعم، احذف {{name}}", + "DELETE_CANNOT_UNDONE" => "لا يمكن التراجع عن هذا الإجراء", + "DELETE_NAMED" => "احذف {{name}}", + "DENY" => "رفض", + "DISABLE" => "تعطيل", + "DISABLED" => "معطل", + "EDIT" => "تصحيح", + "ENABLE" => "تمكين", + "ENABLED" => "مكين", + "OVERRIDE" => "كتب فوق الكتابة", + "RESET" => "إعادة تعيين", + "SAVE" => "احفظ", + "SEARCH" => "ابحث", + "SORT" => "فرز", + "SUBMIT" => "ارسل", + "PRINT" => "اطباعة", + "REMOVE" => "إزالة", + "UNACTIVATED" => "إبطال", + "UPDATE" => "تحديث", + "YES" => "نعم", + "NO" => "لا", + "OPTIONAL" => "اختياري", + + // Misc + "BUILT_WITH_UF" => "بنيت مع UserFrosting", + "ADMINLTE_THEME_BY" => "فكرة رئيسية Almsaeed Studio كل الحقوق محفوظة", + "WELCOME_TO" => "مرحبا بك في {{title}}!" +]; diff --git a/main/app/sprinkles/core/locale/ar/validate.php b/main/app/sprinkles/core/locale/ar/validate.php index bbccab7..52698b6 100644 --- a/main/app/sprinkles/core/locale/ar/validate.php +++ b/main/app/sprinkles/core/locale/ar/validate.php @@ -1,25 +1,25 @@ - [ - "ARRAY" => "القيمات ل {{label}} يجب أن تكون في مجموعة", - "BOOLEAN" => "القيم ل {{label}} يجب أن يكون إما '٠' أو '١'", - "INTEGER" => "القيم ل {{label}} يجب أن يكون رقم", - "INVALID_EMAIL" => "عنوان البريد الإلكتروني غير صالح", - "LENGTH_RANGE" => "{{label}} لابد ان تكون بين {{min}} و {{max}} حورف", - "NO_LEAD_WS" => "القيم ل {{label}} لا يمكن أن تبدأ المساحات، علامات، أو بيضاء أخرى", - "NO_TRAIL_WS" => "القيم ل {{label}} لا يمكن أن ينتهي مع مسافات، علامات، أو بيضاء أخرى", - "REQUIRED" => " تحديد قيمة ل {{label}}" - ] -]; + [ + "ARRAY" => "القيمات ل {{label}} يجب أن تكون في مجموعة", + "BOOLEAN" => "القيم ل {{label}} يجب أن يكون إما '٠' أو '١'", + "INTEGER" => "القيم ل {{label}} يجب أن يكون رقم", + "INVALID_EMAIL" => "عنوان البريد الإلكتروني غير صالح", + "LENGTH_RANGE" => "{{label}} لابد ان تكون بين {{min}} و {{max}} حورف", + "NO_LEAD_WS" => "القيم ل {{label}} لا يمكن أن تبدأ المساحات، علامات، أو بيضاء أخرى", + "NO_TRAIL_WS" => "القيم ل {{label}} لا يمكن أن ينتهي مع مسافات، علامات، أو بيضاء أخرى", + "REQUIRED" => " تحديد قيمة ل {{label}}" + ] +]; diff --git a/main/app/sprinkles/core/locale/de_DE/errors.php b/main/app/sprinkles/core/locale/de_DE/errors.php index 49e3ed5..4246b17 100644 --- a/main/app/sprinkles/core/locale/de_DE/errors.php +++ b/main/app/sprinkles/core/locale/de_DE/errors.php @@ -1,53 +1,53 @@ - [ - "@TRANSLATION" => "Fehler", - - "400" => [ - "TITLE" => "Fehler 400: Ungültige Anforderung", - "DESCRIPTION" => "Die Anfrage-Nachricht war fehlerhaft aufgebaut.", - ], - - "404" => [ - "TITLE" => "Fehler 404: Seite nicht gefunden", - "DESCRIPTION" => "Die angeforderte Ressource wurde nicht gefunden.", - "DETAIL" => "Wir haben versucht Ihre Seite zu finden ...", - "EXPLAIN" => "Die von Ihnen gesuchte Seite konnte nicht gefunden werden.", - "RETURN" => "Klicken Sie Hier, um zur Startseite zurückzukehren." - ], - - "CONFIG" => [ - "TITLE" => "UserFrosting Konfigurationsproblem!", - "DESCRIPTION" => "Einige UserFrosting-Konfigurationsanforderungen wurden nicht erfüllt.", - "DETAIL" => "Etwas stimmt hier nicht.", - "RETURN" => "Bitte beheben Sie die folgenden Fehler dann laden Sie die Website neu." - ], - - "DESCRIPTION" => "Wir haben eine große Störung in der Macht erkannt.", - "DETAIL" => "Hier haben wir:", - - "ENCOUNTERED" => "Uhhh ... etwas ist passiert. Wir wissen nicht was.", - - "MAIL" => "Schwerwiegender Fehler beim Mailversand, wenden Sie sich an Ihren Serveradministrator. Wenn Sie der Administrator sind, überprüfen Sie bitte das UF-Mail-Protokoll.", - - "RETURN" => "Klicken Sie Hier, um zur Startseite zurückzukehren.", - - "SERVER" => "Hoppla, sieht aus als hätte der Server möglicherweise gepatzt. Wenn Sie ein Administrator sind, überprüfen Sie bitte die PHP- oder UF-Fehlerprotokolle.", - - "TITLE" => "Störung in der Kraft" - ] -]; + [ + "@TRANSLATION" => "Fehler", + + "400" => [ + "TITLE" => "Fehler 400: Ungültige Anforderung", + "DESCRIPTION" => "Die Anfrage-Nachricht war fehlerhaft aufgebaut.", + ], + + "404" => [ + "TITLE" => "Fehler 404: Seite nicht gefunden", + "DESCRIPTION" => "Die angeforderte Ressource wurde nicht gefunden.", + "DETAIL" => "Wir haben versucht Ihre Seite zu finden ...", + "EXPLAIN" => "Die von Ihnen gesuchte Seite konnte nicht gefunden werden.", + "RETURN" => "Klicken Sie Hier, um zur Startseite zurückzukehren." + ], + + "CONFIG" => [ + "TITLE" => "UserFrosting Konfigurationsproblem!", + "DESCRIPTION" => "Einige UserFrosting-Konfigurationsanforderungen wurden nicht erfüllt.", + "DETAIL" => "Etwas stimmt hier nicht.", + "RETURN" => "Bitte beheben Sie die folgenden Fehler dann laden Sie die Website neu." + ], + + "DESCRIPTION" => "Wir haben eine große Störung in der Macht erkannt.", + "DETAIL" => "Hier haben wir:", + + "ENCOUNTERED" => "Uhhh ... etwas ist passiert. Wir wissen nicht was.", + + "MAIL" => "Schwerwiegender Fehler beim Mailversand, wenden Sie sich an Ihren Serveradministrator. Wenn Sie der Administrator sind, überprüfen Sie bitte das UF-Mail-Protokoll.", + + "RETURN" => "Klicken Sie Hier, um zur Startseite zurückzukehren.", + + "SERVER" => "Hoppla, sieht aus als hätte der Server möglicherweise gepatzt. Wenn Sie ein Administrator sind, überprüfen Sie bitte die PHP- oder UF-Fehlerprotokolle.", + + "TITLE" => "Störung in der Kraft" + ] +]; diff --git a/main/app/sprinkles/core/locale/de_DE/main.php b/main/app/sprinkles/core/locale/de_DE/main.php index c821115..83f04d9 100644 --- a/main/app/sprinkles/core/locale/de_DE/main.php +++ b/main/app/sprinkles/core/locale/de_DE/main.php @@ -1,20 +1,20 @@ - [ - "FEED" => "Neues", - "EXPLORE" => "Entdecken", - "CHAT" => "Nachrichten", - "FRIENDS" => "Freunde", - "PERSONAL" => "Persönliche Daten" - ], - "CHAT_MESSAGES" => [ - "USER_GROUP_JOIN" => "{{user}} ist der Gruppe beigetreten", - "YOU_GROUP_JOIN" => "Du bist der Gruppe {{group}} beigetreten", - "USER_DISCONNECT" => "{{user}} hat sich vom Server getrennt", - "JOIN_GROUP_PH" => "Betrete eine Gruppe...", - "WRITE_MESSAGE_PH" => "Schreibe eine Nachricht..." - ], - "EXPLORE_TAB" => [ - "USER_SEARCH_PH" => "Suche ein Profil..." - ] + [ + "FEED" => "Neues", + "EXPLORE" => "Entdecken", + "CHAT" => "Nachrichten", + "FRIENDS" => "Freunde", + "PERSONAL" => "Persönliche Daten" + ], + "CHAT_MESSAGES" => [ + "USER_GROUP_JOIN" => "{{user}} ist der Gruppe beigetreten", + "YOU_GROUP_JOIN" => "Du bist der Gruppe {{group}} beigetreten", + "USER_DISCONNECT" => "{{user}} hat sich vom Server getrennt", + "JOIN_GROUP_PH" => "Betrete eine Gruppe...", + "WRITE_MESSAGE_PH" => "Schreibe eine Nachricht..." + ], + "EXPLORE_TAB" => [ + "USER_SEARCH_PH" => "Suche ein Profil..." + ] ]; \ No newline at end of file diff --git a/main/app/sprinkles/core/locale/de_DE/validate.php b/main/app/sprinkles/core/locale/de_DE/validate.php index a1d0c75..6659863 100644 --- a/main/app/sprinkles/core/locale/de_DE/validate.php +++ b/main/app/sprinkles/core/locale/de_DE/validate.php @@ -1,32 +1,32 @@ - [ - "ARRAY" => "Die Werte für {{label}} müssen in einem Feld liegen.", - "BOOLEAN" => "Der Wert für {{label}} muss entweder '0' oder '1' sein.", - "INTEGER" => "Der Wert für {{label}} muss eine ganze Zahl sein.", - "INVALID_EMAIL" => "Ungültige E-Mail-Adresse.", - "LENGTH_RANGE" => "{{label}} muss zwischen {{min}} und {{max}} Zeichen lang sein.", - "NO_LEAD_WS" => "Der Wert für {{label}} kann nicht mit Leerzeichen, Tabulatoren oder anderen Leerzeichen beginnen.", - "NO_TRAIL_WS" => "Der Wert für {{label}} kann nicht mit Leerzeichen, Tabulatoren oder anderen Leerzeichen enden.", - "REQUIRED" => "Bitte geben Sie einen Wert für {{label}} an.", - "SPRUNJE" => [ - "BAD_FILTER" => "{{name}} ist kein gültiger Filter für dieses Sprunje.", - "BAD_LIST" => "{{name}} ist kein gültige Liste für dieses Sprunje.", - "BAD_SORT" => "{{name}} ist kein gültiges Sortierungsfeld für dieses Sprunje." - ] - ] -]; + [ + "ARRAY" => "Die Werte für {{label}} müssen in einem Feld liegen.", + "BOOLEAN" => "Der Wert für {{label}} muss entweder '0' oder '1' sein.", + "INTEGER" => "Der Wert für {{label}} muss eine ganze Zahl sein.", + "INVALID_EMAIL" => "Ungültige E-Mail-Adresse.", + "LENGTH_RANGE" => "{{label}} muss zwischen {{min}} und {{max}} Zeichen lang sein.", + "NO_LEAD_WS" => "Der Wert für {{label}} kann nicht mit Leerzeichen, Tabulatoren oder anderen Leerzeichen beginnen.", + "NO_TRAIL_WS" => "Der Wert für {{label}} kann nicht mit Leerzeichen, Tabulatoren oder anderen Leerzeichen enden.", + "REQUIRED" => "Bitte geben Sie einen Wert für {{label}} an.", + "SPRUNJE" => [ + "BAD_FILTER" => "{{name}} ist kein gültiger Filter für dieses Sprunje.", + "BAD_LIST" => "{{name}} ist kein gültige Liste für dieses Sprunje.", + "BAD_SORT" => "{{name}} ist kein gültiges Sortierungsfeld für dieses Sprunje." + ] + ] +]; diff --git a/main/app/sprinkles/core/locale/en_US/errors.php b/main/app/sprinkles/core/locale/en_US/errors.php index ee982cd..479452b 100644 --- a/main/app/sprinkles/core/locale/en_US/errors.php +++ b/main/app/sprinkles/core/locale/en_US/errors.php @@ -1,51 +1,51 @@ - [ - "@TRANSLATION" => "Error", - - "400" => [ - "TITLE" => "Error 400: Bad Request", - "DESCRIPTION" => "It's probably not your fault.", - ], - - "404" => [ - "TITLE" => "Error 404: Not Found", - "DESCRIPTION" => "We can't seem to find what you're looking for.", - "DETAIL" => "We tried to find your page...", - "EXPLAIN" => "We could not find the page you were looking for.", - "RETURN" => 'Either way, click here to return to the front page.' - ], - - "CONFIG" => [ - "TITLE" => "UserFrosting Configuration Issue!", - "DESCRIPTION" => "Some UserFrosting configuration requirements have not been met.", - "DETAIL" => "Something's not right here.", - "RETURN" => 'Please fix the following errors, then reload.' - ], - - "DESCRIPTION" => "We've sensed a great disturbance in the Force.", - "DETAIL" => "Here's what we got:", - - "ENCOUNTERED" => "Uhhh...something happened. We don't know what.", - - "MAIL" => "Fatal error attempting mail, contact your server administrator. If you are the admin, please check the UserFrosting log.", - - "RETURN" => 'Click here to return to the front page.', - - "SERVER" => "Oops, looks like our server might have goofed. If you're an admin, please check the PHP or UserFrosting logs.", - - "TITLE" => "Disturbance in the Force" - ] -]; + [ + "@TRANSLATION" => "Error", + + "400" => [ + "TITLE" => "Error 400: Bad Request", + "DESCRIPTION" => "It's probably not your fault.", + ], + + "404" => [ + "TITLE" => "Error 404: Not Found", + "DESCRIPTION" => "We can't seem to find what you're looking for.", + "DETAIL" => "We tried to find your page...", + "EXPLAIN" => "We could not find the page you were looking for.", + "RETURN" => 'Either way, click here to return to the front page.' + ], + + "CONFIG" => [ + "TITLE" => "UserFrosting Configuration Issue!", + "DESCRIPTION" => "Some UserFrosting configuration requirements have not been met.", + "DETAIL" => "Something's not right here.", + "RETURN" => 'Please fix the following errors, then reload.' + ], + + "DESCRIPTION" => "We've sensed a great disturbance in the Force.", + "DETAIL" => "Here's what we got:", + + "ENCOUNTERED" => "Uhhh...something happened. We don't know what.", + + "MAIL" => "Fatal error attempting mail, contact your server administrator. If you are the admin, please check the UserFrosting log.", + + "RETURN" => 'Click here to return to the front page.', + + "SERVER" => "Oops, looks like our server might have goofed. If you're an admin, please check the PHP or UserFrosting logs.", + + "TITLE" => "Disturbance in the Force" + ] +]; diff --git a/main/app/sprinkles/core/locale/en_US/main.php b/main/app/sprinkles/core/locale/en_US/main.php index ad155c6..be78e64 100644 --- a/main/app/sprinkles/core/locale/en_US/main.php +++ b/main/app/sprinkles/core/locale/en_US/main.php @@ -1,20 +1,20 @@ - [ - "FEED" => "New", - "EXPLORE" => "Explore", - "CHAT" => "Chat", - "FRIENDS" => "Friends", - "PERSONAL" => "Personal" - ], - "CHAT_MESSAGES" => [ - "USER_GROUP_JOIN" => "{{user}} joined the group", - "YOU_GROUP_JOIN" => "You joined the group {{group}}", - "USER_DISCONNECT" => "{{user}} has disconnected from the server", - "JOIN_GROUP_PH" => "Join a group...", - "WRITE_MESSAGE_PH" => "Write a message..." - ], - "EXPLORE_TAB" => [ - "USER_SEARCH_PH" => "Search a user..." - ] + [ + "FEED" => "New", + "EXPLORE" => "Explore", + "CHAT" => "Chat", + "FRIENDS" => "Friends", + "PERSONAL" => "Personal" + ], + "CHAT_MESSAGES" => [ + "USER_GROUP_JOIN" => "{{user}} joined the group", + "YOU_GROUP_JOIN" => "You joined the group {{group}}", + "USER_DISCONNECT" => "{{user}} has disconnected from the server", + "JOIN_GROUP_PH" => "Join a group...", + "WRITE_MESSAGE_PH" => "Write a message..." + ], + "EXPLORE_TAB" => [ + "USER_SEARCH_PH" => "Search a user..." + ] ]; \ No newline at end of file diff --git a/main/app/sprinkles/core/locale/en_US/messages.php b/main/app/sprinkles/core/locale/en_US/messages.php index 88cfcd6..d355edd 100644 --- a/main/app/sprinkles/core/locale/en_US/messages.php +++ b/main/app/sprinkles/core/locale/en_US/messages.php @@ -1,120 +1,120 @@ - 1, - - "ABOUT" => "About", - - "CAPTCHA" => [ - "@TRANSLATION" => "Captcha", - "FAIL" => "You did not enter the captcha code correctly.", - "SPECIFY" => "Enter the captcha", - "VERIFY" => "Verify the captcha" - ], - - "CSRF_MISSING" => "Missing CSRF token. Try refreshing the page and then submitting again?", - - "DB_INVALID" => "Cannot connect to the database. If you are an administrator, please check your error log.", - "DESCRIPTION" => "Description", - "DOWNLOAD" => [ - "@TRANSLATION" => "Download", - "CSV" => "Download CSV" - ], - - "EMAIL" => [ - "@TRANSLATION" => "Email", - "YOUR" => "Your email address" - ], - - "HOME" => "Home", - - "LEGAL" => [ - "@TRANSLATION" => "Legal Policy", - "DESCRIPTION" => "Our legal policy applies to your usage of this website and our services." - ], - - "LOCALE" => [ - "@TRANSLATION" => "Locale" - ], - - "NAME" => "Name", - "NAVIGATION" => "Navigation", - "NO_RESULTS" => "Sorry, we've got nothing here.", - - "PAGINATION" => [ - "GOTO" => "Jump to Page", - "SHOW" => "Show", - - // Paginator - // possible variables: {size}, {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} - // also {page:input} & {startRow:input} will add a modifiable input in place of the value - "OUTPUT" => "{startRow} to {endRow} of {filteredRows} ({totalRows})", - "NEXT" => "Next page", - "PREVIOUS" => "Previous page", - "FIRST" => "First page", - "LAST" => "Last page" - ], - "PRIVACY" => [ - "@TRANSLATION" => "Privacy Policy", - "DESCRIPTION" => "Our privacy policy outlines what kind of information we collect from you and how we will use it." - ], - - "SLUG" => "Slug", - "SLUG_CONDITION" => "Slug/Conditions", - "SLUG_IN_USE" => "A {{slug}} slug already exists", - "STATUS" => "Status", - "SUGGEST" => "Suggest", - - "UNKNOWN" => "Unknown", - - // Actions words - "ACTIONS" => "Actions", - "ACTIVATE" => "Activate", - "ACTIVE" => "Active", - "ADD" => "Add", - "CANCEL" => "Cancel", - "CONFIRM" => "Confirm", - "CREATE" => "Create", - "DELETE" => "Delete", - "DELETE_CONFIRM" => "Are you sure you want to delete this?", - "DELETE_CONFIRM_YES" => "Yes, delete", - "DELETE_CONFIRM_NAMED" => "Are you sure you want to delete {{name}}?", - "DELETE_CONFIRM_YES_NAMED" => "Yes, delete {{name}}", - "DELETE_CANNOT_UNDONE" => "This action cannot be undone.", - "DELETE_NAMED" => "Delete {{name}}", - "DENY" => "Deny", - "DISABLE" => "Disable", - "DISABLED" => "Disabled", - "EDIT" => "Edit", - "ENABLE" => "Enable", - "ENABLED" => "Enabled", - "OVERRIDE" => "Override", - "RESET" => "Reset", - "SAVE" => "Save", - "SEARCH" => "Search", - "SORT" => "Sort", - "SUBMIT" => "Submit", - "PRINT" => "Print", - "REMOVE" => "Remove", - "UNACTIVATED" => "Unactivated", - "UPDATE" => "Update", - "YES" => "Yes", - "NO" => "No", - "OPTIONAL" => "Optional", - - // Misc. - "BUILT_WITH_UF" => "Built with UserFrosting", - "ADMINLTE_THEME_BY" => "Theme by Almsaeed Studio. All rights reserved", - "WELCOME_TO" => "Welcome to {{title}}!" -]; + 1, + + "ABOUT" => "About", + + "CAPTCHA" => [ + "@TRANSLATION" => "Captcha", + "FAIL" => "You did not enter the captcha code correctly.", + "SPECIFY" => "Enter the captcha", + "VERIFY" => "Verify the captcha" + ], + + "CSRF_MISSING" => "Missing CSRF token. Try refreshing the page and then submitting again?", + + "DB_INVALID" => "Cannot connect to the database. If you are an administrator, please check your error log.", + "DESCRIPTION" => "Description", + "DOWNLOAD" => [ + "@TRANSLATION" => "Download", + "CSV" => "Download CSV" + ], + + "EMAIL" => [ + "@TRANSLATION" => "Email", + "YOUR" => "Your email address" + ], + + "HOME" => "Home", + + "LEGAL" => [ + "@TRANSLATION" => "Legal Policy", + "DESCRIPTION" => "Our legal policy applies to your usage of this website and our services." + ], + + "LOCALE" => [ + "@TRANSLATION" => "Locale" + ], + + "NAME" => "Name", + "NAVIGATION" => "Navigation", + "NO_RESULTS" => "Sorry, we've got nothing here.", + + "PAGINATION" => [ + "GOTO" => "Jump to Page", + "SHOW" => "Show", + + // Paginator + // possible variables: {size}, {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} + // also {page:input} & {startRow:input} will add a modifiable input in place of the value + "OUTPUT" => "{startRow} to {endRow} of {filteredRows} ({totalRows})", + "NEXT" => "Next page", + "PREVIOUS" => "Previous page", + "FIRST" => "First page", + "LAST" => "Last page" + ], + "PRIVACY" => [ + "@TRANSLATION" => "Privacy Policy", + "DESCRIPTION" => "Our privacy policy outlines what kind of information we collect from you and how we will use it." + ], + + "SLUG" => "Slug", + "SLUG_CONDITION" => "Slug/Conditions", + "SLUG_IN_USE" => "A {{slug}} slug already exists", + "STATUS" => "Status", + "SUGGEST" => "Suggest", + + "UNKNOWN" => "Unknown", + + // Actions words + "ACTIONS" => "Actions", + "ACTIVATE" => "Activate", + "ACTIVE" => "Active", + "ADD" => "Add", + "CANCEL" => "Cancel", + "CONFIRM" => "Confirm", + "CREATE" => "Create", + "DELETE" => "Delete", + "DELETE_CONFIRM" => "Are you sure you want to delete this?", + "DELETE_CONFIRM_YES" => "Yes, delete", + "DELETE_CONFIRM_NAMED" => "Are you sure you want to delete {{name}}?", + "DELETE_CONFIRM_YES_NAMED" => "Yes, delete {{name}}", + "DELETE_CANNOT_UNDONE" => "This action cannot be undone.", + "DELETE_NAMED" => "Delete {{name}}", + "DENY" => "Deny", + "DISABLE" => "Disable", + "DISABLED" => "Disabled", + "EDIT" => "Edit", + "ENABLE" => "Enable", + "ENABLED" => "Enabled", + "OVERRIDE" => "Override", + "RESET" => "Reset", + "SAVE" => "Save", + "SEARCH" => "Search", + "SORT" => "Sort", + "SUBMIT" => "Submit", + "PRINT" => "Print", + "REMOVE" => "Remove", + "UNACTIVATED" => "Unactivated", + "UPDATE" => "Update", + "YES" => "Yes", + "NO" => "No", + "OPTIONAL" => "Optional", + + // Misc. + "BUILT_WITH_UF" => "Built with UserFrosting", + "ADMINLTE_THEME_BY" => "Theme by Almsaeed Studio. All rights reserved", + "WELCOME_TO" => "Welcome to {{title}}!" +]; diff --git a/main/app/sprinkles/core/locale/en_US/validate.php b/main/app/sprinkles/core/locale/en_US/validate.php index 8e03c84..95ae835 100644 --- a/main/app/sprinkles/core/locale/en_US/validate.php +++ b/main/app/sprinkles/core/locale/en_US/validate.php @@ -1,33 +1,33 @@ - [ - "ARRAY" => "The values for {{label}} must be in an array.", - "BOOLEAN" => "The value for {{label}} must be either '0' or '1'.", - "INTEGER" => "The value for {{label}} must be an integer.", - "INVALID_EMAIL" => "Invalid email address.", - "LENGTH_RANGE" => "{{label}} must be between {{min}} and {{max}} characters in length.", - "MAX_LENGTH" => "{{label}} must be maximum {{max}} characters in length.", - "MIN_LENGTH" => "{{label}} must be minimum {{min}} characters in length.", - "NO_LEAD_WS" => "The value for {{label}} cannot begin with spaces, tabs, or other whitespace.", - "NO_TRAIL_WS" => "The value for {{label}} cannot end with spaces, tabs, or other whitespace.", - "RANGE" => "The value for {{label}} must be between {{min}} and {{max}}.", - "REQUIRED" => "Please specify a value for {{label}}.", - "SPRUNJE" => [ - "BAD_FILTER" => "{{name}} is not a valid filter for this Sprunje.", - "BAD_LIST" => "{{name}} is not a valid list for this Sprunje.", - "BAD_SORT" => "{{name}} is not a valid sort field for this Sprunje." - ] - ] -]; + [ + "ARRAY" => "The values for {{label}} must be in an array.", + "BOOLEAN" => "The value for {{label}} must be either '0' or '1'.", + "INTEGER" => "The value for {{label}} must be an integer.", + "INVALID_EMAIL" => "Invalid email address.", + "LENGTH_RANGE" => "{{label}} must be between {{min}} and {{max}} characters in length.", + "MAX_LENGTH" => "{{label}} must be maximum {{max}} characters in length.", + "MIN_LENGTH" => "{{label}} must be minimum {{min}} characters in length.", + "NO_LEAD_WS" => "The value for {{label}} cannot begin with spaces, tabs, or other whitespace.", + "NO_TRAIL_WS" => "The value for {{label}} cannot end with spaces, tabs, or other whitespace.", + "RANGE" => "The value for {{label}} must be between {{min}} and {{max}}.", + "REQUIRED" => "Please specify a value for {{label}}.", + "SPRUNJE" => [ + "BAD_FILTER" => "{{name}} is not a valid filter for this Sprunje.", + "BAD_LIST" => "{{name}} is not a valid list for this Sprunje.", + "BAD_SORT" => "{{name}} is not a valid sort field for this Sprunje." + ] + ] +]; diff --git a/main/app/sprinkles/core/locale/es_ES/errors.php b/main/app/sprinkles/core/locale/es_ES/errors.php index 13261cb..362cedb 100644 --- a/main/app/sprinkles/core/locale/es_ES/errors.php +++ b/main/app/sprinkles/core/locale/es_ES/errors.php @@ -1,51 +1,51 @@ - [ - "@TRANSLATION" => "Error", - - "400" => [ - "TITLE" => "Error 400: solicitud incorrecta", - "DESCRIPTION" => "Probablemente no es tu culpa.", - ], - - "404" => [ - "TITLE" => "Error 404 - Página no encontrada", - "DESCRIPTION" => "Parece que no podemos encontrar lo que buscas.", - "DETAIL" => "Intentamos encontrar tu página ...", - "EXPLAIN" => "No pudimos encontrar la página que buscabas.", - "RETURN" => 'De cualquier manera, haga clic en aquí para volver a la página principal.' - ], - - "CONFIG" => [ - "TITLE" => "¡Problema de configuración del Servidor!", - "DESCRIPTION" => "Algunos requisitos de configuración de Servidor no se han cumplido.", - "DETAIL" => "Algo no está bien aquí.", - "RETURN" => 'Corrija los siguientes errores, luego recargue .' - ], - - "DESCRIPTION" => "Hemos sentido una gran perturbación en la Fuerza.", - "DETAIL" => "Esto es lo que tenemos:", - - "ENCOUNTERED" => "Uhhh ... sucedió algo. No sabemos qué.", - - "MAIL" => "Error fatal al intentar enviar correo, póngase en contacto con el administrador del servidor. Si usted es el administrador, compruebe el log de errores.", - - "RETURN" => 'Haga clic en aquí para volver a la página principal.', - - "SERVER" => "¡Vaya, parece que nuestro servidor pudo haber metido la pata. Si eres un administrador, comprueba los registros de errores de PHP o el log de UserFrosting.", - - "TITLE" => "Perturbación en la Fuerza", - ] -]; + [ + "@TRANSLATION" => "Error", + + "400" => [ + "TITLE" => "Error 400: solicitud incorrecta", + "DESCRIPTION" => "Probablemente no es tu culpa.", + ], + + "404" => [ + "TITLE" => "Error 404 - Página no encontrada", + "DESCRIPTION" => "Parece que no podemos encontrar lo que buscas.", + "DETAIL" => "Intentamos encontrar tu página ...", + "EXPLAIN" => "No pudimos encontrar la página que buscabas.", + "RETURN" => 'De cualquier manera, haga clic en aquí para volver a la página principal.' + ], + + "CONFIG" => [ + "TITLE" => "¡Problema de configuración del Servidor!", + "DESCRIPTION" => "Algunos requisitos de configuración de Servidor no se han cumplido.", + "DETAIL" => "Algo no está bien aquí.", + "RETURN" => 'Corrija los siguientes errores, luego recargue .' + ], + + "DESCRIPTION" => "Hemos sentido una gran perturbación en la Fuerza.", + "DETAIL" => "Esto es lo que tenemos:", + + "ENCOUNTERED" => "Uhhh ... sucedió algo. No sabemos qué.", + + "MAIL" => "Error fatal al intentar enviar correo, póngase en contacto con el administrador del servidor. Si usted es el administrador, compruebe el log de errores.", + + "RETURN" => 'Haga clic en aquí para volver a la página principal.', + + "SERVER" => "¡Vaya, parece que nuestro servidor pudo haber metido la pata. Si eres un administrador, comprueba los registros de errores de PHP o el log de UserFrosting.", + + "TITLE" => "Perturbación en la Fuerza", + ] +]; diff --git a/main/app/sprinkles/core/locale/es_ES/messages.php b/main/app/sprinkles/core/locale/es_ES/messages.php index 3e4e640..bacaf70 100644 --- a/main/app/sprinkles/core/locale/es_ES/messages.php +++ b/main/app/sprinkles/core/locale/es_ES/messages.php @@ -1,115 +1,115 @@ - 1, - - "ABOUT" => "Acerca de", - "WELCOME_TO" => "¡Bienvenido a {{title}}!", - - "CAPTCHA" => [ - "@TRANSLATION" => "Captcha", - "FAIL" => "No ha introducido correctamente el código de captcha.", - "SPECIFY" => "Introduzca el captcha", - "VERIFY" => "Verificar el captcha" - ], - - "CSRF_MISSING" => "¿Falta el símbolo CSRF?. Intente refrescar la página y luego volver a enviarla", - - "DB_INVALID" => "No se puede conectar a la base de datos. Si es un administrador, compruebe su registro de errores.", - "DESCRIPTION" => "Descripción", - "DOWNLOAD" => [ - "@TRANSLATION" => "Descargar", - "CSV" => "Descargar CSV" - ], - - "EMAIL" => [ - "@TRANSLATION" => "Email", - "YOUR" => "Tu correo electrónico" - ], - - "HOME" => "Inicio", - - "LEGAL" => "Política Legal", - - "LOCALE" => [ - "@TRANSLATION" => "Traducción" - ], - - "MAIL_ERROR" => "Error fatal al intentar enviar correo, póngase en contacto con el administrador del servidor. Si eres el administrador, comprueba el registro de correo de UF.", - - "NAME" => "Nombre", - "NAVIGATION" => "Navegación", - - "PAGINATION" => [ - "GOTO" => "Ir a la página", - "SHOW" => "Mostrar", - - // Paginator - // possible variables: {size}, {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} - // also {page:input} & {startRow:input} will add a modifiable input in place of the value - "OUTPUT" => "{startRow} a {endRow} de {filteredRows} ({totalRows})", - "NEXT" => "Siguiente página", - "PREVIOUS" => "Pagina anterior", - "FIRST" => "Primera página", - "LAST" => "Última página" - ], - "PRIVACY" => "Política de privacidad", - - "SLUG" => "Slug", - "SLUG_CONDITION" => "Slug/Condiciones", - "SLUG_IN_USE" => "A {{slug}} slug ya existe", - "STATUS" => "Estado", - "SUGGEST" => "Sugerencia", - - "UNKNOWN" => "Desconocido", - - // Actions words - "ACTIONS" => "Acciones", - "ACTIVATE" => "Activar", - "ACTIVE" => "Activo", - "ADD" => "Añadir", - "CANCEL" => "Cancelar", - "CONFIRM" => "Confirmar", - "CREATE" => "Crear", - "DELETE" => "Eliminar", - "DELETE_CONFIRM" => "¿Estás seguro que quieres eliminar esto?", - "DELETE_CONFIRM_YES" => "Sí, borrar", - "DELETE_CONFIRM_NAMED" => "¿Seguro que quieres eliminar {{name}}?", - "DELETE_CONFIRM_YES_NAMED" => "Sí, eliminar {{nombre}}", - "DELETE_CANNOT_UNDONE" => "Esta acción no se puede deshacer.", - "DELETE_NAMED" => "Eliminar {{name}}", - "DENY" => "Negar", - "DISABLE" => "Inhabilitar", - "DISABLED" => "Deshabilidato", - "EDIT" => "Editar", - "ENABLE" => "Habilitar", - "ENABLED" => "Habilitado", - "OVERRIDE" => "Anular", - "RESET" => "Reiniciar", - "SAVE" => "Guardar", - "SEARCH" => "Buscar", - "SORT" => "Ordenar", - "SUBMIT" => "Enviar", - "PRINT" => "Imprimir", - "REMOVE" => "Remover", - "UNACTIVATED" => "Desactivado", - "UPDATE" => "Actualizar", - "YES" => "Si", - "NO" => "No", - "OPTIONAL" => "Opcional", - - // Misc. - "BUILT_WITH_UF" => "Construido con UserFrosting ", - "ADMINLTE_THEME_BY" => "Theme by Almsaeed Studio. All rights reserved" -]; + 1, + + "ABOUT" => "Acerca de", + "WELCOME_TO" => "¡Bienvenido a {{title}}!", + + "CAPTCHA" => [ + "@TRANSLATION" => "Captcha", + "FAIL" => "No ha introducido correctamente el código de captcha.", + "SPECIFY" => "Introduzca el captcha", + "VERIFY" => "Verificar el captcha" + ], + + "CSRF_MISSING" => "¿Falta el símbolo CSRF?. Intente refrescar la página y luego volver a enviarla", + + "DB_INVALID" => "No se puede conectar a la base de datos. Si es un administrador, compruebe su registro de errores.", + "DESCRIPTION" => "Descripción", + "DOWNLOAD" => [ + "@TRANSLATION" => "Descargar", + "CSV" => "Descargar CSV" + ], + + "EMAIL" => [ + "@TRANSLATION" => "Email", + "YOUR" => "Tu correo electrónico" + ], + + "HOME" => "Inicio", + + "LEGAL" => "Política Legal", + + "LOCALE" => [ + "@TRANSLATION" => "Traducción" + ], + + "MAIL_ERROR" => "Error fatal al intentar enviar correo, póngase en contacto con el administrador del servidor. Si eres el administrador, comprueba el registro de correo de UF.", + + "NAME" => "Nombre", + "NAVIGATION" => "Navegación", + + "PAGINATION" => [ + "GOTO" => "Ir a la página", + "SHOW" => "Mostrar", + + // Paginator + // possible variables: {size}, {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} + // also {page:input} & {startRow:input} will add a modifiable input in place of the value + "OUTPUT" => "{startRow} a {endRow} de {filteredRows} ({totalRows})", + "NEXT" => "Siguiente página", + "PREVIOUS" => "Pagina anterior", + "FIRST" => "Primera página", + "LAST" => "Última página" + ], + "PRIVACY" => "Política de privacidad", + + "SLUG" => "Slug", + "SLUG_CONDITION" => "Slug/Condiciones", + "SLUG_IN_USE" => "A {{slug}} slug ya existe", + "STATUS" => "Estado", + "SUGGEST" => "Sugerencia", + + "UNKNOWN" => "Desconocido", + + // Actions words + "ACTIONS" => "Acciones", + "ACTIVATE" => "Activar", + "ACTIVE" => "Activo", + "ADD" => "Añadir", + "CANCEL" => "Cancelar", + "CONFIRM" => "Confirmar", + "CREATE" => "Crear", + "DELETE" => "Eliminar", + "DELETE_CONFIRM" => "¿Estás seguro que quieres eliminar esto?", + "DELETE_CONFIRM_YES" => "Sí, borrar", + "DELETE_CONFIRM_NAMED" => "¿Seguro que quieres eliminar {{name}}?", + "DELETE_CONFIRM_YES_NAMED" => "Sí, eliminar {{nombre}}", + "DELETE_CANNOT_UNDONE" => "Esta acción no se puede deshacer.", + "DELETE_NAMED" => "Eliminar {{name}}", + "DENY" => "Negar", + "DISABLE" => "Inhabilitar", + "DISABLED" => "Deshabilidato", + "EDIT" => "Editar", + "ENABLE" => "Habilitar", + "ENABLED" => "Habilitado", + "OVERRIDE" => "Anular", + "RESET" => "Reiniciar", + "SAVE" => "Guardar", + "SEARCH" => "Buscar", + "SORT" => "Ordenar", + "SUBMIT" => "Enviar", + "PRINT" => "Imprimir", + "REMOVE" => "Remover", + "UNACTIVATED" => "Desactivado", + "UPDATE" => "Actualizar", + "YES" => "Si", + "NO" => "No", + "OPTIONAL" => "Opcional", + + // Misc. + "BUILT_WITH_UF" => "Construido con UserFrosting ", + "ADMINLTE_THEME_BY" => "Theme by Almsaeed Studio. All rights reserved" +]; diff --git a/main/app/sprinkles/core/locale/fa/errors.php b/main/app/sprinkles/core/locale/fa/errors.php index 4a5ba36..76ad548 100644 --- a/main/app/sprinkles/core/locale/fa/errors.php +++ b/main/app/sprinkles/core/locale/fa/errors.php @@ -1,52 +1,52 @@ - [ - "@TRANSLATION" => "خطا", - - "400" => [ - "TITLE" => "خطا 400: درخواست بد", - "DESCRIPTION" => "احتمالا تقصیر شما نیست.", - ], - - "404" => [ - "TITLE" => "خطا 404: صفحه یافت نشد", - "DESCRIPTION" => "به نظر نمیرسد چیزی را که دنبالش هستید پیدا کنیم.", - "DETAIL" => "ما سعی کردیم صفحه شما را پیدا کنیم...", - "EXPLAIN" => "ما نتوانستیم صفحه ی مورد نظر شما را پیدا کنیم.", - "RETURN" => 'در هر حال، اینجا کلیک کنید تا به صفحه اصلی بازگردید.' - ], - - "CONFIG" => [ - "TITLE" => "خطای تنظیمات یوزرفروستینگ!", - "DESCRIPTION" => "برخی از الزامات پیکربندی یوزرفروستینگ به نتیجه نرسید.", - "DETAIL" => "خطایی پیش آمد.", - "RETURN" => 'لطفا خطاهای زیر را اصلاح کنید و سپس مجددا بارگذاری نمایید.' - ], - - "DESCRIPTION" => "ما یک اختلال بزرگ در سیستم احساس کردیم.", - "DETAIL" => "این چیزی است که ما دریافت کردیم", - - "ENCOUNTERED" => "خطایی ویژه. نمیدانیم مشکل چیست.", - - "MAIL" => "خطا در ارسال ایمیل. لطفا با مدیر سیستم تماس برقرار کنید. لطفا لاگ را بررسی کنید.", - - "RETURN" => 'اینجا کلیک تا به صفحه اصلی بازگردید.', - - "SERVER" => "به نظر می آید که در سرور خطایی بوجود آمد. لطفا لاگ پی اچ پی و یوزرفروستینگ را چک کنید.", - - "TITLE" => "اختلالی پدید آمد." - ] -]; + [ + "@TRANSLATION" => "خطا", + + "400" => [ + "TITLE" => "خطا 400: درخواست بد", + "DESCRIPTION" => "احتمالا تقصیر شما نیست.", + ], + + "404" => [ + "TITLE" => "خطا 404: صفحه یافت نشد", + "DESCRIPTION" => "به نظر نمیرسد چیزی را که دنبالش هستید پیدا کنیم.", + "DETAIL" => "ما سعی کردیم صفحه شما را پیدا کنیم...", + "EXPLAIN" => "ما نتوانستیم صفحه ی مورد نظر شما را پیدا کنیم.", + "RETURN" => 'در هر حال، اینجا کلیک کنید تا به صفحه اصلی بازگردید.' + ], + + "CONFIG" => [ + "TITLE" => "خطای تنظیمات یوزرفروستینگ!", + "DESCRIPTION" => "برخی از الزامات پیکربندی یوزرفروستینگ به نتیجه نرسید.", + "DETAIL" => "خطایی پیش آمد.", + "RETURN" => 'لطفا خطاهای زیر را اصلاح کنید و سپس مجددا بارگذاری نمایید.' + ], + + "DESCRIPTION" => "ما یک اختلال بزرگ در سیستم احساس کردیم.", + "DETAIL" => "این چیزی است که ما دریافت کردیم", + + "ENCOUNTERED" => "خطایی ویژه. نمیدانیم مشکل چیست.", + + "MAIL" => "خطا در ارسال ایمیل. لطفا با مدیر سیستم تماس برقرار کنید. لطفا لاگ را بررسی کنید.", + + "RETURN" => 'اینجا کلیک تا به صفحه اصلی بازگردید.', + + "SERVER" => "به نظر می آید که در سرور خطایی بوجود آمد. لطفا لاگ پی اچ پی و یوزرفروستینگ را چک کنید.", + + "TITLE" => "اختلالی پدید آمد." + ] +]; diff --git a/main/app/sprinkles/core/locale/fa/messages.php b/main/app/sprinkles/core/locale/fa/messages.php index af3ea65..46faaee 100644 --- a/main/app/sprinkles/core/locale/fa/messages.php +++ b/main/app/sprinkles/core/locale/fa/messages.php @@ -1,110 +1,110 @@ - 1, - - "ABOUT" => "درباره", - - "CAPTCHA" => [ - "@TRANSLATION" => "کد امنیتی", - "FAIL" => "کد امنیتی درست نیست", - "SPECIFY" => "کد امنیتی را وارد کنید", - "VERIFY" => "کد امنیتی را بررسی کنید" - ], - - "CSRF_MISSING" => "سی اس آر اف توکن یافت نشد. لطفا صفحه را از نو بارگذاری کرده و دوباره تلاش کنید.", - - "DB_INVALID" => "خطا در اتصال به پایگاه داده ها. لطفا لاگ پی اچ پی را چک کنید.", - "DESCRIPTION" => "توضیحات", - "DOWNLOAD" => [ - "@TRANSLATION" => "دانلود", - "CSV" => "دانلود سی اس وی" - ], - - "EMAIL" => [ - "@TRANSLATION" => "ایمیل", - "YOUR" => "آدرس ایمیل" - ], - - "HOME" => "خانه", - - "LEGAL" => "سیاست حقوقی", - - "LOCALE" => [ - "@TRANSLATION" => "زبان" - ], - - "NAME" => "نام", - "NAVIGATION" => "جهت یابی", - "NO_RESULTS" => "با عرض پوزش، چیزی یافت نشد.", - - "PAGINATION" => [ - "GOTO" => "پرش به صفحه", - "SHOW" => "نمایش", - - // Paginator - // possible variables: {size}, {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} - // also {page:input} & {startRow:input} will add a modifiable input in place of the value - "OUTPUT" => "{startRow} تا {endRow} از {filteredRows} ({totalRows})" - ], - "PRIVACY" => "سیاست حفظ حریم خصوصی", - - "SLUG" => "اسلاگ", - "SLUG_CONDITION" => "اسلاگ/شرایط", - "SLUG_IN_USE" => "{{slug}} وجود دارد", - "STATUS" => "وضعیت", - "SUGGEST" => "پیشنهاد", - - "UNKNOWN" => "ناشناخته", - - // Actions words - "ACTIONS" => "اقدام ها", - "ACTIVATE" => "فعال سازی", - "ACTIVE" => "فعال", - "ADD" => "اضافه کردن", - "CANCEL" => "لغو", - "CONFIRM" => "تایید", - "CREATE" => "اضافه کردن", - "DELETE" => "حذف", - "DELETE_CONFIRM" => "آیا مطمئن هستید که میخواهید این را حذف کنید؟", - "DELETE_CONFIRM_YES" => "بله، حذف شود", - "DELETE_CONFIRM_NAMED" => "اطمینان دارید که میخواهید {{name}} را حذف کنید؟", - "DELETE_CONFIRM_YES_NAMED" => "بله، {{name}} حذف شود", - "DELETE_CANNOT_UNDONE" => "این عملیات قابل بازگشت نیست.", - "DELETE_NAMED" => "{{name}} حذف شود", - "DENY" => "انکار", - "DISABLE" => "غیر فعال", - "DISABLED" => "غیر فعال", - "EDIT" => "ویرایش", - "ENABLE" => "فعال", - "ENABLED" => "فعال", - "OVERRIDE" => "تغییر", - "RESET" => "تنظیم مجدد", - "SAVE" => "ذخیره", - "SEARCH" => "جست و جو", - "SORT" => "مرتب سازی", - "SUBMIT" => "ارسال", - "PRINT" => "چاپ", - "REMOVE" => "حذف", - "UNACTIVATED" => "غیر فعال", - "UPDATE" => "به روز رسانی", - "YES" => "بله", - "NO" => "خیر", - "OPTIONAL" => "اختیاری", - - // Misc. - "BUILT_WITH_UF" => "ساخته شده با یوزرفراستینگ", - "ADMINLTE_THEME_BY" => "قالب از Almsaeed Studio. تمامی حقوق محفوظ است" -]; + 1, + + "ABOUT" => "درباره", + + "CAPTCHA" => [ + "@TRANSLATION" => "کد امنیتی", + "FAIL" => "کد امنیتی درست نیست", + "SPECIFY" => "کد امنیتی را وارد کنید", + "VERIFY" => "کد امنیتی را بررسی کنید" + ], + + "CSRF_MISSING" => "سی اس آر اف توکن یافت نشد. لطفا صفحه را از نو بارگذاری کرده و دوباره تلاش کنید.", + + "DB_INVALID" => "خطا در اتصال به پایگاه داده ها. لطفا لاگ پی اچ پی را چک کنید.", + "DESCRIPTION" => "توضیحات", + "DOWNLOAD" => [ + "@TRANSLATION" => "دانلود", + "CSV" => "دانلود سی اس وی" + ], + + "EMAIL" => [ + "@TRANSLATION" => "ایمیل", + "YOUR" => "آدرس ایمیل" + ], + + "HOME" => "خانه", + + "LEGAL" => "سیاست حقوقی", + + "LOCALE" => [ + "@TRANSLATION" => "زبان" + ], + + "NAME" => "نام", + "NAVIGATION" => "جهت یابی", + "NO_RESULTS" => "با عرض پوزش، چیزی یافت نشد.", + + "PAGINATION" => [ + "GOTO" => "پرش به صفحه", + "SHOW" => "نمایش", + + // Paginator + // possible variables: {size}, {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} + // also {page:input} & {startRow:input} will add a modifiable input in place of the value + "OUTPUT" => "{startRow} تا {endRow} از {filteredRows} ({totalRows})" + ], + "PRIVACY" => "سیاست حفظ حریم خصوصی", + + "SLUG" => "اسلاگ", + "SLUG_CONDITION" => "اسلاگ/شرایط", + "SLUG_IN_USE" => "{{slug}} وجود دارد", + "STATUS" => "وضعیت", + "SUGGEST" => "پیشنهاد", + + "UNKNOWN" => "ناشناخته", + + // Actions words + "ACTIONS" => "اقدام ها", + "ACTIVATE" => "فعال سازی", + "ACTIVE" => "فعال", + "ADD" => "اضافه کردن", + "CANCEL" => "لغو", + "CONFIRM" => "تایید", + "CREATE" => "اضافه کردن", + "DELETE" => "حذف", + "DELETE_CONFIRM" => "آیا مطمئن هستید که میخواهید این را حذف کنید؟", + "DELETE_CONFIRM_YES" => "بله، حذف شود", + "DELETE_CONFIRM_NAMED" => "اطمینان دارید که میخواهید {{name}} را حذف کنید؟", + "DELETE_CONFIRM_YES_NAMED" => "بله، {{name}} حذف شود", + "DELETE_CANNOT_UNDONE" => "این عملیات قابل بازگشت نیست.", + "DELETE_NAMED" => "{{name}} حذف شود", + "DENY" => "انکار", + "DISABLE" => "غیر فعال", + "DISABLED" => "غیر فعال", + "EDIT" => "ویرایش", + "ENABLE" => "فعال", + "ENABLED" => "فعال", + "OVERRIDE" => "تغییر", + "RESET" => "تنظیم مجدد", + "SAVE" => "ذخیره", + "SEARCH" => "جست و جو", + "SORT" => "مرتب سازی", + "SUBMIT" => "ارسال", + "PRINT" => "چاپ", + "REMOVE" => "حذف", + "UNACTIVATED" => "غیر فعال", + "UPDATE" => "به روز رسانی", + "YES" => "بله", + "NO" => "خیر", + "OPTIONAL" => "اختیاری", + + // Misc. + "BUILT_WITH_UF" => "ساخته شده با یوزرفراستینگ", + "ADMINLTE_THEME_BY" => "قالب از Almsaeed Studio. تمامی حقوق محفوظ است" +]; diff --git a/main/app/sprinkles/core/locale/fa/validate.php b/main/app/sprinkles/core/locale/fa/validate.php index 54d7afe..d0f0bcd 100644 --- a/main/app/sprinkles/core/locale/fa/validate.php +++ b/main/app/sprinkles/core/locale/fa/validate.php @@ -1,31 +1,31 @@ - [ - "ARRAY" => "مقادیر {{label}} باید از یک آرایه باشند.", - "BOOLEAN" => "مقدار {{label}} باید 1 یا 0 باشد.", - "INTEGER" => "مقدار {{label}} باید یک عدد اینتجر باشد.", - "INVALID_EMAIL" => "آدرس پست الکترونیکی صحیح نیست.", - "LENGTH_RANGE" => "{{label}} باید بین {{min}} و {{max}} حرف باشد.", - "NO_LEAD_WS" => "مقدار {{label}} نباید با فاصله شروع شود.", - "NO_TRAIL_WS" => "مقدار {{label}} نباید با فاصله تمام شود.", - "REQUIRED" => "لطفا برای {{label}} مقداری تعیین کنید.", - "SPRUNJE" => [ - "BAD_FILTER" => "{{name}} فیلتر صحیحی نیست.", - "BAD_LIST" => "{{name}} لیست صحیحی نیست.", - "BAD_SORT" => "{{name}} فیلد مرتب سازی صحیحی نیست." - ] - ] -]; + [ + "ARRAY" => "مقادیر {{label}} باید از یک آرایه باشند.", + "BOOLEAN" => "مقدار {{label}} باید 1 یا 0 باشد.", + "INTEGER" => "مقدار {{label}} باید یک عدد اینتجر باشد.", + "INVALID_EMAIL" => "آدرس پست الکترونیکی صحیح نیست.", + "LENGTH_RANGE" => "{{label}} باید بین {{min}} و {{max}} حرف باشد.", + "NO_LEAD_WS" => "مقدار {{label}} نباید با فاصله شروع شود.", + "NO_TRAIL_WS" => "مقدار {{label}} نباید با فاصله تمام شود.", + "REQUIRED" => "لطفا برای {{label}} مقداری تعیین کنید.", + "SPRUNJE" => [ + "BAD_FILTER" => "{{name}} فیلتر صحیحی نیست.", + "BAD_LIST" => "{{name}} لیست صحیحی نیست.", + "BAD_SORT" => "{{name}} فیلد مرتب سازی صحیحی نیست." + ] + ] +]; diff --git a/main/app/sprinkles/core/locale/fr_FR/main.php b/main/app/sprinkles/core/locale/fr_FR/main.php index 2bb37a8..46d9060 100644 --- a/main/app/sprinkles/core/locale/fr_FR/main.php +++ b/main/app/sprinkles/core/locale/fr_FR/main.php @@ -1,20 +1,20 @@ - [ - "FEED" => "D'actualités", - "EXPLORE" => "Dépister", - "CHAT" => "Message", - "FRIENDS" => "Camarades", - "PERSONAL" => "Personnelles" - ], - "CHAT_MESSAGES" => [ - "USER_GROUP_JOIN" => "{{user}} s'est joint au groupe", - "YOU_GROUP_JOIN" => "Vous avez rejoint le groupe {{group}}", - "USER_DISCONNECT" => "{{user}} s'est déconnecté du serveur", - "JOIN_GROUP_PH" => "Rejoindre un groupe...", - "WRITE_MESSAGE_PH" => "Ecrire un message..." - ], - "EXPLORE_TAB" => [ - "USER_SEARCH_PH" => "Rechercher un profil..." - ] -]; + [ + "FEED" => "D'actualités", + "EXPLORE" => "Dépister", + "CHAT" => "Message", + "FRIENDS" => "Camarades", + "PERSONAL" => "Personnelles" + ], + "CHAT_MESSAGES" => [ + "USER_GROUP_JOIN" => "{{user}} s'est joint au groupe", + "YOU_GROUP_JOIN" => "Vous avez rejoint le groupe {{group}}", + "USER_DISCONNECT" => "{{user}} s'est déconnecté du serveur", + "JOIN_GROUP_PH" => "Rejoindre un groupe...", + "WRITE_MESSAGE_PH" => "Ecrire un message..." + ], + "EXPLORE_TAB" => [ + "USER_SEARCH_PH" => "Rechercher un profil..." + ] +]; diff --git a/main/app/sprinkles/core/locale/fr_FR/messages.php b/main/app/sprinkles/core/locale/fr_FR/messages.php index eb971a8..21c456a 100644 --- a/main/app/sprinkles/core/locale/fr_FR/messages.php +++ b/main/app/sprinkles/core/locale/fr_FR/messages.php @@ -1,105 +1,105 @@ - 2, - - "ABOUT" => "À propos", - - "CAPTCHA" => [ - "@TRANSLATE" => "Captcha", - "VERIFY" => "Vérification du captcha", - "SPECIFY" => "Entrer la valeur du captcha", - "FAIL" => "La valeur du captcha n'a pas été entrée correctement." - ], - - "CSRF_MISSING" => "Jeton CSRF manquant. Essayez de rafraîchir la page et de soumettre de nouveau?", - - "DB_INVALID" => "Impossible de se connecter à la base de données. Si vous êtes un administrateur, vérifiez votre journal d'erreurs.", - "DESCRIPTION" => "Description", - "DOWNLOAD" => [ - "@TRANSLATION" => "Télécharger", - "CSV" => "Télécharger CSV" - ], - - "EMAIL" => [ - "@TRANSLATION" => "Email", - "YOUR" => "Votre adresse email" - ], - - "HOME" => "Accueil", - - "LEGAL" => "Politique légale", - - "LOCALE" => [ - "@TRANSLATION" => "Langue" - ], - - "NAME" => "Nom", - "NAVIGATION" => "Menu principal", - "NO_RESULTS" => "Aucun résultat trouvé.", - - "PAGINATION" => [ - "GOTO" => "Aller à la page", - "SHOW" => "Afficher", - "OUTPUT" => "{startRow} à {endRow} de {filteredRows} ({totalRows})" - ], - "PRIVACY" => "Politique de confidentialité", - - "SLUG" => "Jeton", - "SLUG_CONDITION" => "Jeton/Conditions", - "SLUG_IN_USE" => "Un jeton {{slug}} existe déjà", - "STATUS" => "Statut", - "SUGGEST" => "Suggérer", - - "UNKNOWN" => "Inconnu", - - // Actions words - "ACTIONS" => "Actions", - "ACTIVATE" => "Autoriser", - "ACTIVE" => "Activé", - "ADD" => "Ajouter", - "CANCEL" => "Annuler", - "CONFIRM" => "Confirmer", - "CREATE" => "Créer", - "DELETE" => "Supprimer", - "DELETE_CONFIRM" => "Êtes-vous sûr de vouloir supprimer ceci?", - "DELETE_CONFIRM_YES" => "Oui, supprimer", - "DELETE_CONFIRM_NAMED" => "Êtes-vous sûr de vouloir supprimer {{name}}?", - "DELETE_CONFIRM_YES_NAMED" => "Oui, supprimer {{name}}", - "DELETE_CANNOT_UNDONE" => "Cette action ne peut être annulée.", //This action cannot be undone - "DELETE_NAMED" => "Supprimer {{name}}", - "DENY" => "Refuser", - "DISABLE" => "Désactiver", - "DISABLED" => "Désactivé", - "EDIT" => "Modifier", - "ENABLE" => "Activer", - "ENABLED" => "Activé", - "OVERRIDE" => "Forcer", - "RESET" => "Réinitialiser", - "SAVE" => "Sauvegarder", - "SEARCH" => "Rechercher", - "SORT" => "Trier", - "SUBMIT" => "Envoyer", - "PRINT" => "Imprimer", - "REMOVE" => "Supprimer", - "UNACTIVATED" => "Non activé", - "UPDATE" => "Mettre à jour", - "YES" => "Oui", - "NO" => "Non", - "OPTIONAL" => "Facultatif", - - // Misc. - "BUILT_WITH_UF" => "Créé avec UserFrosting", - "ADMINLTE_THEME_BY" => "Thème par Almsaeed Studio. Tous droits réservés" + 2, + + "ABOUT" => "À propos", + + "CAPTCHA" => [ + "@TRANSLATE" => "Captcha", + "VERIFY" => "Vérification du captcha", + "SPECIFY" => "Entrer la valeur du captcha", + "FAIL" => "La valeur du captcha n'a pas été entrée correctement." + ], + + "CSRF_MISSING" => "Jeton CSRF manquant. Essayez de rafraîchir la page et de soumettre de nouveau?", + + "DB_INVALID" => "Impossible de se connecter à la base de données. Si vous êtes un administrateur, vérifiez votre journal d'erreurs.", + "DESCRIPTION" => "Description", + "DOWNLOAD" => [ + "@TRANSLATION" => "Télécharger", + "CSV" => "Télécharger CSV" + ], + + "EMAIL" => [ + "@TRANSLATION" => "Email", + "YOUR" => "Votre adresse email" + ], + + "HOME" => "Accueil", + + "LEGAL" => "Politique légale", + + "LOCALE" => [ + "@TRANSLATION" => "Langue" + ], + + "NAME" => "Nom", + "NAVIGATION" => "Menu principal", + "NO_RESULTS" => "Aucun résultat trouvé.", + + "PAGINATION" => [ + "GOTO" => "Aller à la page", + "SHOW" => "Afficher", + "OUTPUT" => "{startRow} à {endRow} de {filteredRows} ({totalRows})" + ], + "PRIVACY" => "Politique de confidentialité", + + "SLUG" => "Jeton", + "SLUG_CONDITION" => "Jeton/Conditions", + "SLUG_IN_USE" => "Un jeton {{slug}} existe déjà", + "STATUS" => "Statut", + "SUGGEST" => "Suggérer", + + "UNKNOWN" => "Inconnu", + + // Actions words + "ACTIONS" => "Actions", + "ACTIVATE" => "Autoriser", + "ACTIVE" => "Activé", + "ADD" => "Ajouter", + "CANCEL" => "Annuler", + "CONFIRM" => "Confirmer", + "CREATE" => "Créer", + "DELETE" => "Supprimer", + "DELETE_CONFIRM" => "Êtes-vous sûr de vouloir supprimer ceci?", + "DELETE_CONFIRM_YES" => "Oui, supprimer", + "DELETE_CONFIRM_NAMED" => "Êtes-vous sûr de vouloir supprimer {{name}}?", + "DELETE_CONFIRM_YES_NAMED" => "Oui, supprimer {{name}}", + "DELETE_CANNOT_UNDONE" => "Cette action ne peut être annulée.", //This action cannot be undone + "DELETE_NAMED" => "Supprimer {{name}}", + "DENY" => "Refuser", + "DISABLE" => "Désactiver", + "DISABLED" => "Désactivé", + "EDIT" => "Modifier", + "ENABLE" => "Activer", + "ENABLED" => "Activé", + "OVERRIDE" => "Forcer", + "RESET" => "Réinitialiser", + "SAVE" => "Sauvegarder", + "SEARCH" => "Rechercher", + "SORT" => "Trier", + "SUBMIT" => "Envoyer", + "PRINT" => "Imprimer", + "REMOVE" => "Supprimer", + "UNACTIVATED" => "Non activé", + "UPDATE" => "Mettre à jour", + "YES" => "Oui", + "NO" => "Non", + "OPTIONAL" => "Facultatif", + + // Misc. + "BUILT_WITH_UF" => "Créé avec UserFrosting", + "ADMINLTE_THEME_BY" => "Thème par Almsaeed Studio. Tous droits réservés" ]; \ No newline at end of file diff --git a/main/app/sprinkles/core/locale/fr_FR/validate.php b/main/app/sprinkles/core/locale/fr_FR/validate.php index 261244d..b928fc9 100644 --- a/main/app/sprinkles/core/locale/fr_FR/validate.php +++ b/main/app/sprinkles/core/locale/fr_FR/validate.php @@ -1,33 +1,33 @@ - [ - "ARRAY" => "Les valeurs de {{label}} doivent être dans un tableau.", - "BOOLEAN" => "La valeur de {{label}} doit être '0' ou '1'.", - "INTEGER" => "La valeur de {{label}} doit être un nombre entier.", - "INVALID_EMAIL" => "Addresse email invalide.", - "LENGTH_RANGE" => "La valeur de {{label}} doit faire entre {{min}} et {{max}} caractères.", - "MAX_LENGTH" => "La valeur de {{label}} doit être d'un maximum de {{max}} caractères.", - "MIN_LENGTH" => "La valeur de {{label}} doit être d'un minimum de {{min}} caractères.", - "NO_LEAD_WS" => "La valeur de {{label}} ne peut pas commencer par des espaces, des tabulations ou d'autres caractères invisibles", - "NO_TRAIL_WS" => "La valeur de {{label}} ne peut pas se terminer par des espaces, des tabulations ou d'autres caractères invisibles", - "RANGE" => "Le champ {{label}} doit être une valeur entre {{min}} et {{max}}.", - "REQUIRED" => "Le champ {{label}} doit être rempli.", - "SPRUNJE" => [ - "BAD_FILTER" => "{{name}} ne peut pas être utilisé pour filtrer ce Sprunje.", - "BAD_LIST" => "{{name}} is not a valid list for this Sprunje.", - "BAD_SORT" => "{{name}} ne peut pas être utilisé pour trier Sprunje." - ] - ] + [ + "ARRAY" => "Les valeurs de {{label}} doivent être dans un tableau.", + "BOOLEAN" => "La valeur de {{label}} doit être '0' ou '1'.", + "INTEGER" => "La valeur de {{label}} doit être un nombre entier.", + "INVALID_EMAIL" => "Addresse email invalide.", + "LENGTH_RANGE" => "La valeur de {{label}} doit faire entre {{min}} et {{max}} caractères.", + "MAX_LENGTH" => "La valeur de {{label}} doit être d'un maximum de {{max}} caractères.", + "MIN_LENGTH" => "La valeur de {{label}} doit être d'un minimum de {{min}} caractères.", + "NO_LEAD_WS" => "La valeur de {{label}} ne peut pas commencer par des espaces, des tabulations ou d'autres caractères invisibles", + "NO_TRAIL_WS" => "La valeur de {{label}} ne peut pas se terminer par des espaces, des tabulations ou d'autres caractères invisibles", + "RANGE" => "Le champ {{label}} doit être une valeur entre {{min}} et {{max}}.", + "REQUIRED" => "Le champ {{label}} doit être rempli.", + "SPRUNJE" => [ + "BAD_FILTER" => "{{name}} ne peut pas être utilisé pour filtrer ce Sprunje.", + "BAD_LIST" => "{{name}} is not a valid list for this Sprunje.", + "BAD_SORT" => "{{name}} ne peut pas être utilisé pour trier Sprunje." + ] + ] ]; \ No newline at end of file diff --git a/main/app/sprinkles/core/locale/it_IT/messages.php b/main/app/sprinkles/core/locale/it_IT/messages.php index 8f269e7..76b9aa5 100644 --- a/main/app/sprinkles/core/locale/it_IT/messages.php +++ b/main/app/sprinkles/core/locale/it_IT/messages.php @@ -1,123 +1,123 @@ - 1, - - "ABOUT" => "Riguardo a noi", - - "CAPTCHA" => [ - "@TRANSLATION" => "Captcha", - "FAIL" => "Domanda di sicurezza sbagliata", - "SPECIFY" => "Inserire il captcha", - "VERIFY" => "Verifica la captcha" - ], - - "CSRF_MISSING" => "Sigillo CSRF mancante. Prova a aggiornare la pagina e poi di inviarlo nuovamente?", - - "DB_INVALID" => "Impossibile connettersi al database. Se sei un amministratore, controlla il registro PHP o UserFrosting.", - "DESCRIPTION" => "Descrizione", - "DOWNLOAD" => [ - "@TRANSLATION" => "Scaricare", - "CSV" => "Scarica CSV" - ], - - "EMAIL" => [ - "@TRANSLATION" => "E-mail", - "YOUR" => "La tua email" - ], - - "HOME" => "Inizio", - - "LEGAL" => [ - "@TRANSLATION" => "Politica Legale", - "DESCRIPTION" => "La nostra politica legale si applica al tuo utilizzo di questo sito e dei nostri servizi." - ], - - "LOCALE" => [ - "@TRANSLATION" => "Località" - ], - - "NAME" => "Nome", - "NAVIGATION" => "Navigazione", - "NO_RESULTS" => "Spiacenti, non abbiamo niente qui.", - - "PAGINATION" => [ - "GOTO" => "Vai alla pagina", - "SHOW" => "Mostrare", - - // Paginator - // possible variables: {size}, {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} - // also {page:input} & {startRow:input} will add a modifiable input in place of the value - "OUTPUT" => "{startRow} a {endRow} di {filteredRows} ({totalRows})", - "NEXT" => "Pagina successiva", - "PREVIOUS" => "Pagina precedente", - "FIRST" => "Prima pagina", - "LAST" => "Ultima pagina" - ], - "PRIVACY" => [ - "@TRANSLATION" => "Politica sulla riservatezza", - "DESCRIPTION" => "La nostra politica sulla privacy descrive quali tipi di informazioni raccoglieremo da te e come lo useremo." - ], - - "SLUG" => "Slug", - "SLUG_CONDITION" => "Slug/Condizioni", - "SLUG_IN_USE" => "Esiste già uno slug {{slug}}", - "STATUS" => "Stato", - "SUGGEST" => "Suggerire", - - "UNKNOWN" => "Sconosciuto", - - // Actions words - "ACTIONS" => "Azioni", - "ACTIVATE" => "Attivare", - "ACTIVE" => "Attivo", - "ADD" => "Aggiungere", - "CANCEL" => "Annulla", - "CONFIRM" => "Conferma", - "CREATE" => "Creare", - "DELETE" => "Elimina", - "DELETE_CONFIRM" => "Sei sicuro di voler cancellare questo?", - "DELETE_CONFIRM_YES" => "Sì, elimini", - "DELETE_CONFIRM_NAMED" => "Sei sicuro di voler eliminare {{name}}?", - "DELETE_CONFIRM_YES_NAMED" => "Sì, eliminare {{name}}", - "DELETE_CANNOT_UNDONE" => "Questa azione non può essere annullata.", - "DELETE_NAMED" => "Elimina {{name}}", - "DENY" => "Nega", - "DISABLE" => "Disattivare", - "DISABLED" => "Disabilitato", - "EDIT" => "Modifica", - "ENABLE" => "Abilitare", - "ENABLED" => "Abilitato", - "OVERRIDE" => "Alterare", - "RESET" => "Azzerare", - "SAVE" => "Memorizzare", - "SEARCH" => "Cercare", - "SORT" => "Ordinare", - "SUBMIT" => "Inviare", - "SUCCESS" => "Successo", - "PRINT" => "Stampare", - "REMOVE" => "Rimuovere", - "UNACTIVATED" => "Non attivato", - "UPDATE" => "Aggiornare", - "YES" => "Sì", - "NO" => "No", - "OPTIONAL" => "Opzionale", - - // Misc. - "BUILT_WITH_UF" => "Construito UserFrosting", - "ADMINLTE_THEME_BY" => "Tema da Almsaeed Studio. Tutti i diritti riservati", - "WELCOME_TO" => "Benvenuto a {{title}}!" -]; + 1, + + "ABOUT" => "Riguardo a noi", + + "CAPTCHA" => [ + "@TRANSLATION" => "Captcha", + "FAIL" => "Domanda di sicurezza sbagliata", + "SPECIFY" => "Inserire il captcha", + "VERIFY" => "Verifica la captcha" + ], + + "CSRF_MISSING" => "Sigillo CSRF mancante. Prova a aggiornare la pagina e poi di inviarlo nuovamente?", + + "DB_INVALID" => "Impossibile connettersi al database. Se sei un amministratore, controlla il registro PHP o UserFrosting.", + "DESCRIPTION" => "Descrizione", + "DOWNLOAD" => [ + "@TRANSLATION" => "Scaricare", + "CSV" => "Scarica CSV" + ], + + "EMAIL" => [ + "@TRANSLATION" => "E-mail", + "YOUR" => "La tua email" + ], + + "HOME" => "Inizio", + + "LEGAL" => [ + "@TRANSLATION" => "Politica Legale", + "DESCRIPTION" => "La nostra politica legale si applica al tuo utilizzo di questo sito e dei nostri servizi." + ], + + "LOCALE" => [ + "@TRANSLATION" => "Località" + ], + + "NAME" => "Nome", + "NAVIGATION" => "Navigazione", + "NO_RESULTS" => "Spiacenti, non abbiamo niente qui.", + + "PAGINATION" => [ + "GOTO" => "Vai alla pagina", + "SHOW" => "Mostrare", + + // Paginator + // possible variables: {size}, {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} + // also {page:input} & {startRow:input} will add a modifiable input in place of the value + "OUTPUT" => "{startRow} a {endRow} di {filteredRows} ({totalRows})", + "NEXT" => "Pagina successiva", + "PREVIOUS" => "Pagina precedente", + "FIRST" => "Prima pagina", + "LAST" => "Ultima pagina" + ], + "PRIVACY" => [ + "@TRANSLATION" => "Politica sulla riservatezza", + "DESCRIPTION" => "La nostra politica sulla privacy descrive quali tipi di informazioni raccoglieremo da te e come lo useremo." + ], + + "SLUG" => "Slug", + "SLUG_CONDITION" => "Slug/Condizioni", + "SLUG_IN_USE" => "Esiste già uno slug {{slug}}", + "STATUS" => "Stato", + "SUGGEST" => "Suggerire", + + "UNKNOWN" => "Sconosciuto", + + // Actions words + "ACTIONS" => "Azioni", + "ACTIVATE" => "Attivare", + "ACTIVE" => "Attivo", + "ADD" => "Aggiungere", + "CANCEL" => "Annulla", + "CONFIRM" => "Conferma", + "CREATE" => "Creare", + "DELETE" => "Elimina", + "DELETE_CONFIRM" => "Sei sicuro di voler cancellare questo?", + "DELETE_CONFIRM_YES" => "Sì, elimini", + "DELETE_CONFIRM_NAMED" => "Sei sicuro di voler eliminare {{name}}?", + "DELETE_CONFIRM_YES_NAMED" => "Sì, eliminare {{name}}", + "DELETE_CANNOT_UNDONE" => "Questa azione non può essere annullata.", + "DELETE_NAMED" => "Elimina {{name}}", + "DENY" => "Nega", + "DISABLE" => "Disattivare", + "DISABLED" => "Disabilitato", + "EDIT" => "Modifica", + "ENABLE" => "Abilitare", + "ENABLED" => "Abilitato", + "OVERRIDE" => "Alterare", + "RESET" => "Azzerare", + "SAVE" => "Memorizzare", + "SEARCH" => "Cercare", + "SORT" => "Ordinare", + "SUBMIT" => "Inviare", + "SUCCESS" => "Successo", + "PRINT" => "Stampare", + "REMOVE" => "Rimuovere", + "UNACTIVATED" => "Non attivato", + "UPDATE" => "Aggiornare", + "YES" => "Sì", + "NO" => "No", + "OPTIONAL" => "Opzionale", + + // Misc. + "BUILT_WITH_UF" => "Construito UserFrosting", + "ADMINLTE_THEME_BY" => "Tema da Almsaeed Studio. Tutti i diritti riservati", + "WELCOME_TO" => "Benvenuto a {{title}}!" +]; diff --git a/main/app/sprinkles/core/locale/it_IT/validate.php b/main/app/sprinkles/core/locale/it_IT/validate.php index a800e6b..d2f0ade 100644 --- a/main/app/sprinkles/core/locale/it_IT/validate.php +++ b/main/app/sprinkles/core/locale/it_IT/validate.php @@ -1,32 +1,32 @@ - [ - "ARRAY" => "I valori per {{label}} devono essere in un vettore.", - "BOOLEAN" => "Il valore per {{label}} deve essere '0' o '1'.", - "INTEGER" => "Il valore per {{label}} deve essere un intero.", - "INVALID_EMAIL" => "Indirizzo mail non valido", - "LENGTH_RANGE" => "{{label}} deve essere compreso tra i caratteri {{min}} e {{max}} in lunghezza.", - "NO_LEAD_WS" => "Il valore di {{label}} non può iniziare con spazi, tabulazioni o altri spazi vuoti.", - "NO_TRAIL_WS" => "Il valore di {{label}} non può terminare con spazi, tabulazioni o altri spazi vuoti.", - "REQUIRED" => "Il campo {{label}} deve essere specificato.", - "SPRUNJE" => [ - "BAD_FILTER" => "{{name}} non è un filtro valido per questo Sprunje.", - "BAD_LIST" => " {{name}} non è un elenco valido per questo Sprunje.", - "BAD_SORT" => "{{name}} non è un campo di ordinamento valido per questo Sprunje." - ] - ] -]; + [ + "ARRAY" => "I valori per {{label}} devono essere in un vettore.", + "BOOLEAN" => "Il valore per {{label}} deve essere '0' o '1'.", + "INTEGER" => "Il valore per {{label}} deve essere un intero.", + "INVALID_EMAIL" => "Indirizzo mail non valido", + "LENGTH_RANGE" => "{{label}} deve essere compreso tra i caratteri {{min}} e {{max}} in lunghezza.", + "NO_LEAD_WS" => "Il valore di {{label}} non può iniziare con spazi, tabulazioni o altri spazi vuoti.", + "NO_TRAIL_WS" => "Il valore di {{label}} non può terminare con spazi, tabulazioni o altri spazi vuoti.", + "REQUIRED" => "Il campo {{label}} deve essere specificato.", + "SPRUNJE" => [ + "BAD_FILTER" => "{{name}} non è un filtro valido per questo Sprunje.", + "BAD_LIST" => " {{name}} non è un elenco valido per questo Sprunje.", + "BAD_SORT" => "{{name}} non è un campo di ordinamento valido per questo Sprunje." + ] + ] +]; diff --git a/main/app/sprinkles/core/locale/pt_PT/messages.php b/main/app/sprinkles/core/locale/pt_PT/messages.php index 8dec8aa..4a8c80a 100644 --- a/main/app/sprinkles/core/locale/pt_PT/messages.php +++ b/main/app/sprinkles/core/locale/pt_PT/messages.php @@ -1,102 +1,102 @@ - 1, - - "ABOUT" => "Acerca", - - "CAPTCHA" => [ - "@TRANSLATION" => "Captcha", - "FAIL" => "Código captcha não introduzido corretamente.", - "SPECIFY" => "Introduza o código captcha", - "VERIFY" => "Verifique o código captcha" - ], - - "CSRF_MISSING" => "Token CSRF em falta. Tente refrescar a página e submeter de novo?", - - "DB_INVALID" => "Não é possível estabelecer ligação com a base de dados. Se é administrador, por favor consulte o log do servidor.", - "DESCRIPTION" => "Descrição", - "DOWNLOAD" => [ - "@TRANSLATION" => "Descarregar", - "CSV" => "Descarregar CSV" - ], - - "EMAIL" => [ - "@TRANSLATION" => "Email", - "YOUR" => "O seu endereço de email" - ], - - "HOME" => "Início", - - "LEGAL" => "Política Legal", - - "LOCALE" => [ - "@TRANSLATION" => "Localização" - ], - - "NAME" => "Nome", - "NAVIGATION" => "Navegação", - - "PAGINATION" => [ - "GOTO" => "Saltar para Página", - "SHOW" => "Mostrar", - "OUTPUT" => "{startRow} to {endRow} of {filteredRows} ({totalRows})" - ], - "PRIVACY" => "Política de Privacidade", - - "SLUG" => "Slug", - "SLUG_CONDITION" => "Slug/Condições", - "STATUS" => "Estado", - - "UNKNOWN" => "Desconhecido", - - // Actions words - "ACTIONS" => "Ações", - "ACTIVATE" => "Ativar", - "ACTIVE" => "Ativo", - "ADD" => "Adicionar", - "CANCEL" => "Cancelar", - "CONFIRM" => "Confirmar", - "CREATE" => "Criar", - "DELETE" => "Remover", - "DELETE_CONFIRM" => "Tem a certeza que deseja remover isto?", - "DELETE_CONFIRM_YES" => "Sim, remover", - "DELETE_CONFIRM_NAMED" => "Tem a certeza que deseja remover {{name}}?", - "DELETE_CONFIRM_YES_NAMED" => "Sim, remover {{name}}", - "DELETE_CANNOT_UNDONE" => "Esta ação não pode ser desfeita.", - "DELETE_NAMED" => "Remover {{name}}", - "DENY" => "Recusar", - "DISABLE" => "Desativar", - "DISABLED" => "Inativo", - "EDIT" => "Editar", - "ENABLE" => "Ativar", - "ENABLED" => "Ativo", - "OVERRIDE" => "Alterar", - "RESET" => "Apagar", - "SAVE" => "Guardar", - "SEARCH" => "Procurar", - "SORT" => "Ordenar", - "SUBMIT" => "Submeter", - "PRINT" => "Imprimir", - "REMOVE" => "Remover", - "UNACTIVATED" => "Inativo", - "UPDATE" => "Atualizar", - "YES" => "Sim", - "NO" => "Não", - "OPTIONAL" => "Opcional", - - // Misc. - "BUILT_WITH_UF" => "Desenvolvido sobre UserFrosting", - "ADMINLTE_THEME_BY" => "Tema por Almsaeed Studio. Todos os direitos reservados" -]; + 1, + + "ABOUT" => "Acerca", + + "CAPTCHA" => [ + "@TRANSLATION" => "Captcha", + "FAIL" => "Código captcha não introduzido corretamente.", + "SPECIFY" => "Introduza o código captcha", + "VERIFY" => "Verifique o código captcha" + ], + + "CSRF_MISSING" => "Token CSRF em falta. Tente refrescar a página e submeter de novo?", + + "DB_INVALID" => "Não é possível estabelecer ligação com a base de dados. Se é administrador, por favor consulte o log do servidor.", + "DESCRIPTION" => "Descrição", + "DOWNLOAD" => [ + "@TRANSLATION" => "Descarregar", + "CSV" => "Descarregar CSV" + ], + + "EMAIL" => [ + "@TRANSLATION" => "Email", + "YOUR" => "O seu endereço de email" + ], + + "HOME" => "Início", + + "LEGAL" => "Política Legal", + + "LOCALE" => [ + "@TRANSLATION" => "Localização" + ], + + "NAME" => "Nome", + "NAVIGATION" => "Navegação", + + "PAGINATION" => [ + "GOTO" => "Saltar para Página", + "SHOW" => "Mostrar", + "OUTPUT" => "{startRow} to {endRow} of {filteredRows} ({totalRows})" + ], + "PRIVACY" => "Política de Privacidade", + + "SLUG" => "Slug", + "SLUG_CONDITION" => "Slug/Condições", + "STATUS" => "Estado", + + "UNKNOWN" => "Desconhecido", + + // Actions words + "ACTIONS" => "Ações", + "ACTIVATE" => "Ativar", + "ACTIVE" => "Ativo", + "ADD" => "Adicionar", + "CANCEL" => "Cancelar", + "CONFIRM" => "Confirmar", + "CREATE" => "Criar", + "DELETE" => "Remover", + "DELETE_CONFIRM" => "Tem a certeza que deseja remover isto?", + "DELETE_CONFIRM_YES" => "Sim, remover", + "DELETE_CONFIRM_NAMED" => "Tem a certeza que deseja remover {{name}}?", + "DELETE_CONFIRM_YES_NAMED" => "Sim, remover {{name}}", + "DELETE_CANNOT_UNDONE" => "Esta ação não pode ser desfeita.", + "DELETE_NAMED" => "Remover {{name}}", + "DENY" => "Recusar", + "DISABLE" => "Desativar", + "DISABLED" => "Inativo", + "EDIT" => "Editar", + "ENABLE" => "Ativar", + "ENABLED" => "Ativo", + "OVERRIDE" => "Alterar", + "RESET" => "Apagar", + "SAVE" => "Guardar", + "SEARCH" => "Procurar", + "SORT" => "Ordenar", + "SUBMIT" => "Submeter", + "PRINT" => "Imprimir", + "REMOVE" => "Remover", + "UNACTIVATED" => "Inativo", + "UPDATE" => "Atualizar", + "YES" => "Sim", + "NO" => "Não", + "OPTIONAL" => "Opcional", + + // Misc. + "BUILT_WITH_UF" => "Desenvolvido sobre UserFrosting", + "ADMINLTE_THEME_BY" => "Tema por Almsaeed Studio. Todos os direitos reservados" +]; diff --git a/main/app/sprinkles/core/locale/pt_PT/validate.php b/main/app/sprinkles/core/locale/pt_PT/validate.php index bc9647c..842f12b 100644 --- a/main/app/sprinkles/core/locale/pt_PT/validate.php +++ b/main/app/sprinkles/core/locale/pt_PT/validate.php @@ -1,25 +1,25 @@ - [ - "ARRAY" => "Os valores para {{label}} devem estar contidos num array.", - "BOOLEAN" => "O valor para {{label}} deve ser '0' ou '1'.", - "INTEGER" => "O valor para {{label}} deve ser um inteiro.", - "INVALID_EMAIL" => "Endereço de email inválido.", - "LENGTH_RANGE" => "{{label}} deve conter entre {{min}} e {{max}} caracteres.", - "NO_LEAD_WS" => "O valor para {{label}} não pode começar por espaços, tabulações, ou outros espaços em branco.", - "NO_TRAIL_WS" => "O valor para {{label}} não pode terminar em espaços, tabulações, ou outros espaços em branco.", - "REQUIRED" => "Por favor especifique um valor para {{label}}." - ] -]; + [ + "ARRAY" => "Os valores para {{label}} devem estar contidos num array.", + "BOOLEAN" => "O valor para {{label}} deve ser '0' ou '1'.", + "INTEGER" => "O valor para {{label}} deve ser um inteiro.", + "INVALID_EMAIL" => "Endereço de email inválido.", + "LENGTH_RANGE" => "{{label}} deve conter entre {{min}} e {{max}} caracteres.", + "NO_LEAD_WS" => "O valor para {{label}} não pode começar por espaços, tabulações, ou outros espaços em branco.", + "NO_TRAIL_WS" => "O valor para {{label}} não pode terminar em espaços, tabulações, ou outros espaços em branco.", + "REQUIRED" => "Por favor especifique um valor para {{label}}." + ] +]; diff --git a/main/app/sprinkles/core/locale/ru_RU/errors.php b/main/app/sprinkles/core/locale/ru_RU/errors.php index bbd0cb3..1a61e30 100644 --- a/main/app/sprinkles/core/locale/ru_RU/errors.php +++ b/main/app/sprinkles/core/locale/ru_RU/errors.php @@ -1,51 +1,51 @@ - [ - "@TRANSLATION" => "Ошибка", - - "400" => [ - "TITLE" => "Ошибка 400: Неправильный запрос", - "DESCRIPTION" => "Это, вероятно, не ваша вина.", - ], - - "404" => [ - "TITLE" => "Ошибка 404: Не найдено", - "DESCRIPTION" => "Кажется, мы не можем найти то, что вам нужно.", - "DETAIL" => "Мы пытались найти вашу страницу...", - "EXPLAIN" => "Мы не можем найти страницу, которую вы искали.", - "RETURN" => 'В любом случае, нажмите здесь чтобы вернуться на главную страницу.' - ], - - "CONFIG" => [ - "TITLE" => "Проблема в конфигурации!", - "DESCRIPTION" => "Некоторые требования к конфигурации UserFrosting, не были соблюдены.", - "DETAIL" => "Что-то здесь не так.", - "RETURN" => 'Пожалуйста, исправьте следующие ошибки, затем перезагрузите.' - ], - - "DESCRIPTION" => "Мы обнаружили большое и сильное нарушение.", - "DETAIL" => "Вот что мы получили:", - - "ENCOUNTERED" => "Ох... что-то произошло. Мы не знаем, что.", - - "MAIL" => "Неустранимая ошибка почтовой службы, обратитесь к администратору сервера. Если вы являетесь администратором, пожалуйста, проверьте логи.", - - "RETURN" => 'Нажмите здесь для возврата на главную страницу.', - - "SERVER" => "К сожалению, кажется сервер имеет ошибки. Если вы являетесь администратором сервера, пожалуйста проверьте логи.", - - "TITLE" => "Сильное нарушение" - ] -]; + [ + "@TRANSLATION" => "Ошибка", + + "400" => [ + "TITLE" => "Ошибка 400: Неправильный запрос", + "DESCRIPTION" => "Это, вероятно, не ваша вина.", + ], + + "404" => [ + "TITLE" => "Ошибка 404: Не найдено", + "DESCRIPTION" => "Кажется, мы не можем найти то, что вам нужно.", + "DETAIL" => "Мы пытались найти вашу страницу...", + "EXPLAIN" => "Мы не можем найти страницу, которую вы искали.", + "RETURN" => 'В любом случае, нажмите здесь чтобы вернуться на главную страницу.' + ], + + "CONFIG" => [ + "TITLE" => "Проблема в конфигурации!", + "DESCRIPTION" => "Некоторые требования к конфигурации UserFrosting, не были соблюдены.", + "DETAIL" => "Что-то здесь не так.", + "RETURN" => 'Пожалуйста, исправьте следующие ошибки, затем перезагрузите.' + ], + + "DESCRIPTION" => "Мы обнаружили большое и сильное нарушение.", + "DETAIL" => "Вот что мы получили:", + + "ENCOUNTERED" => "Ох... что-то произошло. Мы не знаем, что.", + + "MAIL" => "Неустранимая ошибка почтовой службы, обратитесь к администратору сервера. Если вы являетесь администратором, пожалуйста, проверьте логи.", + + "RETURN" => 'Нажмите здесь для возврата на главную страницу.', + + "SERVER" => "К сожалению, кажется сервер имеет ошибки. Если вы являетесь администратором сервера, пожалуйста проверьте логи.", + + "TITLE" => "Сильное нарушение" + ] +]; diff --git a/main/app/sprinkles/core/locale/ru_RU/messages.php b/main/app/sprinkles/core/locale/ru_RU/messages.php index 4b11b51..ddd53a7 100644 --- a/main/app/sprinkles/core/locale/ru_RU/messages.php +++ b/main/app/sprinkles/core/locale/ru_RU/messages.php @@ -1,120 +1,120 @@ - 1, - - "ABOUT" => "О нас", - - "CAPTCHA" => [ - "@TRANSLATION" => "Капча", - "FAIL" => "Код безопасности был введен с ошибками.", - "SPECIFY" => "Введите код капчи", - "VERIFY" => "Проверьте капчу" - ], - - "CSRF_MISSING" => "Отсутствует CSRF токен. Попробуйте обновить страницу и повторить попытку ещё раз?", - - "DB_INVALID" => "Не удается подключиться к базе данных. Если вы являетесь администратором, пожалуйста проверьте лог ошибок.", - "DESCRIPTION" => "Описание", - "DOWNLOAD" => [ - "@TRANSLATION" => "Скачать", - "CSV" => "Скачать CSV" - ], - - "EMAIL" => [ - "@TRANSLATION" => "Email", - "YOUR" => "Ваш e-mail" - ], - - "HOME" => "Главная", - - "LEGAL" => [ - "@TRANSLATION" => "Правовая информация", - "DESCRIPTION" => "Наша правовая политика применима к использованию вами данного веб-сайта и наших услуг." - ], - - "LOCALE" => [ - "@TRANSLATION" => "Язык" - ], - - "NAME" => "Имя", - "NAVIGATION" => "Навигация", - "NO_RESULTS" => "Извини, здесь ничего нет.", - - "PAGINATION" => [ - "GOTO" => "Перейти к странице", - "SHOW" => "Показать", - - // Paginator - // possible variables: {size}, {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} - // also {page:input} & {startRow:input} will add a modifiable input in place of the value - "OUTPUT" => "{startRow} к {endRow} из {filteredRows} ({totalRows})", - "NEXT" => "Следующая", - "PREVIOUS" => "Предыдущая", - "FIRST" => "Первая", - "LAST" => "Последняя" - ], - "PRIVACY" => [ - "@TRANSLATION" => "Политика конфиденциальности", - "DESCRIPTION" => "Наша политика конфиденциальности описывает, какую информацию мы собираем от вас и как мы будем использовать её." - ], - - "SLUG" => "Метка", - "SLUG_CONDITION" => "Метка/Условия", - "SLUG_IN_USE" => "{{slug}} метка уже существует", - "STATUS" => "Статус", - "SUGGEST" => "Предложить", - - "UNKNOWN" => "Неизвестно", - - // Actions words - "ACTIONS" => "Действия", - "ACTIVATE" => "Активировать", - "ACTIVE" => "Активные", - "ADD" => "Добавить", - "CANCEL" => "Отмена", - "CONFIRM" => "Подтвердить", - "CREATE" => "Создать", - "DELETE" => "Удалить", - "DELETE_CONFIRM" => "Вы уверены, что хотите удалить это?", - "DELETE_CONFIRM_YES" => "Да, удалить", - "DELETE_CONFIRM_NAMED" => "Вы уверены, что хотите удалить {{name}}?", - "DELETE_CONFIRM_YES_NAMED" => "Да, удалить {{name}}", - "DELETE_CANNOT_UNDONE" => "Это действие нельзя будет отменить.", - "DELETE_NAMED" => "Удаление {{name}}", - "DENY" => "Запретить", - "DISABLE" => "Отключить", - "DISABLED" => "Отключено", - "EDIT" => "Изменить", - "ENABLE" => "Включить", - "ENABLED" => "Включено", - "OVERRIDE" => "Отменить", - "RESET" => "Сброс", - "SAVE" => "Сохранить", - "SEARCH" => "Поиск", - "SORT" => "Сортировка", - "SUBMIT" => "Отправить", - "PRINT" => "Печать", - "REMOVE" => "Удалить", - "UNACTIVATED" => "Не активировано", - "UPDATE" => "Обновить", - "YES" => "Да", - "NO" => "Нет", - "OPTIONAL" => "Дополнительно", - - // Misc. - "BUILT_WITH_UF" => "Создано через UserFrosting", - "ADMINLTE_THEME_BY" => "Тема от Almsaeed Studio. Все права защищены", - "WELCOME_TO" => "Добро пожаловать на {{title}}!" -]; + 1, + + "ABOUT" => "О нас", + + "CAPTCHA" => [ + "@TRANSLATION" => "Капча", + "FAIL" => "Код безопасности был введен с ошибками.", + "SPECIFY" => "Введите код капчи", + "VERIFY" => "Проверьте капчу" + ], + + "CSRF_MISSING" => "Отсутствует CSRF токен. Попробуйте обновить страницу и повторить попытку ещё раз?", + + "DB_INVALID" => "Не удается подключиться к базе данных. Если вы являетесь администратором, пожалуйста проверьте лог ошибок.", + "DESCRIPTION" => "Описание", + "DOWNLOAD" => [ + "@TRANSLATION" => "Скачать", + "CSV" => "Скачать CSV" + ], + + "EMAIL" => [ + "@TRANSLATION" => "Email", + "YOUR" => "Ваш e-mail" + ], + + "HOME" => "Главная", + + "LEGAL" => [ + "@TRANSLATION" => "Правовая информация", + "DESCRIPTION" => "Наша правовая политика применима к использованию вами данного веб-сайта и наших услуг." + ], + + "LOCALE" => [ + "@TRANSLATION" => "Язык" + ], + + "NAME" => "Имя", + "NAVIGATION" => "Навигация", + "NO_RESULTS" => "Извини, здесь ничего нет.", + + "PAGINATION" => [ + "GOTO" => "Перейти к странице", + "SHOW" => "Показать", + + // Paginator + // possible variables: {size}, {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} + // also {page:input} & {startRow:input} will add a modifiable input in place of the value + "OUTPUT" => "{startRow} к {endRow} из {filteredRows} ({totalRows})", + "NEXT" => "Следующая", + "PREVIOUS" => "Предыдущая", + "FIRST" => "Первая", + "LAST" => "Последняя" + ], + "PRIVACY" => [ + "@TRANSLATION" => "Политика конфиденциальности", + "DESCRIPTION" => "Наша политика конфиденциальности описывает, какую информацию мы собираем от вас и как мы будем использовать её." + ], + + "SLUG" => "Метка", + "SLUG_CONDITION" => "Метка/Условия", + "SLUG_IN_USE" => "{{slug}} метка уже существует", + "STATUS" => "Статус", + "SUGGEST" => "Предложить", + + "UNKNOWN" => "Неизвестно", + + // Actions words + "ACTIONS" => "Действия", + "ACTIVATE" => "Активировать", + "ACTIVE" => "Активные", + "ADD" => "Добавить", + "CANCEL" => "Отмена", + "CONFIRM" => "Подтвердить", + "CREATE" => "Создать", + "DELETE" => "Удалить", + "DELETE_CONFIRM" => "Вы уверены, что хотите удалить это?", + "DELETE_CONFIRM_YES" => "Да, удалить", + "DELETE_CONFIRM_NAMED" => "Вы уверены, что хотите удалить {{name}}?", + "DELETE_CONFIRM_YES_NAMED" => "Да, удалить {{name}}", + "DELETE_CANNOT_UNDONE" => "Это действие нельзя будет отменить.", + "DELETE_NAMED" => "Удаление {{name}}", + "DENY" => "Запретить", + "DISABLE" => "Отключить", + "DISABLED" => "Отключено", + "EDIT" => "Изменить", + "ENABLE" => "Включить", + "ENABLED" => "Включено", + "OVERRIDE" => "Отменить", + "RESET" => "Сброс", + "SAVE" => "Сохранить", + "SEARCH" => "Поиск", + "SORT" => "Сортировка", + "SUBMIT" => "Отправить", + "PRINT" => "Печать", + "REMOVE" => "Удалить", + "UNACTIVATED" => "Не активировано", + "UPDATE" => "Обновить", + "YES" => "Да", + "NO" => "Нет", + "OPTIONAL" => "Дополнительно", + + // Misc. + "BUILT_WITH_UF" => "Создано через UserFrosting", + "ADMINLTE_THEME_BY" => "Тема от Almsaeed Studio. Все права защищены", + "WELCOME_TO" => "Добро пожаловать на {{title}}!" +]; diff --git a/main/app/sprinkles/core/locale/ru_RU/validate.php b/main/app/sprinkles/core/locale/ru_RU/validate.php index e705fa4..a269b00 100644 --- a/main/app/sprinkles/core/locale/ru_RU/validate.php +++ b/main/app/sprinkles/core/locale/ru_RU/validate.php @@ -1,33 +1,33 @@ - [ - "ARRAY" => "Значения для {{label}} должны быть элементами массива.", - "BOOLEAN" => "Значение {{label}} должно быть '0' или '1'.", - "INTEGER" => "Значение {{label}} должно быть целым.", - "INVALID_EMAIL" => "Неправильный email.", - "LENGTH_RANGE" => "{{label}} должно быть между {{min}} и {{max}} символов в длину.", - "MAX_LENGTH" => "{{label}} должны быть максимально {{max}} символов в длину.", - "MIN_LENGTH" => "{{label}} должно быть минимально {{min}} символов в длину.", - "NO_LEAD_WS" => "Значение {{label}} не может начинаться с пробелов, табуляции или других пробелов.", - "NO_TRAIL_WS" => "Значение {{label}} не может заканчиваться пробелами, табуляции или другими пробелами.", - "RANGE" => "Значение {{label}} должно быть между {{min}} и {{max}} симв.", - "REQUIRED" => "Пожалуйста, укажите значение для {{label}}.", - "SPRUNJE" => [ - "BAD_FILTER" => "{{name}} не является допустимым фильтром.", - "BAD_LIST" => "{{name}} не является допустимым списком.", - "BAD_SORT" => "{{name}} не является допустимым для сортировки полей." - ] - ] -]; + [ + "ARRAY" => "Значения для {{label}} должны быть элементами массива.", + "BOOLEAN" => "Значение {{label}} должно быть '0' или '1'.", + "INTEGER" => "Значение {{label}} должно быть целым.", + "INVALID_EMAIL" => "Неправильный email.", + "LENGTH_RANGE" => "{{label}} должно быть между {{min}} и {{max}} символов в длину.", + "MAX_LENGTH" => "{{label}} должны быть максимально {{max}} символов в длину.", + "MIN_LENGTH" => "{{label}} должно быть минимально {{min}} символов в длину.", + "NO_LEAD_WS" => "Значение {{label}} не может начинаться с пробелов, табуляции или других пробелов.", + "NO_TRAIL_WS" => "Значение {{label}} не может заканчиваться пробелами, табуляции или другими пробелами.", + "RANGE" => "Значение {{label}} должно быть между {{min}} и {{max}} симв.", + "REQUIRED" => "Пожалуйста, укажите значение для {{label}}.", + "SPRUNJE" => [ + "BAD_FILTER" => "{{name}} не является допустимым фильтром.", + "BAD_LIST" => "{{name}} не является допустимым списком.", + "BAD_SORT" => "{{name}} не является допустимым для сортировки полей." + ] + ] +]; diff --git a/main/app/sprinkles/core/locale/th_TH/errors.php b/main/app/sprinkles/core/locale/th_TH/errors.php index 7b3d41d..8f9413e 100644 --- a/main/app/sprinkles/core/locale/th_TH/errors.php +++ b/main/app/sprinkles/core/locale/th_TH/errors.php @@ -1,51 +1,51 @@ - [ - "@TRANSLATION" => "ข้อผิดพลาด", - - "400" => [ - "TITLE" => "ข้อผิดพลาด 400: การร้องขอไม่ถูกต้อง", - "DESCRIPTION" => "นี่ไม่น่าจะเป็นความผิดพลาดของคุณ", - ], - - "404" => [ - "TITLE" => "ข้อผิดพลาด 404: ไม่พบหน้านี้", - "DESCRIPTION" => "ดูเหมือนเราจะไม่สามารถหาสิ่งที่คุณต้องการได้", - "DETAIL" => "เราพยายามได้ที่จะหาหน้าของคุณ...", - "EXPLAIN" => "เราไม่สามารถหาหน้าที่คุณมองหาอยู่ได้", - "RETURN" => 'อย่างไรก็ตาม คลิก ที่นี่ เพื่อกลับไปยังหน้าแรก' - ], - - "CONFIG" => [ - "TITLE" => "เกิดปัญหาจากการตั้งค่า UserFrosting!", - "DESCRIPTION" => "การตั้งค่าบางอย่างของ UserFrosting ยังไม่ตรงตามความต้องการ", - "DETAIL" => "มีบางอย่างไม่ถูกต้องอยู่", - "RETURN" => 'กรุณาแก้ไขข้อผิดพลาดดังกล่าว จากนั้น โหลดหน้านี้อีกครั้ง' - ], - - "DESCRIPTION" => "เรารู้สึกความโกลาหลในกองทัพได้เป็นอย่างดี", - "DETAIL" => "นี่คือสิ่งที่เราพบ:", - - "ENCOUNTERED" => "อืมม...บางอย่างเกิดขึ้น แต่เราไม่รู้ว่าคืออะไร", - - "MAIL" => "เกิดข้อผิดพลาดร้ายแรงระหว่างการพยายามส่งอีเมล กรุณาติดต่อผู้ดูแลระบบของเซิฟเวอร์นี้ หากคุณเป็นผู้ดูแล กรุณาตรวจสอบบันทึกอีเมลของ UF", - - "RETURN" => 'คลิก ที่นี่ เพื่อกลับไปยังหน้าแรก', - - "SERVER" => "โอ้ว ดูเหมือนระบบของเราอาจจะผิดพลาดเอง หากคุณเป็นผู้ดูแล กรุณาตรวจสอบบันทึกข้อผิดพลาดของ PHP หรือ UF", - - "TITLE" => "เกิดความโกลาหลในกองทัพ" - ] -]; + [ + "@TRANSLATION" => "ข้อผิดพลาด", + + "400" => [ + "TITLE" => "ข้อผิดพลาด 400: การร้องขอไม่ถูกต้อง", + "DESCRIPTION" => "นี่ไม่น่าจะเป็นความผิดพลาดของคุณ", + ], + + "404" => [ + "TITLE" => "ข้อผิดพลาด 404: ไม่พบหน้านี้", + "DESCRIPTION" => "ดูเหมือนเราจะไม่สามารถหาสิ่งที่คุณต้องการได้", + "DETAIL" => "เราพยายามได้ที่จะหาหน้าของคุณ...", + "EXPLAIN" => "เราไม่สามารถหาหน้าที่คุณมองหาอยู่ได้", + "RETURN" => 'อย่างไรก็ตาม คลิก ที่นี่ เพื่อกลับไปยังหน้าแรก' + ], + + "CONFIG" => [ + "TITLE" => "เกิดปัญหาจากการตั้งค่า UserFrosting!", + "DESCRIPTION" => "การตั้งค่าบางอย่างของ UserFrosting ยังไม่ตรงตามความต้องการ", + "DETAIL" => "มีบางอย่างไม่ถูกต้องอยู่", + "RETURN" => 'กรุณาแก้ไขข้อผิดพลาดดังกล่าว จากนั้น โหลดหน้านี้อีกครั้ง' + ], + + "DESCRIPTION" => "เรารู้สึกความโกลาหลในกองทัพได้เป็นอย่างดี", + "DETAIL" => "นี่คือสิ่งที่เราพบ:", + + "ENCOUNTERED" => "อืมม...บางอย่างเกิดขึ้น แต่เราไม่รู้ว่าคืออะไร", + + "MAIL" => "เกิดข้อผิดพลาดร้ายแรงระหว่างการพยายามส่งอีเมล กรุณาติดต่อผู้ดูแลระบบของเซิฟเวอร์นี้ หากคุณเป็นผู้ดูแล กรุณาตรวจสอบบันทึกอีเมลของ UF", + + "RETURN" => 'คลิก ที่นี่ เพื่อกลับไปยังหน้าแรก', + + "SERVER" => "โอ้ว ดูเหมือนระบบของเราอาจจะผิดพลาดเอง หากคุณเป็นผู้ดูแล กรุณาตรวจสอบบันทึกข้อผิดพลาดของ PHP หรือ UF", + + "TITLE" => "เกิดความโกลาหลในกองทัพ" + ] +]; diff --git a/main/app/sprinkles/core/locale/th_TH/messages.php b/main/app/sprinkles/core/locale/th_TH/messages.php index d9bdbc7..34e609d 100644 --- a/main/app/sprinkles/core/locale/th_TH/messages.php +++ b/main/app/sprinkles/core/locale/th_TH/messages.php @@ -1,102 +1,102 @@ - 1, - - "ABOUT" => "เกี่ยวกับ", - - "CAPTCHA" => [ - "@TRANSLATION" => "รหัสยืนยัน", - "FAIL" => "คุณยังกรอกรหัสยืนยันไม่ถูกต้อง", - "SPECIFY" => "กรอกรหัสยืนยัน", - "VERIFY" => "ตรวจสอบรหัสยืนยัน" - ], - - "CSRF_MISSING" => "ไม่พบโทเคน CSRF กรุณารีเฟรชแล้วส่งข้อมูลใหม่", - - "DB_INVALID" => "ไม่สามารถเชื่อมต่อกับฐานข้อมูลได้ หากคุณเป็นผู้ดูแลระบบ กรุณาตรวจสอบบันทึกข้อผิดพลาด", - "DESCRIPTION" => "รายละเอียด", - "DOWNLOAD" => [ - "@TRANSLATION" => "ดาวน์โหลด", - "CSV" => "ดาวน์โหลด CSV" - ], - - "EMAIL" => [ - "@TRANSLATION" => "อีเมล", - "YOUR" => "ที่อยู่อีเมลของคุณ" - ], - - "HOME" => "หน้าแรก", - - "LEGAL" => "นโยบายทางกฎหมาย", - - "LOCALE" => [ - "@TRANSLATION" => "ภาษา" - ], - - "NAME" => "ชื่อ", - "NAVIGATION" => "เมนูนำทาง", - - "PAGINATION" => [ - "GOTO" => "ข้ามไปยังหน้า", - "SHOW" => "แสดง", - "OUTPUT" => "{startRow} to {endRow} of {filteredRows} ({totalRows})" - ], - "PRIVACY" => "นโยบายความเป็นส่วนตัว", - - "SLUG" => "ข้อกำหนด", - "SLUG_CONDITION" => "ข้อกำหนด/เงื่อนไข", - "STATUS" => "สถานะ", - - "UNKNOWN" => "ไม่ทราบ", - - // Actions words - "ACTIONS" => "การดำเนินการ", - "ACTIVATE" => "เปิดใช้งาน", - "ACTIVE" => "เปิดใช้งานอยู่", - "ADD" => "เพิ่ม", - "CANCEL" => "ยกเลิก", - "CONFIRM" => "ยืนยัน", - "CREATE" => "สร้าง", - "DELETE" => "ลบ", - "DELETE_CONFIRM" => "คุณต้องการที่จะลบใช่หรือไม่?", - "DELETE_CONFIRM_YES" => "ใช่ ลบเลย", - "DELETE_CONFIRM_NAMED" => "คุณต้องการที่จะลบ {{name}} ใช่หรือไม่?", - "DELETE_CONFIRM_YES_NAMED" => "ใช่ ลบ {{name}} เลย", - "DELETE_CANNOT_UNDONE" => "การดำเนินการนี้ไม่สามารถยกเลิกได้", - "DELETE_NAMED" => "ลบ {{name}}", - "DENY" => "ปฏิเสธ", - "DISABLE" => "ปิดการใช้งาน", - "DISABLED" => "ปิดการใช้งานอยู่", - "EDIT" => "แก้ไข", - "ENABLE" => "เปิด", - "ENABLED" => "เปิดอยู่", - "OVERRIDE" => "เขียนทับ", - "RESET" => "รีเซ็ต", - "SAVE" => "บันทึก", - "SEARCH" => "ค้นหา", - "SORT" => "ประเภท", - "SUBMIT" => "ส่ง", - "PRINT" => "พิมพ์", - "REMOVE" => "เอาออก", - "UNACTIVATED" => "ไม่มีการเปิดใช้", - "UPDATE" => "ปรับปรุง", - "YES" => "ใช่", - "NO" => "ไม่", - "OPTIONAL" => "ตัวเลือกเพิ่มเติม", - - // Misc. - "BUILT_WITH_UF" => "สร้างด้วย UserFrosting", - "ADMINLTE_THEME_BY" => "ธีมโดย Almsaeed Studio สงวนลิขสิทธิ์" -]; + 1, + + "ABOUT" => "เกี่ยวกับ", + + "CAPTCHA" => [ + "@TRANSLATION" => "รหัสยืนยัน", + "FAIL" => "คุณยังกรอกรหัสยืนยันไม่ถูกต้อง", + "SPECIFY" => "กรอกรหัสยืนยัน", + "VERIFY" => "ตรวจสอบรหัสยืนยัน" + ], + + "CSRF_MISSING" => "ไม่พบโทเคน CSRF กรุณารีเฟรชแล้วส่งข้อมูลใหม่", + + "DB_INVALID" => "ไม่สามารถเชื่อมต่อกับฐานข้อมูลได้ หากคุณเป็นผู้ดูแลระบบ กรุณาตรวจสอบบันทึกข้อผิดพลาด", + "DESCRIPTION" => "รายละเอียด", + "DOWNLOAD" => [ + "@TRANSLATION" => "ดาวน์โหลด", + "CSV" => "ดาวน์โหลด CSV" + ], + + "EMAIL" => [ + "@TRANSLATION" => "อีเมล", + "YOUR" => "ที่อยู่อีเมลของคุณ" + ], + + "HOME" => "หน้าแรก", + + "LEGAL" => "นโยบายทางกฎหมาย", + + "LOCALE" => [ + "@TRANSLATION" => "ภาษา" + ], + + "NAME" => "ชื่อ", + "NAVIGATION" => "เมนูนำทาง", + + "PAGINATION" => [ + "GOTO" => "ข้ามไปยังหน้า", + "SHOW" => "แสดง", + "OUTPUT" => "{startRow} to {endRow} of {filteredRows} ({totalRows})" + ], + "PRIVACY" => "นโยบายความเป็นส่วนตัว", + + "SLUG" => "ข้อกำหนด", + "SLUG_CONDITION" => "ข้อกำหนด/เงื่อนไข", + "STATUS" => "สถานะ", + + "UNKNOWN" => "ไม่ทราบ", + + // Actions words + "ACTIONS" => "การดำเนินการ", + "ACTIVATE" => "เปิดใช้งาน", + "ACTIVE" => "เปิดใช้งานอยู่", + "ADD" => "เพิ่ม", + "CANCEL" => "ยกเลิก", + "CONFIRM" => "ยืนยัน", + "CREATE" => "สร้าง", + "DELETE" => "ลบ", + "DELETE_CONFIRM" => "คุณต้องการที่จะลบใช่หรือไม่?", + "DELETE_CONFIRM_YES" => "ใช่ ลบเลย", + "DELETE_CONFIRM_NAMED" => "คุณต้องการที่จะลบ {{name}} ใช่หรือไม่?", + "DELETE_CONFIRM_YES_NAMED" => "ใช่ ลบ {{name}} เลย", + "DELETE_CANNOT_UNDONE" => "การดำเนินการนี้ไม่สามารถยกเลิกได้", + "DELETE_NAMED" => "ลบ {{name}}", + "DENY" => "ปฏิเสธ", + "DISABLE" => "ปิดการใช้งาน", + "DISABLED" => "ปิดการใช้งานอยู่", + "EDIT" => "แก้ไข", + "ENABLE" => "เปิด", + "ENABLED" => "เปิดอยู่", + "OVERRIDE" => "เขียนทับ", + "RESET" => "รีเซ็ต", + "SAVE" => "บันทึก", + "SEARCH" => "ค้นหา", + "SORT" => "ประเภท", + "SUBMIT" => "ส่ง", + "PRINT" => "พิมพ์", + "REMOVE" => "เอาออก", + "UNACTIVATED" => "ไม่มีการเปิดใช้", + "UPDATE" => "ปรับปรุง", + "YES" => "ใช่", + "NO" => "ไม่", + "OPTIONAL" => "ตัวเลือกเพิ่มเติม", + + // Misc. + "BUILT_WITH_UF" => "สร้างด้วย UserFrosting", + "ADMINLTE_THEME_BY" => "ธีมโดย Almsaeed Studio สงวนลิขสิทธิ์" +]; diff --git a/main/app/sprinkles/core/locale/th_TH/validate.php b/main/app/sprinkles/core/locale/th_TH/validate.php index 6d141aa..8e14af4 100644 --- a/main/app/sprinkles/core/locale/th_TH/validate.php +++ b/main/app/sprinkles/core/locale/th_TH/validate.php @@ -1,25 +1,25 @@ - [ - "ARRAY" => "ค่าของ {{label}} จะต้องเป็น Array", - "BOOLEAN" => "ค่าของ {{label}} จะต้องเป็น '0' หรือ '1'", - "INTEGER" => "ค่าของ {{label}} จะต้องเป็นตัวเลข", - "INVALID_EMAIL" => "ที่อยู่อีเมลไม่ถูกต้อง", - "LENGTH_RANGE" => "ความยาวของ {{label}} จะต้องอยู่ระหว่าง {{min}} ถึง {{max}} ตัวอักษร", - "NO_LEAD_WS" => "ค่าของ {{label}} ไม่สามารถเริ่มต้นด้วยช่องว่าง หรือ แท็บ", - "NO_TRAIL_WS" => "ค่าของ {{label}} ไม่สามารถลงท้ายด้วยช่องว่าง หรือ แท็บ", - "REQUIRED" => "กรุณากำหนดค่าของ {{label}}" - ] -]; + [ + "ARRAY" => "ค่าของ {{label}} จะต้องเป็น Array", + "BOOLEAN" => "ค่าของ {{label}} จะต้องเป็น '0' หรือ '1'", + "INTEGER" => "ค่าของ {{label}} จะต้องเป็นตัวเลข", + "INVALID_EMAIL" => "ที่อยู่อีเมลไม่ถูกต้อง", + "LENGTH_RANGE" => "ความยาวของ {{label}} จะต้องอยู่ระหว่าง {{min}} ถึง {{max}} ตัวอักษร", + "NO_LEAD_WS" => "ค่าของ {{label}} ไม่สามารถเริ่มต้นด้วยช่องว่าง หรือ แท็บ", + "NO_TRAIL_WS" => "ค่าของ {{label}} ไม่สามารถลงท้ายด้วยช่องว่าง หรือ แท็บ", + "REQUIRED" => "กรุณากำหนดค่าของ {{label}}" + ] +]; diff --git a/main/app/sprinkles/core/locale/tlh/errors.php b/main/app/sprinkles/core/locale/tlh/errors.php index 49e3ed5..4246b17 100644 --- a/main/app/sprinkles/core/locale/tlh/errors.php +++ b/main/app/sprinkles/core/locale/tlh/errors.php @@ -1,53 +1,53 @@ - [ - "@TRANSLATION" => "Fehler", - - "400" => [ - "TITLE" => "Fehler 400: Ungültige Anforderung", - "DESCRIPTION" => "Die Anfrage-Nachricht war fehlerhaft aufgebaut.", - ], - - "404" => [ - "TITLE" => "Fehler 404: Seite nicht gefunden", - "DESCRIPTION" => "Die angeforderte Ressource wurde nicht gefunden.", - "DETAIL" => "Wir haben versucht Ihre Seite zu finden ...", - "EXPLAIN" => "Die von Ihnen gesuchte Seite konnte nicht gefunden werden.", - "RETURN" => "Klicken Sie Hier, um zur Startseite zurückzukehren." - ], - - "CONFIG" => [ - "TITLE" => "UserFrosting Konfigurationsproblem!", - "DESCRIPTION" => "Einige UserFrosting-Konfigurationsanforderungen wurden nicht erfüllt.", - "DETAIL" => "Etwas stimmt hier nicht.", - "RETURN" => "Bitte beheben Sie die folgenden Fehler dann laden Sie die Website neu." - ], - - "DESCRIPTION" => "Wir haben eine große Störung in der Macht erkannt.", - "DETAIL" => "Hier haben wir:", - - "ENCOUNTERED" => "Uhhh ... etwas ist passiert. Wir wissen nicht was.", - - "MAIL" => "Schwerwiegender Fehler beim Mailversand, wenden Sie sich an Ihren Serveradministrator. Wenn Sie der Administrator sind, überprüfen Sie bitte das UF-Mail-Protokoll.", - - "RETURN" => "Klicken Sie Hier, um zur Startseite zurückzukehren.", - - "SERVER" => "Hoppla, sieht aus als hätte der Server möglicherweise gepatzt. Wenn Sie ein Administrator sind, überprüfen Sie bitte die PHP- oder UF-Fehlerprotokolle.", - - "TITLE" => "Störung in der Kraft" - ] -]; + [ + "@TRANSLATION" => "Fehler", + + "400" => [ + "TITLE" => "Fehler 400: Ungültige Anforderung", + "DESCRIPTION" => "Die Anfrage-Nachricht war fehlerhaft aufgebaut.", + ], + + "404" => [ + "TITLE" => "Fehler 404: Seite nicht gefunden", + "DESCRIPTION" => "Die angeforderte Ressource wurde nicht gefunden.", + "DETAIL" => "Wir haben versucht Ihre Seite zu finden ...", + "EXPLAIN" => "Die von Ihnen gesuchte Seite konnte nicht gefunden werden.", + "RETURN" => "Klicken Sie Hier, um zur Startseite zurückzukehren." + ], + + "CONFIG" => [ + "TITLE" => "UserFrosting Konfigurationsproblem!", + "DESCRIPTION" => "Einige UserFrosting-Konfigurationsanforderungen wurden nicht erfüllt.", + "DETAIL" => "Etwas stimmt hier nicht.", + "RETURN" => "Bitte beheben Sie die folgenden Fehler dann laden Sie die Website neu." + ], + + "DESCRIPTION" => "Wir haben eine große Störung in der Macht erkannt.", + "DETAIL" => "Hier haben wir:", + + "ENCOUNTERED" => "Uhhh ... etwas ist passiert. Wir wissen nicht was.", + + "MAIL" => "Schwerwiegender Fehler beim Mailversand, wenden Sie sich an Ihren Serveradministrator. Wenn Sie der Administrator sind, überprüfen Sie bitte das UF-Mail-Protokoll.", + + "RETURN" => "Klicken Sie Hier, um zur Startseite zurückzukehren.", + + "SERVER" => "Hoppla, sieht aus als hätte der Server möglicherweise gepatzt. Wenn Sie ein Administrator sind, überprüfen Sie bitte die PHP- oder UF-Fehlerprotokolle.", + + "TITLE" => "Störung in der Kraft" + ] +]; diff --git a/main/app/sprinkles/core/locale/tlh/main.php b/main/app/sprinkles/core/locale/tlh/main.php index 8905b60..8b91dc7 100644 --- a/main/app/sprinkles/core/locale/tlh/main.php +++ b/main/app/sprinkles/core/locale/tlh/main.php @@ -1,21 +1,21 @@ - [ - "FEED" => "De'", - "EXPLORE" => "Tu'", - "CHAT" => "Jaw", - "FRIENDS" => "Jup", - "PERSONAL" => "Ghot" - ], - "CHAT_MESSAGES" => [ - "USER_GROUP_JOIN" => "Ghom muv {{user}}", - "YOU_GROUP_JOIN" => "Ghom {{group}} muv SoH", - "USER_DISCONNECT" => "{{user}} chev vo' jabwI'", - "JOIN_GROUP_PH" => "Ghom muv...", - "WRITE_MESSAGE_PH" => "QIn ghItlh...", - ], - "EXPLORE_TAB" => [ - "USER_SEARCH_PH" => "jupDaj vItu'..." - ] + [ + "FEED" => "De'", + "EXPLORE" => "Tu'", + "CHAT" => "Jaw", + "FRIENDS" => "Jup", + "PERSONAL" => "Ghot" + ], + "CHAT_MESSAGES" => [ + "USER_GROUP_JOIN" => "Ghom muv {{user}}", + "YOU_GROUP_JOIN" => "Ghom {{group}} muv SoH", + "USER_DISCONNECT" => "{{user}} chev vo' jabwI'", + "JOIN_GROUP_PH" => "Ghom muv...", + "WRITE_MESSAGE_PH" => "QIn ghItlh...", + ], + "EXPLORE_TAB" => [ + "USER_SEARCH_PH" => "jupDaj vItu'..." + ] ]; \ No newline at end of file diff --git a/main/app/sprinkles/core/locale/tlh/validate.php b/main/app/sprinkles/core/locale/tlh/validate.php index a1d0c75..6659863 100644 --- a/main/app/sprinkles/core/locale/tlh/validate.php +++ b/main/app/sprinkles/core/locale/tlh/validate.php @@ -1,32 +1,32 @@ - [ - "ARRAY" => "Die Werte für {{label}} müssen in einem Feld liegen.", - "BOOLEAN" => "Der Wert für {{label}} muss entweder '0' oder '1' sein.", - "INTEGER" => "Der Wert für {{label}} muss eine ganze Zahl sein.", - "INVALID_EMAIL" => "Ungültige E-Mail-Adresse.", - "LENGTH_RANGE" => "{{label}} muss zwischen {{min}} und {{max}} Zeichen lang sein.", - "NO_LEAD_WS" => "Der Wert für {{label}} kann nicht mit Leerzeichen, Tabulatoren oder anderen Leerzeichen beginnen.", - "NO_TRAIL_WS" => "Der Wert für {{label}} kann nicht mit Leerzeichen, Tabulatoren oder anderen Leerzeichen enden.", - "REQUIRED" => "Bitte geben Sie einen Wert für {{label}} an.", - "SPRUNJE" => [ - "BAD_FILTER" => "{{name}} ist kein gültiger Filter für dieses Sprunje.", - "BAD_LIST" => "{{name}} ist kein gültige Liste für dieses Sprunje.", - "BAD_SORT" => "{{name}} ist kein gültiges Sortierungsfeld für dieses Sprunje." - ] - ] -]; + [ + "ARRAY" => "Die Werte für {{label}} müssen in einem Feld liegen.", + "BOOLEAN" => "Der Wert für {{label}} muss entweder '0' oder '1' sein.", + "INTEGER" => "Der Wert für {{label}} muss eine ganze Zahl sein.", + "INVALID_EMAIL" => "Ungültige E-Mail-Adresse.", + "LENGTH_RANGE" => "{{label}} muss zwischen {{min}} und {{max}} Zeichen lang sein.", + "NO_LEAD_WS" => "Der Wert für {{label}} kann nicht mit Leerzeichen, Tabulatoren oder anderen Leerzeichen beginnen.", + "NO_TRAIL_WS" => "Der Wert für {{label}} kann nicht mit Leerzeichen, Tabulatoren oder anderen Leerzeichen enden.", + "REQUIRED" => "Bitte geben Sie einen Wert für {{label}} an.", + "SPRUNJE" => [ + "BAD_FILTER" => "{{name}} ist kein gültiger Filter für dieses Sprunje.", + "BAD_LIST" => "{{name}} ist kein gültige Liste für dieses Sprunje.", + "BAD_SORT" => "{{name}} ist kein gültiges Sortierungsfeld für dieses Sprunje." + ] + ] +]; diff --git a/main/app/sprinkles/core/locale/valitron/ar.php b/main/app/sprinkles/core/locale/valitron/ar.php index 7834e10..9278c56 100644 --- a/main/app/sprinkles/core/locale/valitron/ar.php +++ b/main/app/sprinkles/core/locale/valitron/ar.php @@ -1,28 +1,28 @@ - "مطلوب", - 'equals' => "يجب أن يكون مساوي لي '%s'", - 'different' => "يجب ان يكون غير '%s'", - 'accepted' => "يجب ان يكون نعم", - 'numeric' => "يجب ان يكون رقم", - 'integer' => "يجب ان يكون رقم (0-9)", - 'length' => "يجب ان يكون أطول من %d", - 'min' => "يجب ان يكون اعلي من %s", - 'max' => "يجب ان يكون اقل من %s", - 'in' => "الُمدخل يغير صحيح", - 'notIn' => "الُمدخل يغير صحيح", - 'ip' => "رقم الإتصال غير صحيح", - 'email' => "البريد الألكتروني غير صحيح", - 'url' => "الرابط غير صحيح", - 'urlActive' => "يجب أن يكون نطاق فعال", - 'alpha' => "يجب أن يحتوي فقط علي a-z", - 'alphaNum' => "يجب ان يحتوي فقط a-z او ارقام 0-9", - 'slug' => "يجب ان يحتوي فقط علي a-z, و ارقام 0-9, شرطات و خط سفلي", - 'regex' => "خطا بالصيغة", - 'date' => "خطا بالتاريخ", - 'dateFormat' => "يجب ان يكون تاريخ بهذه الصيغة '%s'", - 'dateBefore' => "التاريخ يجب ان يكون قبل '%s'", - 'dateAfter' => "التاريخ يجب ان يكون بعد '%s'", - 'contains' => "يجب ان يحتوي %s" -); + "مطلوب", + 'equals' => "يجب أن يكون مساوي لي '%s'", + 'different' => "يجب ان يكون غير '%s'", + 'accepted' => "يجب ان يكون نعم", + 'numeric' => "يجب ان يكون رقم", + 'integer' => "يجب ان يكون رقم (0-9)", + 'length' => "يجب ان يكون أطول من %d", + 'min' => "يجب ان يكون اعلي من %s", + 'max' => "يجب ان يكون اقل من %s", + 'in' => "الُمدخل يغير صحيح", + 'notIn' => "الُمدخل يغير صحيح", + 'ip' => "رقم الإتصال غير صحيح", + 'email' => "البريد الألكتروني غير صحيح", + 'url' => "الرابط غير صحيح", + 'urlActive' => "يجب أن يكون نطاق فعال", + 'alpha' => "يجب أن يحتوي فقط علي a-z", + 'alphaNum' => "يجب ان يحتوي فقط a-z او ارقام 0-9", + 'slug' => "يجب ان يحتوي فقط علي a-z, و ارقام 0-9, شرطات و خط سفلي", + 'regex' => "خطا بالصيغة", + 'date' => "خطا بالتاريخ", + 'dateFormat' => "يجب ان يكون تاريخ بهذه الصيغة '%s'", + 'dateBefore' => "التاريخ يجب ان يكون قبل '%s'", + 'dateAfter' => "التاريخ يجب ان يكون بعد '%s'", + 'contains' => "يجب ان يحتوي %s" +); diff --git a/main/app/sprinkles/core/locale/valitron/de.php b/main/app/sprinkles/core/locale/valitron/de.php index d5242e3..438ed51 100644 --- a/main/app/sprinkles/core/locale/valitron/de.php +++ b/main/app/sprinkles/core/locale/valitron/de.php @@ -1,33 +1,33 @@ - "ist erforderlich", - 'equals' => "muss identisch mit '%s' sein", - 'different' => "muss sich von '%s' unterscheiden", - 'accepted' => "muss markiert sein", - 'numeric' => "muss eine Zahl sein", - 'integer' => "muss eine ganze Zahl sein", - 'length' => "kann nicht länger als %d sein", - 'min' => "muss größer als %s sein", - 'max' => "muss kleiner als %s sein", - 'in' => "enthält einen ungültigen Wert", - 'notIn' => "enthält einen ungültigen Wert", - 'ip' => "enthält keine gültige IP-Addresse", - 'email' => "enthält keine gültige E-Mail-Adresse", - 'url' => "enthält keine gültige URL", - 'urlActive' => "muss eine aktive Domain sein", - 'alpha' => "darf nur Buchstaben enthalten", - 'alphaNum' => "darf nur Buchstaben und Ganzzahlen enthalten", - 'slug' => "darf nur Buchstaben, Ganzzahlen, Schrägstriche und Grundstriche enthalten", - 'regex' => "enthält ungültige Zeichen", - 'date' => "enthält kein gültiges Datum", - 'dateFormat' => "benötigt ein Datum im Format '%s'", - 'dateBefore' => "benötigt ein Datum, das vor dem '%s' liegt", - 'dateAfter' => "benötigt ein Datum, das nach dem '%s' liegt", - 'contains' => "muss %s beinhalten", - 'boolean' => "muss ein Wahrheitswert sein", - 'lengthBetween' => "benötigt zwischen %d und %d Zeichen", - 'creditCard' => "muss eine gültige Kreditkartennummer sein", - "lengthMin" => "muss mindestens %d Zeichen enthalten", - "lengthMax" => "kann nicht mehr als %d Zeichen enthalten" -); + "ist erforderlich", + 'equals' => "muss identisch mit '%s' sein", + 'different' => "muss sich von '%s' unterscheiden", + 'accepted' => "muss markiert sein", + 'numeric' => "muss eine Zahl sein", + 'integer' => "muss eine ganze Zahl sein", + 'length' => "kann nicht länger als %d sein", + 'min' => "muss größer als %s sein", + 'max' => "muss kleiner als %s sein", + 'in' => "enthält einen ungültigen Wert", + 'notIn' => "enthält einen ungültigen Wert", + 'ip' => "enthält keine gültige IP-Addresse", + 'email' => "enthält keine gültige E-Mail-Adresse", + 'url' => "enthält keine gültige URL", + 'urlActive' => "muss eine aktive Domain sein", + 'alpha' => "darf nur Buchstaben enthalten", + 'alphaNum' => "darf nur Buchstaben und Ganzzahlen enthalten", + 'slug' => "darf nur Buchstaben, Ganzzahlen, Schrägstriche und Grundstriche enthalten", + 'regex' => "enthält ungültige Zeichen", + 'date' => "enthält kein gültiges Datum", + 'dateFormat' => "benötigt ein Datum im Format '%s'", + 'dateBefore' => "benötigt ein Datum, das vor dem '%s' liegt", + 'dateAfter' => "benötigt ein Datum, das nach dem '%s' liegt", + 'contains' => "muss %s beinhalten", + 'boolean' => "muss ein Wahrheitswert sein", + 'lengthBetween' => "benötigt zwischen %d und %d Zeichen", + 'creditCard' => "muss eine gültige Kreditkartennummer sein", + "lengthMin" => "muss mindestens %d Zeichen enthalten", + "lengthMax" => "kann nicht mehr als %d Zeichen enthalten" +); diff --git a/main/app/sprinkles/core/locale/valitron/el.php b/main/app/sprinkles/core/locale/valitron/el.php index 089f6d2..444d2a3 100644 --- a/main/app/sprinkles/core/locale/valitron/el.php +++ b/main/app/sprinkles/core/locale/valitron/el.php @@ -1,34 +1,34 @@ - "είναι απαραίτητο", - 'equals' => "πρέπει να είναι ίδιο με '%s'", - 'different' => "πρέπει να διαφέρει από '%s'", - 'accepted' => "πρέπει να έχει αποδεχτεί", - 'numeric' => "πρέπει να είναι αριθμός", - 'integer' => "πρέπει να είναι ακέραιος αριθμός (0-9)", - 'length' => "πρέπει να είναι μεγαλύτερο από %d", - 'min' => "πρέπει να είναι τουλάχιστον %s", - 'max' => "δεν πρέπει να είναι περισσότερο από %s", - 'in' => "περιέχει μη έγκυρη τιμή", - 'notIn' => "περιέχει μη έγκυρη τιμή", - 'ip' => "δεν είναι έγκυρη διεύθυνση IP", - 'email' => "δεν είναι έγκυρη διεύθυνση email", - 'url' => "δεν είναι URL", - 'urlActive' => "πρέπει να είναι ενεργό domain", - 'alpha' => "πρέπει να περιέχει μόνο χαρακτήρες", - 'alphaNum' => "πρέπει να περιέχει μόνο χαρακτήρες και/ή αριθμούς", - 'slug' => "πρέπει να περιέχει μόνο χαρακτήρες, αριθμούς, παύλες και κάτω παύλες", - 'regex' => "περιέχει μη έγκυρους χαρακτήρες", - 'date' => "δεν είναι έγκυρη ημερομηνία", - 'dateFormat' => "πρέπει να είναι ημερομηνία της μορφής '%s'", - 'dateBefore' => "πρέπει να είναι ημερομηνία πριν από '%s'", - 'dateAfter' => "πρέπει να είναι ημερομηνία μετά από '%s'", - 'contains' => "πρέπει να περιέχει %s", - 'boolean' => "πρέπει να είναι boolean", - 'lengthBetween' => "πρέπει να είναι μεταξύ %d και %d χαρακτήρων", - 'creditCard' => "πρέπει να είναι ένα έγκυρο νούμερο πιστωτικής κάρτας", - "lengthMin" => "πρέπει να περιέχει περισσότερους από %d χαρακτήρες", - "lengthMax" => "πρέπει να περιέχει λιγότερους από %d χαρακτήρες", - "instanceOf" => "πρέπει να είναι αντικείμενο της '%s'" -); + "είναι απαραίτητο", + 'equals' => "πρέπει να είναι ίδιο με '%s'", + 'different' => "πρέπει να διαφέρει από '%s'", + 'accepted' => "πρέπει να έχει αποδεχτεί", + 'numeric' => "πρέπει να είναι αριθμός", + 'integer' => "πρέπει να είναι ακέραιος αριθμός (0-9)", + 'length' => "πρέπει να είναι μεγαλύτερο από %d", + 'min' => "πρέπει να είναι τουλάχιστον %s", + 'max' => "δεν πρέπει να είναι περισσότερο από %s", + 'in' => "περιέχει μη έγκυρη τιμή", + 'notIn' => "περιέχει μη έγκυρη τιμή", + 'ip' => "δεν είναι έγκυρη διεύθυνση IP", + 'email' => "δεν είναι έγκυρη διεύθυνση email", + 'url' => "δεν είναι URL", + 'urlActive' => "πρέπει να είναι ενεργό domain", + 'alpha' => "πρέπει να περιέχει μόνο χαρακτήρες", + 'alphaNum' => "πρέπει να περιέχει μόνο χαρακτήρες και/ή αριθμούς", + 'slug' => "πρέπει να περιέχει μόνο χαρακτήρες, αριθμούς, παύλες και κάτω παύλες", + 'regex' => "περιέχει μη έγκυρους χαρακτήρες", + 'date' => "δεν είναι έγκυρη ημερομηνία", + 'dateFormat' => "πρέπει να είναι ημερομηνία της μορφής '%s'", + 'dateBefore' => "πρέπει να είναι ημερομηνία πριν από '%s'", + 'dateAfter' => "πρέπει να είναι ημερομηνία μετά από '%s'", + 'contains' => "πρέπει να περιέχει %s", + 'boolean' => "πρέπει να είναι boolean", + 'lengthBetween' => "πρέπει να είναι μεταξύ %d και %d χαρακτήρων", + 'creditCard' => "πρέπει να είναι ένα έγκυρο νούμερο πιστωτικής κάρτας", + "lengthMin" => "πρέπει να περιέχει περισσότερους από %d χαρακτήρες", + "lengthMax" => "πρέπει να περιέχει λιγότερους από %d χαρακτήρες", + "instanceOf" => "πρέπει να είναι αντικείμενο της '%s'" +); diff --git a/main/app/sprinkles/core/locale/valitron/en.php b/main/app/sprinkles/core/locale/valitron/en.php index bb8b7fe..ce7f3f4 100644 --- a/main/app/sprinkles/core/locale/valitron/en.php +++ b/main/app/sprinkles/core/locale/valitron/en.php @@ -1,34 +1,34 @@ - "is required", - 'equals' => "must be the same as '%s'", - 'different' => "must be different than '%s'", - 'accepted' => "must be accepted", - 'numeric' => "must be numeric", - 'integer' => "must be an integer (0-9)", - 'length' => "must be longer than %d", - 'min' => "must be at least %s", - 'max' => "must be no more than %s", - 'in' => "contains invalid value", - 'notIn' => "contains invalid value", - 'ip' => "is not a valid IP address", - 'email' => "is not a valid email address", - 'url' => "not a URL", - 'urlActive' => "must be an active domain", - 'alpha' => "must contain only letters a-z", - 'alphaNum' => "must contain only letters a-z and/or numbers 0-9", - 'slug' => "must contain only letters a-z, numbers 0-9, dashes and underscores", - 'regex' => "contains invalid characters", - 'date' => "is not a valid date", - 'dateFormat' => "must be date with format '%s'", - 'dateBefore' => "must be date before '%s'", - 'dateAfter' => "must be date after '%s'", - 'contains' => "must contain %s", - 'boolean' => "must be a boolean", - 'lengthBetween' => "must be between %d and %d characters", - 'creditCard' => "must be a valid credit card number", - "lengthMin" => "must contain greater than %d characters", - "lengthMax" => "must contain less than %d characters", - "instanceOf" => "must be an instance of '%s'" -); + "is required", + 'equals' => "must be the same as '%s'", + 'different' => "must be different than '%s'", + 'accepted' => "must be accepted", + 'numeric' => "must be numeric", + 'integer' => "must be an integer (0-9)", + 'length' => "must be longer than %d", + 'min' => "must be at least %s", + 'max' => "must be no more than %s", + 'in' => "contains invalid value", + 'notIn' => "contains invalid value", + 'ip' => "is not a valid IP address", + 'email' => "is not a valid email address", + 'url' => "not a URL", + 'urlActive' => "must be an active domain", + 'alpha' => "must contain only letters a-z", + 'alphaNum' => "must contain only letters a-z and/or numbers 0-9", + 'slug' => "must contain only letters a-z, numbers 0-9, dashes and underscores", + 'regex' => "contains invalid characters", + 'date' => "is not a valid date", + 'dateFormat' => "must be date with format '%s'", + 'dateBefore' => "must be date before '%s'", + 'dateAfter' => "must be date after '%s'", + 'contains' => "must contain %s", + 'boolean' => "must be a boolean", + 'lengthBetween' => "must be between %d and %d characters", + 'creditCard' => "must be a valid credit card number", + "lengthMin" => "must contain greater than %d characters", + "lengthMax" => "must contain less than %d characters", + "instanceOf" => "must be an instance of '%s'" +); diff --git a/main/app/sprinkles/core/locale/valitron/es.php b/main/app/sprinkles/core/locale/valitron/es.php index cf208ff..c1002f2 100644 --- a/main/app/sprinkles/core/locale/valitron/es.php +++ b/main/app/sprinkles/core/locale/valitron/es.php @@ -1,34 +1,34 @@ - "es requerido", - 'equals' => "debe ser igual a '%s'", - 'different' => "debe ser diferente a '%s'", - 'accepted' => "debe ser aceptado", - 'numeric' => "debe ser numérico", - 'integer' => "debe ser un entero (0-9)", - 'length' => "debe ser mas largo de %d", - 'min' => "debe ser mayor a %s", - 'max' => "debe ser menor a %s", - 'in' => "contiene un valor invalido", - 'notIn' => "contiene un valor invalido", - 'ip' => "no es una dirección IP", - 'email' => "no es un correo electrónico válido", - 'url' => "no es una URL", - 'urlActive' => "debe ser un dominio activo", - 'alpha' => "debe contener solo letras a-z", - 'alphaNum' => "debe contener solo letras a-z o números 0-9", - 'slug' => "debe contener solo letras a-z, números 0-9, diagonales y guiones bajos", - 'regex' => "contiene caracteres inválidos", - 'date' => "no es una fecha válida", - 'dateFormat' => "debe ser una fecha con formato '%s'", - 'dateBefore' => "debe ser una fecha antes de '%s'", - 'dateAfter' => "debe ser una fecha después de '%s'", - 'contains' => "debe contener %s", - 'boolean' => "debe ser booleano", - 'lengthBetween' => "debe ser entre %d y %d caracteres", - 'creditCard' => "debe ser un numero de tarjeta de crédito válido", - "lengthMin" => "debe contener mas de %d caracteres", - "lengthMax" => "debe contener menos de %d caracteres", - "instanceOf" => "debe ser una instancia de '%s'" -); + "es requerido", + 'equals' => "debe ser igual a '%s'", + 'different' => "debe ser diferente a '%s'", + 'accepted' => "debe ser aceptado", + 'numeric' => "debe ser numérico", + 'integer' => "debe ser un entero (0-9)", + 'length' => "debe ser mas largo de %d", + 'min' => "debe ser mayor a %s", + 'max' => "debe ser menor a %s", + 'in' => "contiene un valor invalido", + 'notIn' => "contiene un valor invalido", + 'ip' => "no es una dirección IP", + 'email' => "no es un correo electrónico válido", + 'url' => "no es una URL", + 'urlActive' => "debe ser un dominio activo", + 'alpha' => "debe contener solo letras a-z", + 'alphaNum' => "debe contener solo letras a-z o números 0-9", + 'slug' => "debe contener solo letras a-z, números 0-9, diagonales y guiones bajos", + 'regex' => "contiene caracteres inválidos", + 'date' => "no es una fecha válida", + 'dateFormat' => "debe ser una fecha con formato '%s'", + 'dateBefore' => "debe ser una fecha antes de '%s'", + 'dateAfter' => "debe ser una fecha después de '%s'", + 'contains' => "debe contener %s", + 'boolean' => "debe ser booleano", + 'lengthBetween' => "debe ser entre %d y %d caracteres", + 'creditCard' => "debe ser un numero de tarjeta de crédito válido", + "lengthMin" => "debe contener mas de %d caracteres", + "lengthMax" => "debe contener menos de %d caracteres", + "instanceOf" => "debe ser una instancia de '%s'" +); diff --git a/main/app/sprinkles/core/locale/valitron/fr.php b/main/app/sprinkles/core/locale/valitron/fr.php index 728d782..6bd678f 100644 --- a/main/app/sprinkles/core/locale/valitron/fr.php +++ b/main/app/sprinkles/core/locale/valitron/fr.php @@ -1,34 +1,34 @@ - "est obligatoire", - 'equals' => "doit être identique à '%s'", - 'different' => "doit être différent de '%s'", - 'accepted' => "doit être accepté", - 'numeric' => "doit être numérique", - 'integer' => "doit être un entier (0-9)", - 'length' => "doit être plus long que %d", - 'min' => "doit être plus grand que %s", - 'max' => "doit être plus petit que %s", - 'in' => "contient une valeur non valide", - 'notIn' => "contient une valeur non valide", - 'ip' => "n'est pas une adresse IP valide", - 'email' => "n'est pas une adresse email valide", - 'url' => "n'est pas une URL", - 'urlActive' => "doit être un domaine actif", - 'alpha' => "doit contenir uniquement les lettres a-z", - 'alphaNum' => "doit contenir uniquement des lettres de a-z et/ou des chiffres 0-9", - 'slug' => "doit contenir uniquement des lettres de a-z, des chiffres 0-9, des tirets et des traits soulignés", - 'regex' => "contient des caractères invalides", - 'date' => "n'est pas une date valide", - 'dateFormat' => "doit être une date avec le format '%s'", - 'dateBefore' => "doit être une date avant '%s'", - 'dateAfter' => "doit être une date après '%s'", - 'contains' => "doit contenir %s", - 'boolean' => "doit être un booléen", - 'lengthBetween' => "doit contenir entre %d et %d caractères", - 'creditCard' => "doit être un numéro de carte de crédit valide", - "lengthMin" => "doit contenir plus de %d caractères", - "lengthMax" => "doit contenir moins de %d caractères", - "instanceOf" => "doit être une instance de '%s'" -); + "est obligatoire", + 'equals' => "doit être identique à '%s'", + 'different' => "doit être différent de '%s'", + 'accepted' => "doit être accepté", + 'numeric' => "doit être numérique", + 'integer' => "doit être un entier (0-9)", + 'length' => "doit être plus long que %d", + 'min' => "doit être plus grand que %s", + 'max' => "doit être plus petit que %s", + 'in' => "contient une valeur non valide", + 'notIn' => "contient une valeur non valide", + 'ip' => "n'est pas une adresse IP valide", + 'email' => "n'est pas une adresse email valide", + 'url' => "n'est pas une URL", + 'urlActive' => "doit être un domaine actif", + 'alpha' => "doit contenir uniquement les lettres a-z", + 'alphaNum' => "doit contenir uniquement des lettres de a-z et/ou des chiffres 0-9", + 'slug' => "doit contenir uniquement des lettres de a-z, des chiffres 0-9, des tirets et des traits soulignés", + 'regex' => "contient des caractères invalides", + 'date' => "n'est pas une date valide", + 'dateFormat' => "doit être une date avec le format '%s'", + 'dateBefore' => "doit être une date avant '%s'", + 'dateAfter' => "doit être une date après '%s'", + 'contains' => "doit contenir %s", + 'boolean' => "doit être un booléen", + 'lengthBetween' => "doit contenir entre %d et %d caractères", + 'creditCard' => "doit être un numéro de carte de crédit valide", + "lengthMin" => "doit contenir plus de %d caractères", + "lengthMax" => "doit contenir moins de %d caractères", + "instanceOf" => "doit être une instance de '%s'" +); diff --git a/main/app/sprinkles/core/locale/valitron/id.php b/main/app/sprinkles/core/locale/valitron/id.php index 552ab90..8d6dad7 100644 --- a/main/app/sprinkles/core/locale/valitron/id.php +++ b/main/app/sprinkles/core/locale/valitron/id.php @@ -1,33 +1,33 @@ - "harus diisi", - 'equals' => "harus sama dengan '%s'", - 'different' => "harus berbeda dengan '%s'", - 'accepted' => "harus diterima (accepted)", - 'numeric' => "harus berupa nomor/angka", - 'integer' => "harus berupa nilai integer (0-9)", - 'length' => "harus lebih panjang dari %d", - 'min' => "harus lebih besar dari %s", - 'max' => "harus kurang dari %s", - 'in' => "berisi nilai/value yang tidak valid", - 'notIn' => "berisi nilai/value yang tidak valid", - 'ip' => "format alamat IP tidak benar", - 'email' => "format alamat email tidak benar", - 'url' => "bukan format URL yang benar", - 'urlActive' => "harus berupa domain aktif", - 'alpha' => "hanya boleh menggunakan huruf a-z", - 'alphaNum' => "hanya boleh menggunakan huruf a-z dan atau nomor 0-9", - 'slug' => "hanya boleh menggunakan huruf a-z, nomor 0-9, tanda minus (-), dan uderscore atau strip bawah (_)", - 'regex' => "berisi karakter yang tidak valid", - 'date' => "format tanggal tidak valid", - 'dateFormat' => "harus berupa tanggal dengan format '%s'", - 'dateBefore' => "tanggal harus sebelum tanggal '%s'", - 'dateAfter' => "tanggal harus sesudah tanggal '%s'", - 'contains' => "harus berisi %s", - 'boolean' => "harus berupa nilai boolean", - 'lengthBetween' => "harus diantara karakter %d dan %d", - 'creditCard' => "nomor kartu kredit harus valid", - "lengthMin" => "minimal berisi %d karakter", - "lengthMax" => "maksimal berisi %d karakter" -); + "harus diisi", + 'equals' => "harus sama dengan '%s'", + 'different' => "harus berbeda dengan '%s'", + 'accepted' => "harus diterima (accepted)", + 'numeric' => "harus berupa nomor/angka", + 'integer' => "harus berupa nilai integer (0-9)", + 'length' => "harus lebih panjang dari %d", + 'min' => "harus lebih besar dari %s", + 'max' => "harus kurang dari %s", + 'in' => "berisi nilai/value yang tidak valid", + 'notIn' => "berisi nilai/value yang tidak valid", + 'ip' => "format alamat IP tidak benar", + 'email' => "format alamat email tidak benar", + 'url' => "bukan format URL yang benar", + 'urlActive' => "harus berupa domain aktif", + 'alpha' => "hanya boleh menggunakan huruf a-z", + 'alphaNum' => "hanya boleh menggunakan huruf a-z dan atau nomor 0-9", + 'slug' => "hanya boleh menggunakan huruf a-z, nomor 0-9, tanda minus (-), dan uderscore atau strip bawah (_)", + 'regex' => "berisi karakter yang tidak valid", + 'date' => "format tanggal tidak valid", + 'dateFormat' => "harus berupa tanggal dengan format '%s'", + 'dateBefore' => "tanggal harus sebelum tanggal '%s'", + 'dateAfter' => "tanggal harus sesudah tanggal '%s'", + 'contains' => "harus berisi %s", + 'boolean' => "harus berupa nilai boolean", + 'lengthBetween' => "harus diantara karakter %d dan %d", + 'creditCard' => "nomor kartu kredit harus valid", + "lengthMin" => "minimal berisi %d karakter", + "lengthMax" => "maksimal berisi %d karakter" +); diff --git a/main/app/sprinkles/core/locale/valitron/it.php b/main/app/sprinkles/core/locale/valitron/it.php index cac99f5..d157ce8 100644 --- a/main/app/sprinkles/core/locale/valitron/it.php +++ b/main/app/sprinkles/core/locale/valitron/it.php @@ -1,31 +1,31 @@ - "è obbligatorio", - 'equals' => "deve essere uguale a '%s'", - 'different' => "deve essere differente da '%s'", - 'accepted' => "deve essere accettato", - 'numeric' => "deve essere numerico", - 'integer' => "deve essere un intero (0-9)", - 'length' => "deve avere una lunghezza di %d", - 'min' => "deve essere superiore a %s", - 'max' => "deve essere inferiore a %s", - 'in' => "contiene un valore non valido", - 'notIn' => "contiene un valore non valido", - 'ip' => "non è un indirizzo IP valido", - 'email' => "non è un indirizzo email valido", - 'url' => "non è una URL", - 'urlActive' => "deve essere un dominio attivo", - 'alpha' => "deve contenere solamente lettere (a-z)", - 'alphaNum' => "deve contenere solamente lettere (a-z) e/o numeri (0-9)", - 'slug' => "deve contenere solamente lettere (a-z), numeri (0-9), trattini (-) e trattini bassi (_)", - 'regex' => "contiene caratteri non validi", - 'date' => "non è una data valida", - 'dateFormat' => "deve essere una data nel formato '%s'", - 'dateBefore' => "deve essere una data precedente al '%s'", - 'dateAfter' => "deve essere una data successiva al '%s'", - 'contains' => "deve contenere %s", - 'boolean' => "deve essere un booleano", - 'lengthBetween' => "deve essere compreso tra %d e %d caratteri", - 'creditCard' => "deve essere un numero di carta di credito valido" -); + "è obbligatorio", + 'equals' => "deve essere uguale a '%s'", + 'different' => "deve essere differente da '%s'", + 'accepted' => "deve essere accettato", + 'numeric' => "deve essere numerico", + 'integer' => "deve essere un intero (0-9)", + 'length' => "deve avere una lunghezza di %d", + 'min' => "deve essere superiore a %s", + 'max' => "deve essere inferiore a %s", + 'in' => "contiene un valore non valido", + 'notIn' => "contiene un valore non valido", + 'ip' => "non è un indirizzo IP valido", + 'email' => "non è un indirizzo email valido", + 'url' => "non è una URL", + 'urlActive' => "deve essere un dominio attivo", + 'alpha' => "deve contenere solamente lettere (a-z)", + 'alphaNum' => "deve contenere solamente lettere (a-z) e/o numeri (0-9)", + 'slug' => "deve contenere solamente lettere (a-z), numeri (0-9), trattini (-) e trattini bassi (_)", + 'regex' => "contiene caratteri non validi", + 'date' => "non è una data valida", + 'dateFormat' => "deve essere una data nel formato '%s'", + 'dateBefore' => "deve essere una data precedente al '%s'", + 'dateAfter' => "deve essere una data successiva al '%s'", + 'contains' => "deve contenere %s", + 'boolean' => "deve essere un booleano", + 'lengthBetween' => "deve essere compreso tra %d e %d caratteri", + 'creditCard' => "deve essere un numero di carta di credito valido" +); diff --git a/main/app/sprinkles/core/locale/valitron/ja.php b/main/app/sprinkles/core/locale/valitron/ja.php index facf0da..4b178cb 100644 --- a/main/app/sprinkles/core/locale/valitron/ja.php +++ b/main/app/sprinkles/core/locale/valitron/ja.php @@ -1,33 +1,33 @@ - "を入力してください", - 'equals' => "は「%s」と同じ内容を入力してください", - 'different' => "は「%s」と異なる内容を入力してください", - 'accepted' => "に同意してください", - 'numeric' => "は数値を入力してください", - 'integer' => "は半角数字で入力してください", - 'length' => "は%d文字で入力してください", - 'min' => "には%sより大きな値を入力してください", - 'max' => "には%sより小さな値を入力してください", - 'in' => "には選択できない値が含まれています", - 'notIn' => "には選択できない値が含まれています", - 'ip' => "はIPアドレスの書式として正しくありません", - 'email' => "はメールアドレスの書式として正しくありません", - 'url' => "はURLの書式として正しくありません", - 'urlActive' => "はアクティブなドメインではありません", - 'alpha' => "は半角英字で入力してください", - 'alphaNum' => "は半角英数字で入力してください", - 'slug' => "は半角英数字、もしくは「-」「_」の文字で入力してください", - 'regex' => "の書式が正しくありません", - 'date' => "は日付の書式として正しくありません", - 'dateFormat' => "は「%s」の書式で日付を入力してください", - 'dateBefore' => "は「%s」以前の日付を入力してください", - 'dateAfter' => "は「%s」以後の日付を入力してください", - 'contains' => "は「%s」を含んでいなければいけません", - 'boolean' => "は真偽値である必要があります", - 'lengthBetween' => "は%d〜%d文字で入力してください", - 'creditCard' => "はクレジットカード番号の書式として正しくありません", - "lengthMin" => "は%d文字以上入力してください", - "lengthMax" => "は%d文字以内で入力してください" -); + "を入力してください", + 'equals' => "は「%s」と同じ内容を入力してください", + 'different' => "は「%s」と異なる内容を入力してください", + 'accepted' => "に同意してください", + 'numeric' => "は数値を入力してください", + 'integer' => "は半角数字で入力してください", + 'length' => "は%d文字で入力してください", + 'min' => "には%sより大きな値を入力してください", + 'max' => "には%sより小さな値を入力してください", + 'in' => "には選択できない値が含まれています", + 'notIn' => "には選択できない値が含まれています", + 'ip' => "はIPアドレスの書式として正しくありません", + 'email' => "はメールアドレスの書式として正しくありません", + 'url' => "はURLの書式として正しくありません", + 'urlActive' => "はアクティブなドメインではありません", + 'alpha' => "は半角英字で入力してください", + 'alphaNum' => "は半角英数字で入力してください", + 'slug' => "は半角英数字、もしくは「-」「_」の文字で入力してください", + 'regex' => "の書式が正しくありません", + 'date' => "は日付の書式として正しくありません", + 'dateFormat' => "は「%s」の書式で日付を入力してください", + 'dateBefore' => "は「%s」以前の日付を入力してください", + 'dateAfter' => "は「%s」以後の日付を入力してください", + 'contains' => "は「%s」を含んでいなければいけません", + 'boolean' => "は真偽値である必要があります", + 'lengthBetween' => "は%d〜%d文字で入力してください", + 'creditCard' => "はクレジットカード番号の書式として正しくありません", + "lengthMin" => "は%d文字以上入力してください", + "lengthMax" => "は%d文字以内で入力してください" +); diff --git a/main/app/sprinkles/core/locale/valitron/lv.php b/main/app/sprinkles/core/locale/valitron/lv.php index 06a77c5..1ec70e2 100644 --- a/main/app/sprinkles/core/locale/valitron/lv.php +++ b/main/app/sprinkles/core/locale/valitron/lv.php @@ -1,31 +1,31 @@ - "ir obligāts lauks", - 'equals' => "jāsakrīt ar '%s'", - 'different' => "nedrīkst sakrist ar '%s' lauku", - 'accepted' => "laukam jābūt apstiprinātam", - 'numeric' => "jābūt skaitliskai vērtībai", - 'integer' => "jābūt ciparam (0-9)", - 'length' => "nedrīkst būt garāks par %d simboliem", - 'min' => "jābūt garākam par %s simboliem", - 'max' => "jābūt īsākam par %s simboliem", - 'in' => "lauks satur nederīgu vērtību", - 'notIn' => "lauks satur nederīgu vērtību", - 'ip' => " lauks nav derīga IP adrese", - 'email' => "lauks nav norādīta derīga epasta adrese", - 'url' => "lauks nav tīmekļa saite", - 'urlActive' => "saite neatrodas esošajā domēna vārdā", - 'alpha' => "lauks var saturēt tikai alfabēta burtus a-z", - 'alphaNum' => "lauks var saturēt tikai alfabēta burtus un/vai ciparus 0-9", - 'slug' => "lauks var saturēt tikai alfabēta burtus un/vai ciparus 0-9, domuzīmes and zemsvītras", - 'regex' => "lauks satur nederīgus simbolus", - 'date' => "lauks ir nederīgā datuma formātā", - 'dateFormat' => "laukam jābūt datuma formātā '%s'", - 'dateBefore' => "lauka datumam jābūt pirms '%s'", - 'dateAfter' => "lauka datumam jābūt pēc '%s'", - 'contains' => "laukam jāsatur %s", - 'boolean' => "laukam jābūt ir/nav vērtībai", - 'lengthBetween' => "lauka garumam jābūt no %d līdz %d simbolu garam", - 'creditCard' => "laukam jābūt derīgam kredītkartes numuram" -); + "ir obligāts lauks", + 'equals' => "jāsakrīt ar '%s'", + 'different' => "nedrīkst sakrist ar '%s' lauku", + 'accepted' => "laukam jābūt apstiprinātam", + 'numeric' => "jābūt skaitliskai vērtībai", + 'integer' => "jābūt ciparam (0-9)", + 'length' => "nedrīkst būt garāks par %d simboliem", + 'min' => "jābūt garākam par %s simboliem", + 'max' => "jābūt īsākam par %s simboliem", + 'in' => "lauks satur nederīgu vērtību", + 'notIn' => "lauks satur nederīgu vērtību", + 'ip' => " lauks nav derīga IP adrese", + 'email' => "lauks nav norādīta derīga epasta adrese", + 'url' => "lauks nav tīmekļa saite", + 'urlActive' => "saite neatrodas esošajā domēna vārdā", + 'alpha' => "lauks var saturēt tikai alfabēta burtus a-z", + 'alphaNum' => "lauks var saturēt tikai alfabēta burtus un/vai ciparus 0-9", + 'slug' => "lauks var saturēt tikai alfabēta burtus un/vai ciparus 0-9, domuzīmes and zemsvītras", + 'regex' => "lauks satur nederīgus simbolus", + 'date' => "lauks ir nederīgā datuma formātā", + 'dateFormat' => "laukam jābūt datuma formātā '%s'", + 'dateBefore' => "lauka datumam jābūt pirms '%s'", + 'dateAfter' => "lauka datumam jābūt pēc '%s'", + 'contains' => "laukam jāsatur %s", + 'boolean' => "laukam jābūt ir/nav vērtībai", + 'lengthBetween' => "lauka garumam jābūt no %d līdz %d simbolu garam", + 'creditCard' => "laukam jābūt derīgam kredītkartes numuram" +); diff --git a/main/app/sprinkles/core/locale/valitron/pt-br.php b/main/app/sprinkles/core/locale/valitron/pt-br.php index 6c689b7..c248575 100644 --- a/main/app/sprinkles/core/locale/valitron/pt-br.php +++ b/main/app/sprinkles/core/locale/valitron/pt-br.php @@ -1,28 +1,28 @@ - "é obrigatório", - 'equals' => "deve ser o mesmo que '%s'", - 'different' => "deve ser diferente de '%s'", - 'accepted' => "deve ser aceito", - 'numeric' => "deve ser um número", - 'integer' => "deve ser um inteiro (0-9)", - 'length' => "deve ter mais que %d caracteres", - 'min' => "deve ser maior que %s", - 'max' => "deve ser menor que %s", - 'in' => "contém um valor inválido", - 'notIn' => "contém um valor inválido", - 'ip' => "não é um IP válido", - 'email' => "não é um email válido", - 'url' => "não é uma URL válida", - 'urlActive' => "deve ser um domínio ativo", - 'alpha' => "deve conter as letras a-z", - 'alphaNum' => "deve conter apenas letras a-z e/ou números 0-9", - 'slug' => "deve conter apenas letras a-z, números 0-9, ou os caracteres - ou _", - 'regex' => "contém caracteres inválidos", - 'date' => "não é uma data válida", - 'dateFormat' => "deve ser uma data no formato '%s'", - 'dateBefore' => "deve ser uma data anterior a '%s'", - 'dateAfter' => "deve ser uma data posterior a '%s'", - 'contains' => "deve conter %s" -); + "é obrigatório", + 'equals' => "deve ser o mesmo que '%s'", + 'different' => "deve ser diferente de '%s'", + 'accepted' => "deve ser aceito", + 'numeric' => "deve ser um número", + 'integer' => "deve ser um inteiro (0-9)", + 'length' => "deve ter mais que %d caracteres", + 'min' => "deve ser maior que %s", + 'max' => "deve ser menor que %s", + 'in' => "contém um valor inválido", + 'notIn' => "contém um valor inválido", + 'ip' => "não é um IP válido", + 'email' => "não é um email válido", + 'url' => "não é uma URL válida", + 'urlActive' => "deve ser um domínio ativo", + 'alpha' => "deve conter as letras a-z", + 'alphaNum' => "deve conter apenas letras a-z e/ou números 0-9", + 'slug' => "deve conter apenas letras a-z, números 0-9, ou os caracteres - ou _", + 'regex' => "contém caracteres inválidos", + 'date' => "não é uma data válida", + 'dateFormat' => "deve ser uma data no formato '%s'", + 'dateBefore' => "deve ser uma data anterior a '%s'", + 'dateAfter' => "deve ser uma data posterior a '%s'", + 'contains' => "deve conter %s" +); diff --git a/main/app/sprinkles/core/locale/valitron/ro.php b/main/app/sprinkles/core/locale/valitron/ro.php index bb85376..a5177d0 100644 --- a/main/app/sprinkles/core/locale/valitron/ro.php +++ b/main/app/sprinkles/core/locale/valitron/ro.php @@ -1,33 +1,33 @@ - "este necesar", - 'equals' => "trebuie sa fie la fel ca '%s'", - 'different' => "trebuie sa fie diferit ca '%s'", - 'accepted' => "trebuie acceptat", - 'numeric' => "trebuie sa fie numeric", - 'integer' => "trebuie sa fie o cifra (0-9)", - 'length' => "trebuie sa fie mai lung de %d", - 'min' => "trebuie sa fie minim %s", - 'max' => "nu trebuie sa fie mai mare de %s", - 'in' => "contine valori invalide", - 'notIn' => "contine valori invalide", - 'ip' => "nu este o adresa de IP valida", - 'email' => "nu este o adresa de email valida", - 'url' => "nu este un URL", - 'urlActive' => "trebuie sa fie un domeniu activ", - 'alpha' => "poate contine doar litere a-z", - 'alphaNum' => "poate contine doar litere a-z si/sau numere 0-9", - 'slug' => "poate contine doar litere a-z, numere 0-9, minus si underscore", - 'regex' => "contine caractere invalide", - 'date' => "nu este o data valida", - 'dateFormat' => "trebuie sa fie o data cu formatul '%s'", - 'dateBefore' => "trebuie sa fie o data inainte de '%s'", - 'dateAfter' => "trebuie sa fie o data dupa '%s'", - 'contains' => "trebuie sa contina %s", - 'boolean' => "trebuie sa fie valoare logica (boolean)", - 'lengthBetween' => "trebuie sa fie intre %d si %d caractere", - 'creditCard' => "trebuie sa fie un card de credit valid", - "lengthMin" => "trebuie sa contina mai mult de %d caractere", - "lengthMax" => "trebuie sa contina mai putin de %d caractere", - "instanceOf" => "trebuie sa fie o instanta a '%s'" -); + "este necesar", + 'equals' => "trebuie sa fie la fel ca '%s'", + 'different' => "trebuie sa fie diferit ca '%s'", + 'accepted' => "trebuie acceptat", + 'numeric' => "trebuie sa fie numeric", + 'integer' => "trebuie sa fie o cifra (0-9)", + 'length' => "trebuie sa fie mai lung de %d", + 'min' => "trebuie sa fie minim %s", + 'max' => "nu trebuie sa fie mai mare de %s", + 'in' => "contine valori invalide", + 'notIn' => "contine valori invalide", + 'ip' => "nu este o adresa de IP valida", + 'email' => "nu este o adresa de email valida", + 'url' => "nu este un URL", + 'urlActive' => "trebuie sa fie un domeniu activ", + 'alpha' => "poate contine doar litere a-z", + 'alphaNum' => "poate contine doar litere a-z si/sau numere 0-9", + 'slug' => "poate contine doar litere a-z, numere 0-9, minus si underscore", + 'regex' => "contine caractere invalide", + 'date' => "nu este o data valida", + 'dateFormat' => "trebuie sa fie o data cu formatul '%s'", + 'dateBefore' => "trebuie sa fie o data inainte de '%s'", + 'dateAfter' => "trebuie sa fie o data dupa '%s'", + 'contains' => "trebuie sa contina %s", + 'boolean' => "trebuie sa fie valoare logica (boolean)", + 'lengthBetween' => "trebuie sa fie intre %d si %d caractere", + 'creditCard' => "trebuie sa fie un card de credit valid", + "lengthMin" => "trebuie sa contina mai mult de %d caractere", + "lengthMax" => "trebuie sa contina mai putin de %d caractere", + "instanceOf" => "trebuie sa fie o instanta a '%s'" +); diff --git a/main/app/sprinkles/core/locale/valitron/ru.php b/main/app/sprinkles/core/locale/valitron/ru.php index 06f3537..5d20461 100644 --- a/main/app/sprinkles/core/locale/valitron/ru.php +++ b/main/app/sprinkles/core/locale/valitron/ru.php @@ -1,33 +1,33 @@ - "обязательно для заполнения", - 'equals' => "должно содержать '%s'", - 'different' => "должно отличаться от '%s'", - 'accepted' => "должно быть указано", - 'numeric' => "должно содержать числовое значение", - 'integer' => "должно быть числом", - 'length' => "должно быть длиннее, чем %d", - 'min' => "должно быть больше, чем %s", - 'max' => "должно быть меньше, чем %s", - 'in' => "содержит неверное значение", - 'notIn' => "содержит неверное значение", - 'ip' => "не является валидным IP адресом", - 'email' => "не является валидным email адресом", - 'url' => "не является ссылкой", - 'urlActive' => "содержит не активную ссылку", - 'alpha' => "должно содержать только латинские символы", - 'alphaNum' => "должно содержать только латинские символы и/или цифры", - 'slug' => "должно содержать только латинские символы, цифры, тире и подчёркивания", - 'regex' => "содержит недопустимые символы", - 'date' => "не является датой", - 'dateFormat' => "должно содержать дату следующего формата: %s", - 'dateBefore' => "должно содержать дату не позднее, чем %s", - 'dateAfter' => "должно содержать дату не ранее, чем %s", - 'contains' => "должно содержать %s", - 'boolean' => "должно содержать логическое значение", - 'lengthBetween' => "должно содержать от %d до %d символов", - 'creditCard' => "должно быть номером кредитной карты", - "lengthMin" => "должно содержать более %d символов", - "lengthMax" => "должно содержать менее %d символов" -); + "обязательно для заполнения", + 'equals' => "должно содержать '%s'", + 'different' => "должно отличаться от '%s'", + 'accepted' => "должно быть указано", + 'numeric' => "должно содержать числовое значение", + 'integer' => "должно быть числом", + 'length' => "должно быть длиннее, чем %d", + 'min' => "должно быть больше, чем %s", + 'max' => "должно быть меньше, чем %s", + 'in' => "содержит неверное значение", + 'notIn' => "содержит неверное значение", + 'ip' => "не является валидным IP адресом", + 'email' => "не является валидным email адресом", + 'url' => "не является ссылкой", + 'urlActive' => "содержит не активную ссылку", + 'alpha' => "должно содержать только латинские символы", + 'alphaNum' => "должно содержать только латинские символы и/или цифры", + 'slug' => "должно содержать только латинские символы, цифры, тире и подчёркивания", + 'regex' => "содержит недопустимые символы", + 'date' => "не является датой", + 'dateFormat' => "должно содержать дату следующего формата: %s", + 'dateBefore' => "должно содержать дату не позднее, чем %s", + 'dateAfter' => "должно содержать дату не ранее, чем %s", + 'contains' => "должно содержать %s", + 'boolean' => "должно содержать логическое значение", + 'lengthBetween' => "должно содержать от %d до %d символов", + 'creditCard' => "должно быть номером кредитной карты", + "lengthMin" => "должно содержать более %d символов", + "lengthMax" => "должно содержать менее %d символов" +); diff --git a/main/app/sprinkles/core/locale/valitron/th.php b/main/app/sprinkles/core/locale/valitron/th.php index 342e14d..73d5b11 100644 --- a/main/app/sprinkles/core/locale/valitron/th.php +++ b/main/app/sprinkles/core/locale/valitron/th.php @@ -1,34 +1,34 @@ - "ต้องการ", - 'equals' => "จะต้องเหมือนกับ '%s'", - 'different' => "จะต้องไม่ใช่ '%s'", - 'accepted' => "จะต้องยอมรับ", - 'numeric' => "จะต้องเป็นตัวเลข", - 'integer' => "จะต้องเป็นตัวเลขหลักเดียว (0-9)", - 'length' => "จะต้องมีความยาวมากกว่า %d", - 'min' => "จะต้องมีอย่างน้อย %s", - 'max' => "จะต้องมีไม่มากไปกว่า %s", - 'in' => "ประกอบด้วยค่าที่ไม่ถูกต้อง", - 'notIn' => "ประกอบด้วยค่าที่ไม่ถูกต้อง", - 'ip' => "ไม่ใช่ที่อยู่ไอพีที่ถูกต้อง", - 'email' => "ไม่ใช่ที่อยู่อีเมลที่ถูกต้อง", - 'url' => "ไม่ใช่ลิงก์", - 'urlActive' => "จะต้องเป็นโดเมนที่มีการใช้งานอยู่", - 'alpha' => "จะต้องประกอบไปด้วยตัวอักษร a-z เท่านั้น", - 'alphaNum' => "จะต้องประกอบไปด้วยตัวอักษร a-z และ/หรือ เลข 0-9", - 'slug' => "จะต้องประกอบไปด้วยตัวอักษร a-z เลข 0-9 ขีดกลาง และขีดล่าง", - 'regex' => "ประกอบด้วยอักขระที่ไม่ถูกต้อง", - 'date' => "ไม่ใช่วันที่ที่ถูกต้อง", - 'dateFormat' => "จะต้องเป็นวันที่ที่มีรูปแบบ '%s'", - 'dateBefore' => "จะต้องเป็นวันที่ก่อน '%s'", - 'dateAfter' => "จะต้องเป็นวันที่หลังจาก '%s'", - 'contains' => "จะต้องประกอบไปด้วย %s", - 'boolean' => "จะต้องเป็นใช่ หรือ ไม่ใช่", - 'lengthBetween' => "จะต้องอยู่ระหว่าง %d ถึง %d ตัวอักษร", - 'creditCard' => "จะต้องเป็นหมายเลขบัตรเครดิตที่ถูกต้อง", - "lengthMin" => "จะต้องมีความยาวมากกว่า %d ตัวอักษร", - "lengthMax" => "จะต้องมีความยาวน้อยกว่า %d ตัวอักษร", - "instanceOf" => "จะต้องเป็นกรณีของ '%s'" -); + "ต้องการ", + 'equals' => "จะต้องเหมือนกับ '%s'", + 'different' => "จะต้องไม่ใช่ '%s'", + 'accepted' => "จะต้องยอมรับ", + 'numeric' => "จะต้องเป็นตัวเลข", + 'integer' => "จะต้องเป็นตัวเลขหลักเดียว (0-9)", + 'length' => "จะต้องมีความยาวมากกว่า %d", + 'min' => "จะต้องมีอย่างน้อย %s", + 'max' => "จะต้องมีไม่มากไปกว่า %s", + 'in' => "ประกอบด้วยค่าที่ไม่ถูกต้อง", + 'notIn' => "ประกอบด้วยค่าที่ไม่ถูกต้อง", + 'ip' => "ไม่ใช่ที่อยู่ไอพีที่ถูกต้อง", + 'email' => "ไม่ใช่ที่อยู่อีเมลที่ถูกต้อง", + 'url' => "ไม่ใช่ลิงก์", + 'urlActive' => "จะต้องเป็นโดเมนที่มีการใช้งานอยู่", + 'alpha' => "จะต้องประกอบไปด้วยตัวอักษร a-z เท่านั้น", + 'alphaNum' => "จะต้องประกอบไปด้วยตัวอักษร a-z และ/หรือ เลข 0-9", + 'slug' => "จะต้องประกอบไปด้วยตัวอักษร a-z เลข 0-9 ขีดกลาง และขีดล่าง", + 'regex' => "ประกอบด้วยอักขระที่ไม่ถูกต้อง", + 'date' => "ไม่ใช่วันที่ที่ถูกต้อง", + 'dateFormat' => "จะต้องเป็นวันที่ที่มีรูปแบบ '%s'", + 'dateBefore' => "จะต้องเป็นวันที่ก่อน '%s'", + 'dateAfter' => "จะต้องเป็นวันที่หลังจาก '%s'", + 'contains' => "จะต้องประกอบไปด้วย %s", + 'boolean' => "จะต้องเป็นใช่ หรือ ไม่ใช่", + 'lengthBetween' => "จะต้องอยู่ระหว่าง %d ถึง %d ตัวอักษร", + 'creditCard' => "จะต้องเป็นหมายเลขบัตรเครดิตที่ถูกต้อง", + "lengthMin" => "จะต้องมีความยาวมากกว่า %d ตัวอักษร", + "lengthMax" => "จะต้องมีความยาวน้อยกว่า %d ตัวอักษร", + "instanceOf" => "จะต้องเป็นกรณีของ '%s'" +); diff --git a/main/app/sprinkles/core/locale/valitron/zh-cn.php b/main/app/sprinkles/core/locale/valitron/zh-cn.php index 367ddac..9f2d0dd 100644 --- a/main/app/sprinkles/core/locale/valitron/zh-cn.php +++ b/main/app/sprinkles/core/locale/valitron/zh-cn.php @@ -1,28 +1,28 @@ - "不能为空", - 'equals' => "必须和 '%s' 一致", - 'different' => "必须和 '%s' 不一致", - 'accepted' => "必须接受", - 'numeric' => "只能是数字", - 'integer' => "只能是整数(0-9)", - 'length' => "长度必须大于 %d", - 'min' => "必须大于 %s", - 'max' => "必须小于 %s", - 'in' => "无效的值", - 'notIn' => "无效的值", - 'ip' => "无效IP地址", - 'email' => "无效邮箱地址", - 'url' => "无效的URL", - 'urlActive' => "必须是可用的域名", - 'alpha' => "只能包括英文字母(a-z)", - 'alphaNum' => "只能包括英文字母(a-z)和数字(0-9)", - 'slug' => "只能包括英文字母(a-z)、数字(0-9)、破折号和下划线", - 'regex' => "无效格式", - 'date' => "无效的日期", - 'dateFormat' => "日期的格式应该为 '%s'", - 'dateBefore' => "日期必须在 '%s' 之前", - 'dateAfter' => "日期必须在 '%s' 之后", - 'contains' => "必须包含 %s" -); + "不能为空", + 'equals' => "必须和 '%s' 一致", + 'different' => "必须和 '%s' 不一致", + 'accepted' => "必须接受", + 'numeric' => "只能是数字", + 'integer' => "只能是整数(0-9)", + 'length' => "长度必须大于 %d", + 'min' => "必须大于 %s", + 'max' => "必须小于 %s", + 'in' => "无效的值", + 'notIn' => "无效的值", + 'ip' => "无效IP地址", + 'email' => "无效邮箱地址", + 'url' => "无效的URL", + 'urlActive' => "必须是可用的域名", + 'alpha' => "只能包括英文字母(a-z)", + 'alphaNum' => "只能包括英文字母(a-z)和数字(0-9)", + 'slug' => "只能包括英文字母(a-z)、数字(0-9)、破折号和下划线", + 'regex' => "无效格式", + 'date' => "无效的日期", + 'dateFormat' => "日期的格式应该为 '%s'", + 'dateBefore' => "日期必须在 '%s' 之前", + 'dateAfter' => "日期必须在 '%s' 之后", + 'contains' => "必须包含 %s" +); diff --git a/main/app/sprinkles/core/locale/valitron/zh-tw.php b/main/app/sprinkles/core/locale/valitron/zh-tw.php index b8135a0..af098c9 100644 --- a/main/app/sprinkles/core/locale/valitron/zh-tw.php +++ b/main/app/sprinkles/core/locale/valitron/zh-tw.php @@ -1,28 +1,28 @@ - "不能為空", - 'equals' => "必須和 '%s' 一致", - 'different' => "必須和 '%s' 不一致", - 'accepted' => "必須接受", - 'numeric' => "只能是數字", - 'integer' => "只能是整數(0-9)", - 'length' => "長度必須大於 %d", - 'min' => "必須大於 %s", - 'max' => "必須小於 %s", - 'in' => "無效的值", - 'notIn' => "無效的值", - 'ip' => "無效IP地址", - 'email' => "無效郵箱地址", - 'url' => "無效的URL", - 'urlActive' => "必須是可用的域名", - 'alpha' => "只能包括英文字母(a-z)", - 'alphaNum' => "只能包括英文字母(a-z)和數字(0-9)", - 'slug' => "只能包括英文字母(a-z)、數字(0-9)、破折號和下劃線", - 'regex' => "無效格式", - 'date' => "無效的日期", - 'dateFormat' => "日期的格式應該為 '%s'", - 'dateBefore' => "日期必須在 '%s' 之前", - 'dateAfter' => "日期必須在 '%s' 之後", - 'contains' => "必須包含 %s" -); + "不能為空", + 'equals' => "必須和 '%s' 一致", + 'different' => "必須和 '%s' 不一致", + 'accepted' => "必須接受", + 'numeric' => "只能是數字", + 'integer' => "只能是整數(0-9)", + 'length' => "長度必須大於 %d", + 'min' => "必須大於 %s", + 'max' => "必須小於 %s", + 'in' => "無效的值", + 'notIn' => "無效的值", + 'ip' => "無效IP地址", + 'email' => "無效郵箱地址", + 'url' => "無效的URL", + 'urlActive' => "必須是可用的域名", + 'alpha' => "只能包括英文字母(a-z)", + 'alphaNum' => "只能包括英文字母(a-z)和數字(0-9)", + 'slug' => "只能包括英文字母(a-z)、數字(0-9)、破折號和下劃線", + 'regex' => "無效格式", + 'date' => "無效的日期", + 'dateFormat' => "日期的格式應該為 '%s'", + 'dateBefore' => "日期必須在 '%s' 之前", + 'dateAfter' => "日期必須在 '%s' 之後", + 'contains' => "必須包含 %s" +); diff --git a/main/app/sprinkles/core/locale/zh_CN/messages.php b/main/app/sprinkles/core/locale/zh_CN/messages.php index 8ebab81..409ede0 100644 --- a/main/app/sprinkles/core/locale/zh_CN/messages.php +++ b/main/app/sprinkles/core/locale/zh_CN/messages.php @@ -1,105 +1,105 @@ - 0, - - "ABOUT" => "关于", - - "CAPTCHA" => [ - "@TRANSLATION" => "验证码", - "FAIL" => "Y验证码输入错误.", - "SPECIFY" => "输入验证码", - "VERIFY" => "验证" - ], - - "CSRF_MISSING" => " CSRF 标记丢失. 请尝试重新加载页面?", - - "DB_INVALID" => "无法连接到数据库. 如果你是管理员, 请检查错误日志文件.", - "DESCRIPTION" => "描述", - "DOWNLOAD" => [ - "@TRANSLATION" => "下载", - "CSV" => "下载 CSV 文件" - ], - - "EMAIL" => [ - "@TRANSLATION" => "邮件", - "YOUR" => "你的邮件地址" - ], - - "HOME" => "首页", - - "LEGAL" => "法律政策", - - "LOCALE" => [ - "@TRANSLATION" => "本地" - ], - - "MAIL_ERROR" => "尝试发送邮件发送致命错误, 联系网站管理员. 如果你是管理员,请检查UF邮件错误日志.", - - "NAME" => "名字", - "NAVIGATION" => "导航", - - "PAGINATION" => [ - "GOTO" => "跳到页", - "SHOW" => "显示" - ], - "PRIVACY" => "隐私政策", - - "SLUG" => "Slug", - "SLUG_CONDITION" => "Slug/Conditions", - "SLUG_IN_USE" => "A {{slug}} slug already exists", - "STATUS" => "状态", - "SUGGEST" => "建议", - - "UNKNOWN" => "未知", - - // Actions words - "ACTIONS" => "动作", - "ACTIVATE" => "激活", - "ACTIVE" => "Active", - "ADD" => "添加", - "CANCEL" => "取消", - "CONFIRM" => "确认", - "CREATE" => "创建", - "DELETE" => "删除", - "DELETE_CONFIRM" => "你确定要删除这个?", - "DELETE_CONFIRM_YES" => "是的, 删除", - "DELETE_CONFIRM_NAMED" => "你确定要删除 {{name}}?", - "DELETE_CONFIRM_YES_NAMED" => "是的, 删除 {{name}}", - "DELETE_CANNOT_UNDONE" => "这个动作无法撤销.", - "DELETE_NAMED" => "删除 {{name}}", - "DENY" => "拒绝", - "DISABLE" => "禁用", - "DISABLED" => "禁用", - "EDIT" => "编辑", - "ENABLE" => "启用", - "ENABLED" => "启用", - "OVERRIDE" => "覆盖", - "RESET" => "重置", - "SAVE" => "保存", - "SEARCH" => "搜寻", - "SORT" => "排序", - "SUBMIT" => "提交", - "PRINT" => "打印", - "REMOVE" => "删除", - "UNACTIVATED" => "未激活", - "UPDATE" => "更新", - "YES" => "是", - "NO" => "不是", - "OPTIONAL" => "可选择的", - - // Misc. - "BUILT_WITH_UF" => "使用 UserFrosting", - "ADMINLTE_THEME_BY" => "主题作者 Almsaeed Studio.保留所有权" -]; + 0, + + "ABOUT" => "关于", + + "CAPTCHA" => [ + "@TRANSLATION" => "验证码", + "FAIL" => "Y验证码输入错误.", + "SPECIFY" => "输入验证码", + "VERIFY" => "验证" + ], + + "CSRF_MISSING" => " CSRF 标记丢失. 请尝试重新加载页面?", + + "DB_INVALID" => "无法连接到数据库. 如果你是管理员, 请检查错误日志文件.", + "DESCRIPTION" => "描述", + "DOWNLOAD" => [ + "@TRANSLATION" => "下载", + "CSV" => "下载 CSV 文件" + ], + + "EMAIL" => [ + "@TRANSLATION" => "邮件", + "YOUR" => "你的邮件地址" + ], + + "HOME" => "首页", + + "LEGAL" => "法律政策", + + "LOCALE" => [ + "@TRANSLATION" => "本地" + ], + + "MAIL_ERROR" => "尝试发送邮件发送致命错误, 联系网站管理员. 如果你是管理员,请检查UF邮件错误日志.", + + "NAME" => "名字", + "NAVIGATION" => "导航", + + "PAGINATION" => [ + "GOTO" => "跳到页", + "SHOW" => "显示" + ], + "PRIVACY" => "隐私政策", + + "SLUG" => "Slug", + "SLUG_CONDITION" => "Slug/Conditions", + "SLUG_IN_USE" => "A {{slug}} slug already exists", + "STATUS" => "状态", + "SUGGEST" => "建议", + + "UNKNOWN" => "未知", + + // Actions words + "ACTIONS" => "动作", + "ACTIVATE" => "激活", + "ACTIVE" => "Active", + "ADD" => "添加", + "CANCEL" => "取消", + "CONFIRM" => "确认", + "CREATE" => "创建", + "DELETE" => "删除", + "DELETE_CONFIRM" => "你确定要删除这个?", + "DELETE_CONFIRM_YES" => "是的, 删除", + "DELETE_CONFIRM_NAMED" => "你确定要删除 {{name}}?", + "DELETE_CONFIRM_YES_NAMED" => "是的, 删除 {{name}}", + "DELETE_CANNOT_UNDONE" => "这个动作无法撤销.", + "DELETE_NAMED" => "删除 {{name}}", + "DENY" => "拒绝", + "DISABLE" => "禁用", + "DISABLED" => "禁用", + "EDIT" => "编辑", + "ENABLE" => "启用", + "ENABLED" => "启用", + "OVERRIDE" => "覆盖", + "RESET" => "重置", + "SAVE" => "保存", + "SEARCH" => "搜寻", + "SORT" => "排序", + "SUBMIT" => "提交", + "PRINT" => "打印", + "REMOVE" => "删除", + "UNACTIVATED" => "未激活", + "UPDATE" => "更新", + "YES" => "是", + "NO" => "不是", + "OPTIONAL" => "可选择的", + + // Misc. + "BUILT_WITH_UF" => "使用 UserFrosting", + "ADMINLTE_THEME_BY" => "主题作者 Almsaeed Studio.保留所有权" +]; diff --git a/main/app/sprinkles/core/locale/zh_CN/validate.php b/main/app/sprinkles/core/locale/zh_CN/validate.php index f4b3ed8..d19910b 100644 --- a/main/app/sprinkles/core/locale/zh_CN/validate.php +++ b/main/app/sprinkles/core/locale/zh_CN/validate.php @@ -1,29 +1,29 @@ - [ - "ARRAY" => " {{label}} 的值必须在一个数组中.", - "BOOLEAN" => " {{label}} 的值必须是 '0' 或 '1'.", - "INTEGER" => " {{label}} 必须是整数.", - "INVALID_EMAIL" => "无效的邮箱地址.", - "LENGTH_RANGE" => "{{label}} 的长度必须在 {{min}} - {{max}} 之间.", - "NO_LEAD_WS" => "{{label}} 的值不能以空格、TAB或其他空白开始.", - "NO_TRAIL_WS" => " {{label}} 的值不能以空格、TAB或其他空白结束.", - "REQUIRED" => "请为 {{label}} 确定一个值.", - "SPRUNJE" => [ - "BAD_FILTER" => "{{name}} 不是一个有效的 Sprunje 过滤器.", - "BAD_SORT" => "{{name}} 不是一个有效的 Sprunje 排序." - ] - ] -]; + [ + "ARRAY" => " {{label}} 的值必须在一个数组中.", + "BOOLEAN" => " {{label}} 的值必须是 '0' 或 '1'.", + "INTEGER" => " {{label}} 必须是整数.", + "INVALID_EMAIL" => "无效的邮箱地址.", + "LENGTH_RANGE" => "{{label}} 的长度必须在 {{min}} - {{max}} 之间.", + "NO_LEAD_WS" => "{{label}} 的值不能以空格、TAB或其他空白开始.", + "NO_TRAIL_WS" => " {{label}} 的值不能以空格、TAB或其他空白结束.", + "REQUIRED" => "请为 {{label}} 确定一个值.", + "SPRUNJE" => [ + "BAD_FILTER" => "{{name}} 不是一个有效的 Sprunje 过滤器.", + "BAD_SORT" => "{{name}} 不是一个有效的 Sprunje 排序." + ] + ] +]; diff --git a/main/app/sprinkles/core/routes/routes.php b/main/app/sprinkles/core/routes/routes.php index 9b8c7db..1d0307c 100644 --- a/main/app/sprinkles/core/routes/routes.php +++ b/main/app/sprinkles/core/routes/routes.php @@ -1,27 +1,27 @@ -getContainer()->get('config'); - -$app->get('/', 'UserFrosting\Sprinkle\Core\Controller\CoreController:pageIndex') - ->add('checkEnvironment') - ->add('authGuard') - ->setName('index'); - -$app->get('/test', 'UserFrosting\Sprinkle\Core\Controller\CoreController:pageTest'); - -$app->get('/about', 'UserFrosting\Sprinkle\Core\Controller\CoreController:pageAbout')->add('checkEnvironment'); - -$app->get('/alerts', 'UserFrosting\Sprinkle\Core\Controller\CoreController:jsonAlerts'); - -$app->get('/legal', 'UserFrosting\Sprinkle\Core\Controller\CoreController:pageLegal'); - -$app->get('/privacy', 'UserFrosting\Sprinkle\Core\Controller\CoreController:pagePrivacy'); - -$app->get('/' . $config['assets.raw.path'] . '/{url:.+}', 'UserFrosting\Sprinkle\Core\Controller\CoreController:getAsset'); +getContainer()->get('config'); + +$app->get('/', 'UserFrosting\Sprinkle\Core\Controller\CoreController:pageIndex') + ->add('checkEnvironment') + ->add('authGuard') + ->setName('index'); + +$app->get('/test', 'UserFrosting\Sprinkle\Core\Controller\CoreController:pageTest'); + +$app->get('/about', 'UserFrosting\Sprinkle\Core\Controller\CoreController:pageAbout')->add('checkEnvironment'); + +$app->get('/alerts', 'UserFrosting\Sprinkle\Core\Controller\CoreController:jsonAlerts'); + +$app->get('/legal', 'UserFrosting\Sprinkle\Core\Controller\CoreController:pageLegal'); + +$app->get('/privacy', 'UserFrosting\Sprinkle\Core\Controller\CoreController:pagePrivacy'); + +$app->get('/' . $config['assets.raw.path'] . '/{url:.+}', 'UserFrosting\Sprinkle\Core\Controller\CoreController:getAsset'); diff --git a/main/app/sprinkles/core/src/Alert/AlertStream.php b/main/app/sprinkles/core/src/Alert/AlertStream.php index adb9b5b..2db441f 100644 --- a/main/app/sprinkles/core/src/Alert/AlertStream.php +++ b/main/app/sprinkles/core/src/Alert/AlertStream.php @@ -1,138 +1,138 @@ -messagesKey = $messagesKey; - - $this->setTranslator($translator); - } - - /** - * Set the translator to be used for all message streams. Must be done before `addMessageTranslated` can be used. - * - * @param UserFrosting\I18n\MessageTranslator $translator A MessageTranslator to be used to translate messages when added via `addMessageTranslated`. - */ - public function setTranslator($translator) { - $this->messageTranslator = $translator; - return $this; - } - - /** - * Adds a raw text message to the cache message stream. - * - * @param string $type The type of message, indicating how it will be styled when outputted. Should be set to "success", "danger", "warning", or "info". - * @param string $message The message to be added to the message stream. - * @return MessageStream this MessageStream object. - */ - public function addMessage($type, $message) { - $messages = $this->messages(); - $messages[] = array( - "type" => $type, - "message" => $message - ); - $this->saveMessages($messages); - return $this; - } - - /** - * Adds a text message to the cache message stream, translated into the currently selected language. - * - * @param string $type The type of message, indicating how it will be styled when outputted. Should be set to "success", "danger", "warning", or "info". - * @param string $messageId The message id for the message to be added to the message stream. - * @param array[string] $placeholders An optional hash of placeholder names => placeholder values to substitute into the translated message. - * @return MessageStream this MessageStream object. - */ - public function addMessageTranslated($type, $messageId, $placeholders = array()) { - if (!$this->messageTranslator) { - throw new \RuntimeException("No translator has been set! Please call MessageStream::setTranslator first."); - } - - $message = $this->messageTranslator->translate($messageId, $placeholders); - return $this->addMessage($type, $message); - } - - /** - * Get the messages and then clear the message stream. - * This function does the same thing as `messages()`, except that it also clears all messages afterwards. - * This is useful, because typically we don't want to view the same messages more than once. - * - * @return array An array of messages, each of which is itself an array containing "type" and "message" fields. - */ - public function getAndClearMessages() { - $messages = $this->messages(); - $this->resetMessageStream(); - return $messages; - } - - /** - * Add error messages from a ServerSideValidator object to the message stream. - * - * @param ServerSideValidator $validator - */ - public function addValidationErrors(ServerSideValidator $validator) { - foreach ($validator->errors() as $idx => $field) { - foreach ($field as $eidx => $error) { - $this->addMessage("danger", $error); - } - } - } - - /** - * Return the translator for this message stream. - * - * @return MessageTranslator The translator for this message stream. - */ - public function translator() { - return $this->messageTranslator; - } - - /** - * Get the messages from this message stream. - * - * @return array An array of messages, each of which is itself an array containing "type" and "message" fields. - */ - abstract public function messages(); - - /** - * Clear all messages from this message stream. - */ - abstract public function resetMessageStream(); - - /** - * Save messages to the stream - */ - abstract protected function saveMessages($message); -} +messagesKey = $messagesKey; + + $this->setTranslator($translator); + } + + /** + * Set the translator to be used for all message streams. Must be done before `addMessageTranslated` can be used. + * + * @param UserFrosting\I18n\MessageTranslator $translator A MessageTranslator to be used to translate messages when added via `addMessageTranslated`. + */ + public function setTranslator($translator) { + $this->messageTranslator = $translator; + return $this; + } + + /** + * Adds a raw text message to the cache message stream. + * + * @param string $type The type of message, indicating how it will be styled when outputted. Should be set to "success", "danger", "warning", or "info". + * @param string $message The message to be added to the message stream. + * @return MessageStream this MessageStream object. + */ + public function addMessage($type, $message) { + $messages = $this->messages(); + $messages[] = array( + "type" => $type, + "message" => $message + ); + $this->saveMessages($messages); + return $this; + } + + /** + * Adds a text message to the cache message stream, translated into the currently selected language. + * + * @param string $type The type of message, indicating how it will be styled when outputted. Should be set to "success", "danger", "warning", or "info". + * @param string $messageId The message id for the message to be added to the message stream. + * @param array[string] $placeholders An optional hash of placeholder names => placeholder values to substitute into the translated message. + * @return MessageStream this MessageStream object. + */ + public function addMessageTranslated($type, $messageId, $placeholders = array()) { + if (!$this->messageTranslator) { + throw new \RuntimeException("No translator has been set! Please call MessageStream::setTranslator first."); + } + + $message = $this->messageTranslator->translate($messageId, $placeholders); + return $this->addMessage($type, $message); + } + + /** + * Get the messages and then clear the message stream. + * This function does the same thing as `messages()`, except that it also clears all messages afterwards. + * This is useful, because typically we don't want to view the same messages more than once. + * + * @return array An array of messages, each of which is itself an array containing "type" and "message" fields. + */ + public function getAndClearMessages() { + $messages = $this->messages(); + $this->resetMessageStream(); + return $messages; + } + + /** + * Add error messages from a ServerSideValidator object to the message stream. + * + * @param ServerSideValidator $validator + */ + public function addValidationErrors(ServerSideValidator $validator) { + foreach ($validator->errors() as $idx => $field) { + foreach ($field as $eidx => $error) { + $this->addMessage("danger", $error); + } + } + } + + /** + * Return the translator for this message stream. + * + * @return MessageTranslator The translator for this message stream. + */ + public function translator() { + return $this->messageTranslator; + } + + /** + * Get the messages from this message stream. + * + * @return array An array of messages, each of which is itself an array containing "type" and "message" fields. + */ + abstract public function messages(); + + /** + * Clear all messages from this message stream. + */ + abstract public function resetMessageStream(); + + /** + * Save messages to the stream + */ + abstract protected function saveMessages($message); +} diff --git a/main/app/sprinkles/core/src/Alert/CacheAlertStream.php b/main/app/sprinkles/core/src/Alert/CacheAlertStream.php index f3f6489..8d31462 100644 --- a/main/app/sprinkles/core/src/Alert/CacheAlertStream.php +++ b/main/app/sprinkles/core/src/Alert/CacheAlertStream.php @@ -1,81 +1,81 @@ -cache = $cache; - $this->config = $config; - parent::__construct($messagesKey, $translator); - } - - /** - * Get the messages from this message stream. - * - * @return array An array of messages, each of which is itself an array containing 'type' and 'message' fields. - */ - public function messages() { - if ($this->cache->tags('_s' . session_id())->has($this->messagesKey)) { - return $this->cache->tags('_s' . session_id())->get($this->messagesKey) ?: []; - } else { - return []; - } - } - - /** - * Clear all messages from this message stream. - * - * @return void - */ - public function resetMessageStream() { - $this->cache->tags('_s' . session_id())->forget($this->messagesKey); - } - - /** - * Save messages to the stream - * - * @param string $messages The message - * @return void - */ - protected function saveMessages($messages) { - $this->cache->tags('_s' . session_id())->forever($this->messagesKey, $messages); - } -} +cache = $cache; + $this->config = $config; + parent::__construct($messagesKey, $translator); + } + + /** + * Get the messages from this message stream. + * + * @return array An array of messages, each of which is itself an array containing 'type' and 'message' fields. + */ + public function messages() { + if ($this->cache->tags('_s' . session_id())->has($this->messagesKey)) { + return $this->cache->tags('_s' . session_id())->get($this->messagesKey) ?: []; + } else { + return []; + } + } + + /** + * Clear all messages from this message stream. + * + * @return void + */ + public function resetMessageStream() { + $this->cache->tags('_s' . session_id())->forget($this->messagesKey); + } + + /** + * Save messages to the stream + * + * @param string $messages The message + * @return void + */ + protected function saveMessages($messages) { + $this->cache->tags('_s' . session_id())->forever($this->messagesKey, $messages); + } +} diff --git a/main/app/sprinkles/core/src/Alert/SessionAlertStream.php b/main/app/sprinkles/core/src/Alert/SessionAlertStream.php index fec0973..47a7ff7 100644 --- a/main/app/sprinkles/core/src/Alert/SessionAlertStream.php +++ b/main/app/sprinkles/core/src/Alert/SessionAlertStream.php @@ -1,67 +1,67 @@ -session = $session; - parent::__construct($messagesKey, $translator); - } - - /** - * Get the messages from this message stream. - * - * @return array An array of messages, each of which is itself an array containing "type" and "message" fields. - */ - public function messages() { - return $this->session[$this->messagesKey] ?: []; - } - - /** - * Clear all messages from this message stream. - * - * @return void - */ - public function resetMessageStream() { - $this->session[$this->messagesKey] = []; - } - - /** - * Save messages to the stream - * - * @param string $messages The message - * @return void - */ - protected function saveMessages($messages) { - $this->session[$this->messagesKey] = $messages; - } -} +session = $session; + parent::__construct($messagesKey, $translator); + } + + /** + * Get the messages from this message stream. + * + * @return array An array of messages, each of which is itself an array containing "type" and "message" fields. + */ + public function messages() { + return $this->session[$this->messagesKey] ?: []; + } + + /** + * Clear all messages from this message stream. + * + * @return void + */ + public function resetMessageStream() { + $this->session[$this->messagesKey] = []; + } + + /** + * Save messages to the stream + * + * @param string $messages The message + * @return void + */ + protected function saveMessages($messages) { + $this->session[$this->messagesKey] = $messages; + } +} diff --git a/main/app/sprinkles/core/src/Controller/SimpleController.php b/main/app/sprinkles/core/src/Controller/SimpleController.php index 1e3303a..1e5c45a 100644 --- a/main/app/sprinkles/core/src/Controller/SimpleController.php +++ b/main/app/sprinkles/core/src/Controller/SimpleController.php @@ -1,36 +1,36 @@ -ci = $ci; - } -} +ci = $ci; + } +} diff --git a/main/app/sprinkles/core/src/Core.php b/main/app/sprinkles/core/src/Core.php index 9518fe2..6bf1e36 100644 --- a/main/app/sprinkles/core/src/Core.php +++ b/main/app/sprinkles/core/src/Core.php @@ -1,118 +1,118 @@ - ['onSprinklesInitialized', 0], - 'onSprinklesRegisterServices' => ['onSprinklesRegisterServices', 0], - 'onAddGlobalMiddleware' => ['onAddGlobalMiddleware', 0] - ]; - } - - /** - * Set static references to DI container in necessary classes. - */ - public function onSprinklesInitialized() { - // Set container for data model - Model::$ci = $this->ci; - - // Set container for environment info class - EnvironmentInfo::$ci = $this->ci; - } - - /** - * Get shutdownHandler set up. This needs to be constructed explicitly because it's invoked natively by PHP. - */ - public function onSprinklesRegisterServices() { - // Set up any global PHP settings from the config service. - $config = $this->ci->config; - - // Display PHP fatal errors natively. - if (isset($config['php.display_errors_native'])) { - ini_set('display_errors', $config['php.display_errors_native']); - } - - // Log PHP fatal errors - if (isset($config['php.log_errors'])) { - ini_set('log_errors', $config['php.log_errors']); - } - - // Configure error-reporting level - if (isset($config['php.error_reporting'])) { - error_reporting($config['php.error_reporting']); - } - - // Configure time zone - if (isset($config['php.timezone'])) { - date_default_timezone_set($config['php.timezone']); - } - - // Determine if error display is enabled in the shutdown handler. - $displayErrors = FALSE; - if (in_array(strtolower($config['php.display_errors']), [ - '1', - 'on', - 'true', - 'yes' - ])) { - $displayErrors = TRUE; - } - - $sh = new ShutdownHandler($this->ci, $displayErrors); - $sh->register(); - } - - /** - * Add CSRF middleware. - */ - public function onAddGlobalMiddleware(Event $event) { - $request = $this->ci->request; - $path = $request->getUri()->getPath(); - $method = $request->getMethod(); - - // Normalize path to always have a leading slash - $path = '/' . ltrim($path, '/'); - // Normalize method to uppercase - $method = strtoupper($method); - - $csrfBlacklist = $this->ci->config['csrf.blacklist']; - $isBlacklisted = FALSE; - - // Go through the blacklist and determine if the path and method match any of the blacklist entries. - foreach ($csrfBlacklist as $pattern => $methods) { - $methods = array_map('strtoupper', (array)$methods); - if (in_array($method, $methods) && $pattern != '' && preg_match('~' . $pattern . '~', $path)) { - $isBlacklisted = TRUE; - break; - } - } - - if (!$path || !$isBlacklisted) { - $app = $event->getApp(); - $app->add($this->ci->csrf); - } - } -} + ['onSprinklesInitialized', 0], + 'onSprinklesRegisterServices' => ['onSprinklesRegisterServices', 0], + 'onAddGlobalMiddleware' => ['onAddGlobalMiddleware', 0] + ]; + } + + /** + * Set static references to DI container in necessary classes. + */ + public function onSprinklesInitialized() { + // Set container for data model + Model::$ci = $this->ci; + + // Set container for environment info class + EnvironmentInfo::$ci = $this->ci; + } + + /** + * Get shutdownHandler set up. This needs to be constructed explicitly because it's invoked natively by PHP. + */ + public function onSprinklesRegisterServices() { + // Set up any global PHP settings from the config service. + $config = $this->ci->config; + + // Display PHP fatal errors natively. + if (isset($config['php.display_errors_native'])) { + ini_set('display_errors', $config['php.display_errors_native']); + } + + // Log PHP fatal errors + if (isset($config['php.log_errors'])) { + ini_set('log_errors', $config['php.log_errors']); + } + + // Configure error-reporting level + if (isset($config['php.error_reporting'])) { + error_reporting($config['php.error_reporting']); + } + + // Configure time zone + if (isset($config['php.timezone'])) { + date_default_timezone_set($config['php.timezone']); + } + + // Determine if error display is enabled in the shutdown handler. + $displayErrors = FALSE; + if (in_array(strtolower($config['php.display_errors']), [ + '1', + 'on', + 'true', + 'yes' + ])) { + $displayErrors = TRUE; + } + + $sh = new ShutdownHandler($this->ci, $displayErrors); + $sh->register(); + } + + /** + * Add CSRF middleware. + */ + public function onAddGlobalMiddleware(Event $event) { + $request = $this->ci->request; + $path = $request->getUri()->getPath(); + $method = $request->getMethod(); + + // Normalize path to always have a leading slash + $path = '/' . ltrim($path, '/'); + // Normalize method to uppercase + $method = strtoupper($method); + + $csrfBlacklist = $this->ci->config['csrf.blacklist']; + $isBlacklisted = FALSE; + + // Go through the blacklist and determine if the path and method match any of the blacklist entries. + foreach ($csrfBlacklist as $pattern => $methods) { + $methods = array_map('strtoupper', (array)$methods); + if (in_array($method, $methods) && $pattern != '' && preg_match('~' . $pattern . '~', $path)) { + $isBlacklisted = TRUE; + break; + } + } + + if (!$path || !$isBlacklisted) { + $app = $event->getApp(); + $app->add($this->ci->csrf); + } + } +} diff --git a/main/app/sprinkles/core/src/Database/Builder.php b/main/app/sprinkles/core/src/Database/Builder.php index cebc318..1ed26ff 100644 --- a/main/app/sprinkles/core/src/Database/Builder.php +++ b/main/app/sprinkles/core/src/Database/Builder.php @@ -1,200 +1,200 @@ -where($field, 'LIKE', "$value%"); - } - - /** - * Perform an "ends with" pattern match on a specified column in a query. - * - * @param $query - * @param $field string The column to match - * @param $value string The value to match - */ - public function endsWith($field, $value) { - return $this->where($field, 'LIKE', "%$value"); - } - - /** - * Add columns to be excluded from the query. - * - * @param $value array|string The column(s) to exclude - * @return $this - */ - public function exclude($column) { - $column = is_array($column) ? $column : func_get_args(); - - $this->excludedColumns = array_merge((array)$this->excludedColumns, $column); - - return $this; - } - - /** - * Perform a pattern match on a specified column in a query. - * @param $query - * @param $field string The column to match - * @param $value string The value to match - */ - public function like($field, $value) { - return $this->where($field, 'LIKE', "%$value%"); - } - - /** - * Perform a pattern match on a specified column in a query. - * @param $query - * @param $field string The column to match - * @param $value string The value to match - */ - public function orLike($field, $value) { - return $this->orWhere($field, 'LIKE', "%$value%"); - } - - /** - * Execute the query as a "select" statement. - * - * @param array $columns - * @return \Illuminate\Support\Collection - */ - public function get($columns = ['*']) { - $original = $this->columns; - - if (is_null($original)) { - $this->columns = $columns; - } - - // Exclude any explicitly excluded columns - if (!is_null($this->excludedColumns)) { - $this->removeExcludedSelectColumns(); - } - - $results = $this->processor->processSelect($this, $this->runSelect()); - - $this->columns = $original; - - return collect($results); - } - - /** - * Remove excluded columns from the select column list. - */ - protected function removeExcludedSelectColumns() { - // Convert current column list and excluded column list to fully-qualified list - $this->columns = $this->convertColumnsToFullyQualified($this->columns); - $excludedColumns = $this->convertColumnsToFullyQualified($this->excludedColumns); - - // Remove any explicitly referenced excludable columns - $this->columns = array_diff($this->columns, $excludedColumns); - - // Replace any remaining wildcard columns (*, table.*, etc) with a list - // of fully-qualified column names - $this->columns = $this->replaceWildcardColumns($this->columns); - - $this->columns = array_diff($this->columns, $excludedColumns); - } - - /** - * Find any wildcard columns ('*'), remove it from the column list and replace with an explicit list of columns. - * - * @param array $columns - * @return array - */ - protected function replaceWildcardColumns(array $columns) { - $wildcardTables = $this->findWildcardTables($columns); - - foreach ($wildcardTables as $wildColumn => $table) { - $schemaColumns = $this->getQualifiedColumnNames($table); - - // Remove the `*` or `.*` column and replace with the individual schema columns - $columns = array_diff($columns, [$wildColumn]); - $columns = array_merge($columns, $schemaColumns); - } - - return $columns; - } - - /** - * Return a list of wildcard columns from the list of columns, mapping columns to their corresponding tables. - * - * @param array $columns - * @return array - */ - protected function findWildcardTables(array $columns) { - $tables = []; - - foreach ($columns as $column) { - if ($column == '*') { - $tables[$column] = $this->from; - continue; - } - - if (substr($column, -1) == '*') { - $tableName = explode('.', $column)[0]; - if ($tableName) { - $tables[$column] = $tableName; - } - } - } - - return $tables; - } - - /** - * Gets the fully qualified column names for a specified table. - * - * @param string $table - * @return array - */ - protected function getQualifiedColumnNames($table = NULL) { - $schema = $this->getConnection()->getSchemaBuilder(); - - return $this->convertColumnsToFullyQualified($schema->getColumnListing($table), $table); - } - - /** - * Fully qualify any unqualified columns in a list with this builder's table name. - * - * @param array $columns - * @return array - */ - protected function convertColumnsToFullyQualified($columns, $table = NULL) { - if (is_null($table)) { - $table = $this->from; - } - - array_walk($columns, function (&$item, $key) use ($table) { - if (strpos($item, '.') === FALSE) { - $item = "$table.$item"; - } - }); - - return $columns; - } -} +where($field, 'LIKE', "$value%"); + } + + /** + * Perform an "ends with" pattern match on a specified column in a query. + * + * @param $query + * @param $field string The column to match + * @param $value string The value to match + */ + public function endsWith($field, $value) { + return $this->where($field, 'LIKE', "%$value"); + } + + /** + * Add columns to be excluded from the query. + * + * @param $value array|string The column(s) to exclude + * @return $this + */ + public function exclude($column) { + $column = is_array($column) ? $column : func_get_args(); + + $this->excludedColumns = array_merge((array)$this->excludedColumns, $column); + + return $this; + } + + /** + * Perform a pattern match on a specified column in a query. + * @param $query + * @param $field string The column to match + * @param $value string The value to match + */ + public function like($field, $value) { + return $this->where($field, 'LIKE', "%$value%"); + } + + /** + * Perform a pattern match on a specified column in a query. + * @param $query + * @param $field string The column to match + * @param $value string The value to match + */ + public function orLike($field, $value) { + return $this->orWhere($field, 'LIKE', "%$value%"); + } + + /** + * Execute the query as a "select" statement. + * + * @param array $columns + * @return \Illuminate\Support\Collection + */ + public function get($columns = ['*']) { + $original = $this->columns; + + if (is_null($original)) { + $this->columns = $columns; + } + + // Exclude any explicitly excluded columns + if (!is_null($this->excludedColumns)) { + $this->removeExcludedSelectColumns(); + } + + $results = $this->processor->processSelect($this, $this->runSelect()); + + $this->columns = $original; + + return collect($results); + } + + /** + * Remove excluded columns from the select column list. + */ + protected function removeExcludedSelectColumns() { + // Convert current column list and excluded column list to fully-qualified list + $this->columns = $this->convertColumnsToFullyQualified($this->columns); + $excludedColumns = $this->convertColumnsToFullyQualified($this->excludedColumns); + + // Remove any explicitly referenced excludable columns + $this->columns = array_diff($this->columns, $excludedColumns); + + // Replace any remaining wildcard columns (*, table.*, etc) with a list + // of fully-qualified column names + $this->columns = $this->replaceWildcardColumns($this->columns); + + $this->columns = array_diff($this->columns, $excludedColumns); + } + + /** + * Find any wildcard columns ('*'), remove it from the column list and replace with an explicit list of columns. + * + * @param array $columns + * @return array + */ + protected function replaceWildcardColumns(array $columns) { + $wildcardTables = $this->findWildcardTables($columns); + + foreach ($wildcardTables as $wildColumn => $table) { + $schemaColumns = $this->getQualifiedColumnNames($table); + + // Remove the `*` or `.*` column and replace with the individual schema columns + $columns = array_diff($columns, [$wildColumn]); + $columns = array_merge($columns, $schemaColumns); + } + + return $columns; + } + + /** + * Return a list of wildcard columns from the list of columns, mapping columns to their corresponding tables. + * + * @param array $columns + * @return array + */ + protected function findWildcardTables(array $columns) { + $tables = []; + + foreach ($columns as $column) { + if ($column == '*') { + $tables[$column] = $this->from; + continue; + } + + if (substr($column, -1) == '*') { + $tableName = explode('.', $column)[0]; + if ($tableName) { + $tables[$column] = $tableName; + } + } + } + + return $tables; + } + + /** + * Gets the fully qualified column names for a specified table. + * + * @param string $table + * @return array + */ + protected function getQualifiedColumnNames($table = NULL) { + $schema = $this->getConnection()->getSchemaBuilder(); + + return $this->convertColumnsToFullyQualified($schema->getColumnListing($table), $table); + } + + /** + * Fully qualify any unqualified columns in a list with this builder's table name. + * + * @param array $columns + * @return array + */ + protected function convertColumnsToFullyQualified($columns, $table = NULL) { + if (is_null($table)) { + $table = $this->from; + } + + array_walk($columns, function (&$item, $key) use ($table) { + if (strpos($item, '.') === FALSE) { + $item = "$table.$item"; + } + }); + + return $columns; + } +} diff --git a/main/app/sprinkles/core/src/Database/DatabaseInvalidException.php b/main/app/sprinkles/core/src/Database/DatabaseInvalidException.php index 0eba67b..ec30aa6 100644 --- a/main/app/sprinkles/core/src/Database/DatabaseInvalidException.php +++ b/main/app/sprinkles/core/src/Database/DatabaseInvalidException.php @@ -1,21 +1,21 @@ -schema->hasTable('sessions')) { - $this->schema->create('sessions', function (Blueprint $table) { - $table->string('id')->unique(); - $table->integer('user_id')->nullable(); - $table->string('ip_address', 45)->nullable(); - $table->text('user_agent')->nullable(); - $table->text('payload'); - $table->integer('last_activity'); - }); - } - } - - /** - * {@inheritDoc} - */ - public function down() { - $this->schema->drop('sessions'); - } -} +schema->hasTable('sessions')) { + $this->schema->create('sessions', function (Blueprint $table) { + $table->string('id')->unique(); + $table->integer('user_id')->nullable(); + $table->string('ip_address', 45)->nullable(); + $table->text('user_agent')->nullable(); + $table->text('payload'); + $table->integer('last_activity'); + }); + } + } + + /** + * {@inheritDoc} + */ + public function down() { + $this->schema->drop('sessions'); + } +} diff --git a/main/app/sprinkles/core/src/Database/Migrations/v400/ThrottlesTable.php b/main/app/sprinkles/core/src/Database/Migrations/v400/ThrottlesTable.php index f74fee8..676b44e 100644 --- a/main/app/sprinkles/core/src/Database/Migrations/v400/ThrottlesTable.php +++ b/main/app/sprinkles/core/src/Database/Migrations/v400/ThrottlesTable.php @@ -1,51 +1,51 @@ -schema->hasTable('throttles')) { - $this->schema->create('throttles', function (Blueprint $table) { - $table->increments('id'); - $table->string('type'); - $table->string('ip')->nullable(); - $table->text('request_data')->nullable(); - $table->timestamps(); - - $table->engine = 'InnoDB'; - $table->collation = 'utf8_unicode_ci'; - $table->charset = 'utf8'; - $table->index('type'); - $table->index('ip'); - }); - } - } - - /** - * {@inheritDoc} - */ - public function down() { - $this->schema->drop('throttles'); - } -} +schema->hasTable('throttles')) { + $this->schema->create('throttles', function (Blueprint $table) { + $table->increments('id'); + $table->string('type'); + $table->string('ip')->nullable(); + $table->text('request_data')->nullable(); + $table->timestamps(); + + $table->engine = 'InnoDB'; + $table->collation = 'utf8_unicode_ci'; + $table->charset = 'utf8'; + $table->index('type'); + $table->index('ip'); + }); + } + } + + /** + * {@inheritDoc} + */ + public function down() { + $this->schema->drop('throttles'); + } +} diff --git a/main/app/sprinkles/core/src/Database/Models/Concerns/HasRelationships.php b/main/app/sprinkles/core/src/Database/Models/Concerns/HasRelationships.php index 919c108..ccccf32 100644 --- a/main/app/sprinkles/core/src/Database/Models/Concerns/HasRelationships.php +++ b/main/app/sprinkles/core/src/Database/Models/Concerns/HasRelationships.php @@ -1,272 +1,272 @@ -newRelatedInstance($related); - - $foreignKey = $foreignKey ?: $this->getForeignKey(); - - $localKey = $localKey ?: $this->getKeyName(); - - return new HasManySyncable( - $instance->newQuery(), $this, $instance->getTable() . '.' . $foreignKey, $localKey - ); - } - - /** - * Overrides the default Eloquent morphMany relationship to return a MorphManySyncable. - * - * {@inheritDoc} - * @return \UserFrosting\Sprinkle\Core\Database\Relations\MorphManySyncable - */ - public function morphMany($related, $name, $type = NULL, $id = NULL, $localKey = NULL) { - $instance = $this->newRelatedInstance($related); - - // Here we will gather up the morph type and ID for the relationship so that we - // can properly query the intermediate table of a relation. Finally, we will - // get the table and create the relationship instances for the developers. - list($type, $id) = $this->getMorphs($name, $type, $id); - $table = $instance->getTable(); - $localKey = $localKey ?: $this->getKeyName(); - - return new MorphManySyncable($instance->newQuery(), $this, $table . '.' . $type, $table . '.' . $id, $localKey); - } - - /** - * Define a many-to-many 'through' relationship. - * This is basically hasManyThrough for many-to-many relationships. - * - * @param string $related - * @param string $through - * @param string $firstJoiningTable - * @param string $firstForeignKey - * @param string $firstRelatedKey - * @param string $secondJoiningTable - * @param string $secondForeignKey - * @param string $secondRelatedKey - * @param string $throughRelation - * @param string $relation - * @return \UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyThrough - */ - public function belongsToManyThrough( - $related, - $through, - $firstJoiningTable = NULL, - $firstForeignKey = NULL, - $firstRelatedKey = NULL, - $secondJoiningTable = NULL, - $secondForeignKey = NULL, - $secondRelatedKey = NULL, - $throughRelation = NULL, - $relation = NULL - ) { - // If no relationship name was passed, we will pull backtraces to get the - // name of the calling function. We will use that function name as the - // title of this relation since that is a great convention to apply. - if (is_null($relation)) { - $relation = $this->guessBelongsToManyRelation(); - } - - // Create models for through and related - $through = new $through; - $related = $this->newRelatedInstance($related); - - if (is_null($throughRelation)) { - $throughRelation = $through->getTable(); - } - - // If no table names were provided, we can guess it by concatenating the parent - // and through table names. The two model names are transformed to snake case - // from their default CamelCase also. - if (is_null($firstJoiningTable)) { - $firstJoiningTable = $this->joiningTable($through); - } - - if (is_null($secondJoiningTable)) { - $secondJoiningTable = $through->joiningTable($related); - } - - $firstForeignKey = $firstForeignKey ?: $this->getForeignKey(); - $firstRelatedKey = $firstRelatedKey ?: $through->getForeignKey(); - $secondForeignKey = $secondForeignKey ?: $through->getForeignKey(); - $secondRelatedKey = $secondRelatedKey ?: $related->getForeignKey(); - - // This relationship maps the top model (this) to the through model. - $intermediateRelationship = $this->belongsToMany($through, $firstJoiningTable, $firstForeignKey, $firstRelatedKey, $throughRelation) - ->withPivot($firstForeignKey); - - // Now we set up the relationship with the related model. - $query = new BelongsToManyThrough( - $related->newQuery(), $this, $intermediateRelationship, $secondJoiningTable, $secondForeignKey, $secondRelatedKey, $relation - ); - - return $query; - } - - /** - * Define a unique many-to-many relationship. Similar to a regular many-to-many relationship, but removes duplicate child objects. - * Can also be used to implement ternary relationships. - * - * {@inheritDoc} - * @return \UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyUnique - */ - public function belongsToManyUnique($related, $table = NULL, $foreignKey = NULL, $relatedKey = NULL, $relation = NULL) { - // If no relationship name was passed, we will pull backtraces to get the - // name of the calling function. We will use that function name as the - // title of this relation since that is a great convention to apply. - if (is_null($relation)) { - $relation = $this->guessBelongsToManyRelation(); - } - - // First, we'll need to determine the foreign key and "other key" for the - // relationship. Once we have determined the keys we'll make the query - // instances as well as the relationship instances we need for this. - $instance = $this->newRelatedInstance($related); - - $foreignKey = $foreignKey ?: $this->getForeignKey(); - - $relatedKey = $relatedKey ?: $instance->getForeignKey(); - - // If no table name was provided, we can guess it by concatenating the two - // models using underscores in alphabetical order. The two model names - // are transformed to snake case from their default CamelCase also. - if (is_null($table)) { - $table = $this->joiningTable($related); - } - - return new BelongsToManyUnique( - $instance->newQuery(), $this, $table, $foreignKey, $relatedKey, $relation - ); - } - - /** - * Define a unique morphs-to-many relationship. Similar to a regular morphs-to-many relationship, but removes duplicate child objects. - * - * {@inheritDoc} - * @return \UserFrosting\Sprinkle\Core\Database\Relations\MorphToManyUnique - */ - public function morphToManyUnique($related, $name, $table = NULL, $foreignKey = NULL, $otherKey = NULL, $inverse = FALSE) { - $caller = $this->getBelongsToManyCaller(); - - // First, we will need to determine the foreign key and "other key" for the - // relationship. Once we have determined the keys we will make the query - // instances, as well as the relationship instances we need for these. - $foreignKey = $foreignKey ?: $name . '_id'; - - $instance = new $related; - - $otherKey = $otherKey ?: $instance->getForeignKey(); - - // Now we're ready to create a new query builder for this related model and - // the relationship instances for this relation. This relations will set - // appropriate query constraints then entirely manages the hydrations. - $query = $instance->newQuery(); - - $table = $table ?: Str::plural($name); - - return new MorphToManyUnique( - $query, $this, $name, $table, $foreignKey, - $otherKey, $caller, $inverse - ); - } - - /** - * Define a constrained many-to-many relationship. - * This is similar to a regular many-to-many, but constrains the child results to match an additional constraint key in the parent object. - * This has been superseded by the belongsToManyUnique relationship's `withTernary` method since 4.1.7. - * - * @deprecated since 4.1.6 - * @param string $related - * @param string $constraintKey - * @param string $table - * @param string $foreignKey - * @param string $relatedKey - * @param string $relation - * @return \UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyConstrained - */ - public function belongsToManyConstrained($related, $constraintKey, $table = NULL, $foreignKey = NULL, $relatedKey = NULL, $relation = NULL) { - // If no relationship name was passed, we will pull backtraces to get the - // name of the calling function. We will use that function name as the - // title of this relation since that is a great convention to apply. - if (is_null($relation)) { - $relation = $this->guessBelongsToManyRelation(); - } - - // First, we'll need to determine the foreign key and "other key" for the - // relationship. Once we have determined the keys we'll make the query - // instances as well as the relationship instances we need for this. - $instance = $this->newRelatedInstance($related); - - $foreignKey = $foreignKey ?: $this->getForeignKey(); - - $relatedKey = $relatedKey ?: $instance->getForeignKey(); - - // If no table name was provided, we can guess it by concatenating the two - // models using underscores in alphabetical order. The two model names - // are transformed to snake case from their default CamelCase also. - if (is_null($table)) { - $table = $this->joiningTable($related); - } - - return new BelongsToManyConstrained( - $instance->newQuery(), $this, $constraintKey, $table, $foreignKey, $relatedKey, $relation - ); - } - - /** - * Get the relationship name of the belongs to many. - * - * @return string - */ - protected function getBelongsToManyCaller() { - $self = __FUNCTION__; - - $caller = Arr::first(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), function ($key, $trace) use ($self) { - $caller = $trace['function']; - return !in_array($caller, HasRelationships::$manyMethodsExtended) && $caller != $self; - }); - - return !is_null($caller) ? $caller['function'] : NULL; - } -} +newRelatedInstance($related); + + $foreignKey = $foreignKey ?: $this->getForeignKey(); + + $localKey = $localKey ?: $this->getKeyName(); + + return new HasManySyncable( + $instance->newQuery(), $this, $instance->getTable() . '.' . $foreignKey, $localKey + ); + } + + /** + * Overrides the default Eloquent morphMany relationship to return a MorphManySyncable. + * + * {@inheritDoc} + * @return \UserFrosting\Sprinkle\Core\Database\Relations\MorphManySyncable + */ + public function morphMany($related, $name, $type = NULL, $id = NULL, $localKey = NULL) { + $instance = $this->newRelatedInstance($related); + + // Here we will gather up the morph type and ID for the relationship so that we + // can properly query the intermediate table of a relation. Finally, we will + // get the table and create the relationship instances for the developers. + list($type, $id) = $this->getMorphs($name, $type, $id); + $table = $instance->getTable(); + $localKey = $localKey ?: $this->getKeyName(); + + return new MorphManySyncable($instance->newQuery(), $this, $table . '.' . $type, $table . '.' . $id, $localKey); + } + + /** + * Define a many-to-many 'through' relationship. + * This is basically hasManyThrough for many-to-many relationships. + * + * @param string $related + * @param string $through + * @param string $firstJoiningTable + * @param string $firstForeignKey + * @param string $firstRelatedKey + * @param string $secondJoiningTable + * @param string $secondForeignKey + * @param string $secondRelatedKey + * @param string $throughRelation + * @param string $relation + * @return \UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyThrough + */ + public function belongsToManyThrough( + $related, + $through, + $firstJoiningTable = NULL, + $firstForeignKey = NULL, + $firstRelatedKey = NULL, + $secondJoiningTable = NULL, + $secondForeignKey = NULL, + $secondRelatedKey = NULL, + $throughRelation = NULL, + $relation = NULL + ) { + // If no relationship name was passed, we will pull backtraces to get the + // name of the calling function. We will use that function name as the + // title of this relation since that is a great convention to apply. + if (is_null($relation)) { + $relation = $this->guessBelongsToManyRelation(); + } + + // Create models for through and related + $through = new $through; + $related = $this->newRelatedInstance($related); + + if (is_null($throughRelation)) { + $throughRelation = $through->getTable(); + } + + // If no table names were provided, we can guess it by concatenating the parent + // and through table names. The two model names are transformed to snake case + // from their default CamelCase also. + if (is_null($firstJoiningTable)) { + $firstJoiningTable = $this->joiningTable($through); + } + + if (is_null($secondJoiningTable)) { + $secondJoiningTable = $through->joiningTable($related); + } + + $firstForeignKey = $firstForeignKey ?: $this->getForeignKey(); + $firstRelatedKey = $firstRelatedKey ?: $through->getForeignKey(); + $secondForeignKey = $secondForeignKey ?: $through->getForeignKey(); + $secondRelatedKey = $secondRelatedKey ?: $related->getForeignKey(); + + // This relationship maps the top model (this) to the through model. + $intermediateRelationship = $this->belongsToMany($through, $firstJoiningTable, $firstForeignKey, $firstRelatedKey, $throughRelation) + ->withPivot($firstForeignKey); + + // Now we set up the relationship with the related model. + $query = new BelongsToManyThrough( + $related->newQuery(), $this, $intermediateRelationship, $secondJoiningTable, $secondForeignKey, $secondRelatedKey, $relation + ); + + return $query; + } + + /** + * Define a unique many-to-many relationship. Similar to a regular many-to-many relationship, but removes duplicate child objects. + * Can also be used to implement ternary relationships. + * + * {@inheritDoc} + * @return \UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyUnique + */ + public function belongsToManyUnique($related, $table = NULL, $foreignKey = NULL, $relatedKey = NULL, $relation = NULL) { + // If no relationship name was passed, we will pull backtraces to get the + // name of the calling function. We will use that function name as the + // title of this relation since that is a great convention to apply. + if (is_null($relation)) { + $relation = $this->guessBelongsToManyRelation(); + } + + // First, we'll need to determine the foreign key and "other key" for the + // relationship. Once we have determined the keys we'll make the query + // instances as well as the relationship instances we need for this. + $instance = $this->newRelatedInstance($related); + + $foreignKey = $foreignKey ?: $this->getForeignKey(); + + $relatedKey = $relatedKey ?: $instance->getForeignKey(); + + // If no table name was provided, we can guess it by concatenating the two + // models using underscores in alphabetical order. The two model names + // are transformed to snake case from their default CamelCase also. + if (is_null($table)) { + $table = $this->joiningTable($related); + } + + return new BelongsToManyUnique( + $instance->newQuery(), $this, $table, $foreignKey, $relatedKey, $relation + ); + } + + /** + * Define a unique morphs-to-many relationship. Similar to a regular morphs-to-many relationship, but removes duplicate child objects. + * + * {@inheritDoc} + * @return \UserFrosting\Sprinkle\Core\Database\Relations\MorphToManyUnique + */ + public function morphToManyUnique($related, $name, $table = NULL, $foreignKey = NULL, $otherKey = NULL, $inverse = FALSE) { + $caller = $this->getBelongsToManyCaller(); + + // First, we will need to determine the foreign key and "other key" for the + // relationship. Once we have determined the keys we will make the query + // instances, as well as the relationship instances we need for these. + $foreignKey = $foreignKey ?: $name . '_id'; + + $instance = new $related; + + $otherKey = $otherKey ?: $instance->getForeignKey(); + + // Now we're ready to create a new query builder for this related model and + // the relationship instances for this relation. This relations will set + // appropriate query constraints then entirely manages the hydrations. + $query = $instance->newQuery(); + + $table = $table ?: Str::plural($name); + + return new MorphToManyUnique( + $query, $this, $name, $table, $foreignKey, + $otherKey, $caller, $inverse + ); + } + + /** + * Define a constrained many-to-many relationship. + * This is similar to a regular many-to-many, but constrains the child results to match an additional constraint key in the parent object. + * This has been superseded by the belongsToManyUnique relationship's `withTernary` method since 4.1.7. + * + * @deprecated since 4.1.6 + * @param string $related + * @param string $constraintKey + * @param string $table + * @param string $foreignKey + * @param string $relatedKey + * @param string $relation + * @return \UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyConstrained + */ + public function belongsToManyConstrained($related, $constraintKey, $table = NULL, $foreignKey = NULL, $relatedKey = NULL, $relation = NULL) { + // If no relationship name was passed, we will pull backtraces to get the + // name of the calling function. We will use that function name as the + // title of this relation since that is a great convention to apply. + if (is_null($relation)) { + $relation = $this->guessBelongsToManyRelation(); + } + + // First, we'll need to determine the foreign key and "other key" for the + // relationship. Once we have determined the keys we'll make the query + // instances as well as the relationship instances we need for this. + $instance = $this->newRelatedInstance($related); + + $foreignKey = $foreignKey ?: $this->getForeignKey(); + + $relatedKey = $relatedKey ?: $instance->getForeignKey(); + + // If no table name was provided, we can guess it by concatenating the two + // models using underscores in alphabetical order. The two model names + // are transformed to snake case from their default CamelCase also. + if (is_null($table)) { + $table = $this->joiningTable($related); + } + + return new BelongsToManyConstrained( + $instance->newQuery(), $this, $constraintKey, $table, $foreignKey, $relatedKey, $relation + ); + } + + /** + * Get the relationship name of the belongs to many. + * + * @return string + */ + protected function getBelongsToManyCaller() { + $self = __FUNCTION__; + + $caller = Arr::first(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), function ($key, $trace) use ($self) { + $caller = $trace['function']; + return !in_array($caller, HasRelationships::$manyMethodsExtended) && $caller != $self; + }); + + return !is_null($caller) ? $caller['function'] : NULL; + } +} diff --git a/main/app/sprinkles/core/src/Database/Models/Model.php b/main/app/sprinkles/core/src/Database/Models/Model.php index 28b6be0..38e49fd 100644 --- a/main/app/sprinkles/core/src/Database/Models/Model.php +++ b/main/app/sprinkles/core/src/Database/Models/Model.php @@ -1,133 +1,133 @@ -attributes); - } - - /** - * Determines whether a model exists by checking a unique column, including checking soft-deleted records - * - * @param mixed $value - * @param string $identifier - * @param bool $checkDeleted set to true to include soft-deleted records - * @return \UserFrosting\Sprinkle\Core\Database\Models\Model|null - */ - public static function findUnique($value, $identifier, $checkDeleted = TRUE) { - $query = static::where($identifier, $value); - - if ($checkDeleted) { - $query = $query->withTrashed(); - } - - return $query->first(); - } - - /** - * Determine if an relation exists on the model - even if it is null. - * - * @param string $key - * @return bool - */ - public function relationExists($key) { - return array_key_exists($key, $this->relations); - } - - /** - * Store the object in the DB, creating a new row if one doesn't already exist. - * - * Calls save(), then returns the id of the new record in the database. - * @return int the id of this object. - */ - public function store() { - $this->save(); - - // Store function should always return the id of the object - return $this->id; - } - - /** - * Overrides Laravel's base Model to return our custom query builder object. - * - * @return \UserFrosting\Sprinkles\Core\Database\Builder - */ - protected function newBaseQueryBuilder() { - /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ - $classMapper = static::$ci->classMapper; - - $connection = $this->getConnection(); - - return $classMapper->createInstance( - 'query_builder', - $connection, - $connection->getQueryGrammar(), - $connection->getPostProcessor() - ); - } - - /** - * Get the properties of this object as an associative array. Alias for toArray(). - * - * @deprecated since 4.1.8 There is no point in having this alias. - * @return array - */ - public function export() { - return $this->toArray(); - } - - /** - * For raw array fetching. Must be static, otherwise PHP gets confused about where to find $table. - * - * @deprecated since 4.1.8 setFetchMode is no longer available as of Laravel 5.4. - * @link https://github.com/laravel/framework/issues/17728 - */ - public static function queryBuilder() { - // Set query builder to fetch result sets as associative arrays (instead of creating stdClass objects) - DB::connection()->setFetchMode(\PDO::FETCH_ASSOC); - return DB::table(static::$table); - } -} +attributes); + } + + /** + * Determines whether a model exists by checking a unique column, including checking soft-deleted records + * + * @param mixed $value + * @param string $identifier + * @param bool $checkDeleted set to true to include soft-deleted records + * @return \UserFrosting\Sprinkle\Core\Database\Models\Model|null + */ + public static function findUnique($value, $identifier, $checkDeleted = TRUE) { + $query = static::where($identifier, $value); + + if ($checkDeleted) { + $query = $query->withTrashed(); + } + + return $query->first(); + } + + /** + * Determine if an relation exists on the model - even if it is null. + * + * @param string $key + * @return bool + */ + public function relationExists($key) { + return array_key_exists($key, $this->relations); + } + + /** + * Store the object in the DB, creating a new row if one doesn't already exist. + * + * Calls save(), then returns the id of the new record in the database. + * @return int the id of this object. + */ + public function store() { + $this->save(); + + // Store function should always return the id of the object + return $this->id; + } + + /** + * Overrides Laravel's base Model to return our custom query builder object. + * + * @return \UserFrosting\Sprinkles\Core\Database\Builder + */ + protected function newBaseQueryBuilder() { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + $connection = $this->getConnection(); + + return $classMapper->createInstance( + 'query_builder', + $connection, + $connection->getQueryGrammar(), + $connection->getPostProcessor() + ); + } + + /** + * Get the properties of this object as an associative array. Alias for toArray(). + * + * @deprecated since 4.1.8 There is no point in having this alias. + * @return array + */ + public function export() { + return $this->toArray(); + } + + /** + * For raw array fetching. Must be static, otherwise PHP gets confused about where to find $table. + * + * @deprecated since 4.1.8 setFetchMode is no longer available as of Laravel 5.4. + * @link https://github.com/laravel/framework/issues/17728 + */ + public static function queryBuilder() { + // Set query builder to fetch result sets as associative arrays (instead of creating stdClass objects) + DB::connection()->setFetchMode(\PDO::FETCH_ASSOC); + return DB::table(static::$table); + } +} diff --git a/main/app/sprinkles/core/src/Database/Models/Throttle.php b/main/app/sprinkles/core/src/Database/Models/Throttle.php index 82d2c87..5810e0d 100644 --- a/main/app/sprinkles/core/src/Database/Models/Throttle.php +++ b/main/app/sprinkles/core/src/Database/Models/Throttle.php @@ -1,37 +1,37 @@ -constraintKey = $constraintKey; - parent::__construct($query, $parent, $table, $foreignKey, $relatedKey, $relationName); - } - - /** - * Set the constraints for an eager load of the relation. - * - * @param array $models - * @return void - */ - public function addEagerConstraints(array $models) { - // To make the query more efficient, we only bother querying related models if their pivot key value - // matches the pivot key value of one of the parent models. - $pivotKeys = $this->getPivotKeys($models, $this->constraintKey); - $this->query->whereIn($this->getQualifiedForeignKeyName(), $this->getKeys($models)) - ->whereIn($this->constraintKey, $pivotKeys); - } - - /** - * Gets a list of unique pivot key values from an array of models. - */ - protected function getPivotKeys(array $models, $pivotKey) { - $pivotKeys = []; - foreach ($models as $model) { - $pivotKeys[] = $model->getRelation('pivot')->{$pivotKey}; - } - return array_unique($pivotKeys); - } - - /** - * Match the eagerly loaded results to their parents, constraining the results by matching the values of $constraintKey - * in the parent object to the child objects. - * - * @link Called in https://github.com/laravel/framework/blob/2f4135d8db5ded851d1f4f611124c53b768a3c08/src/Illuminate/Database/Eloquent/Builder.php - * @param array $models - * @param \Illuminate\Database\Eloquent\Collection $results - * @param string $relation - * @return array - */ - public function match(array $models, Collection $results, $relation) { - $dictionary = $this->buildDictionary($results); - - // Once we have an array dictionary of child objects we can easily match the - // children back to their parent using the dictionary and the keys on the - // the parent models. Then we will return the hydrated models back out. - foreach ($models as $model) { - $pivotValue = $model->getRelation('pivot')->{$this->constraintKey}; - if (isset($dictionary[$key = $model->getKey()])) { - // Only match children if their pivot key value matches that of the parent model - $items = $this->findMatchingPivots($dictionary[$key], $pivotValue); - $model->setRelation( - $relation, $this->related->newCollection($items) - ); - } - } - - return $models; - } - - /** - * Filter an array of models, only taking models whose $constraintKey value matches $pivotValue. - * - * @param mixed $pivotValue - * @return array - */ - protected function findMatchingPivots($items, $pivotValue) { - $result = []; - foreach ($items as $item) { - if ($item->getRelation('pivot')->{$this->constraintKey} == $pivotValue) { - $result[] = $item; - } - } - return $result; - } -} +constraintKey = $constraintKey; + parent::__construct($query, $parent, $table, $foreignKey, $relatedKey, $relationName); + } + + /** + * Set the constraints for an eager load of the relation. + * + * @param array $models + * @return void + */ + public function addEagerConstraints(array $models) { + // To make the query more efficient, we only bother querying related models if their pivot key value + // matches the pivot key value of one of the parent models. + $pivotKeys = $this->getPivotKeys($models, $this->constraintKey); + $this->query->whereIn($this->getQualifiedForeignKeyName(), $this->getKeys($models)) + ->whereIn($this->constraintKey, $pivotKeys); + } + + /** + * Gets a list of unique pivot key values from an array of models. + */ + protected function getPivotKeys(array $models, $pivotKey) { + $pivotKeys = []; + foreach ($models as $model) { + $pivotKeys[] = $model->getRelation('pivot')->{$pivotKey}; + } + return array_unique($pivotKeys); + } + + /** + * Match the eagerly loaded results to their parents, constraining the results by matching the values of $constraintKey + * in the parent object to the child objects. + * + * @link Called in https://github.com/laravel/framework/blob/2f4135d8db5ded851d1f4f611124c53b768a3c08/src/Illuminate/Database/Eloquent/Builder.php + * @param array $models + * @param \Illuminate\Database\Eloquent\Collection $results + * @param string $relation + * @return array + */ + public function match(array $models, Collection $results, $relation) { + $dictionary = $this->buildDictionary($results); + + // Once we have an array dictionary of child objects we can easily match the + // children back to their parent using the dictionary and the keys on the + // the parent models. Then we will return the hydrated models back out. + foreach ($models as $model) { + $pivotValue = $model->getRelation('pivot')->{$this->constraintKey}; + if (isset($dictionary[$key = $model->getKey()])) { + // Only match children if their pivot key value matches that of the parent model + $items = $this->findMatchingPivots($dictionary[$key], $pivotValue); + $model->setRelation( + $relation, $this->related->newCollection($items) + ); + } + } + + return $models; + } + + /** + * Filter an array of models, only taking models whose $constraintKey value matches $pivotValue. + * + * @param mixed $pivotValue + * @return array + */ + protected function findMatchingPivots($items, $pivotValue) { + $result = []; + foreach ($items as $item) { + if ($item->getRelation('pivot')->{$this->constraintKey} == $pivotValue) { + $result[] = $item; + } + } + return $result; + } +} diff --git a/main/app/sprinkles/core/src/Database/Relations/BelongsToManyThrough.php b/main/app/sprinkles/core/src/Database/Relations/BelongsToManyThrough.php index 67304be..24aa4cf 100644 --- a/main/app/sprinkles/core/src/Database/Relations/BelongsToManyThrough.php +++ b/main/app/sprinkles/core/src/Database/Relations/BelongsToManyThrough.php @@ -1,223 +1,223 @@ -intermediateRelation = $intermediateRelation; - - parent::__construct($query, $parent, $table, $foreignKey, $relatedKey, $relationName); - } - - /** - * Use the intermediate relationship to determine the "parent" pivot key name - * - * This is a crazy roundabout way to get the name of the intermediate relation's foreign key. - * It would be better if BelongsToMany had a simple accessor for its foreign key. - * @return string - */ - public function getParentKeyName() { - return $this->intermediateRelation->newExistingPivot()->getForeignKey(); - } - - /** - * Get the key for comparing against the parent key in "has" query. - * - * @see \Illuminate\Database\Eloquent\Relations\BelongsToMany - * @return string - */ - public function getExistenceCompareKey() { - return $this->intermediateRelation->getQualifiedForeignKeyName(); - } - - /** - * Add a "via" query to load the intermediate models through which the child models are related. - * - * @param string $viaRelationName - * @param callable $viaCallback - * @return $this - */ - public function withVia($viaRelationName = NULL, $viaCallback = NULL) { - $this->tertiaryRelated = $this->intermediateRelation->getRelated(); - - // Set tertiary key and related model - $this->tertiaryKey = $this->foreignKey; - - $this->tertiaryRelationName = is_null($viaRelationName) ? $this->intermediateRelation->getRelationName() . '_via' : $viaRelationName; - - $this->tertiaryCallback = is_null($viaCallback) - ? function () { - // - } - : $viaCallback; - - return $this; - } - - /** - * Set the constraints for an eager load of the relation. - * - * @param array $models - * @return void - */ - public function addEagerConstraints(array $models) { - // Constraint to only load models where the intermediate relation's foreign key matches the parent model - $intermediateForeignKeyName = $this->intermediateRelation->getQualifiedForeignKeyName(); - - return $this->query->whereIn($intermediateForeignKeyName, $this->getKeys($models)); - } - - /** - * Set the where clause for the relation query. - * - * @return $this - */ - protected function addWhereConstraints() { - $parentKeyName = $this->getParentKeyName(); - - $this->query->where( - $parentKeyName, '=', $this->parent->getKey() - ); - - return $this; - } - - /** - * Match the eagerly loaded results to their parents - * - * @param array $models - * @param \Illuminate\Database\Eloquent\Collection $results - * @param string $relation - * @return array - */ - public function match(array $models, Collection $results, $relation) { - // Build dictionary of parent (e.g. user) to related (e.g. permission) models - list($dictionary, $nestedViaDictionary) = $this->buildDictionary($results, $this->getParentKeyName()); - - // Once we have an array dictionary of child objects we can easily match the - // children back to their parent using the dictionary and the keys on the - // the parent models. Then we will return the hydrated models back out. - foreach ($models as $model) { - if (isset($dictionary[$key = $model->getKey()])) { - /** @var array */ - $items = $dictionary[$key]; - - // Eliminate any duplicates - $items = $this->related->newCollection($items)->unique(); - - // If set, match up the via models to the models in the related collection - if (!is_null($nestedViaDictionary)) { - $this->matchTertiaryModels($nestedViaDictionary[$key], $items); - } - - // Remove the tertiary pivot key from the condensed models - foreach ($items as $relatedModel) { - unset($relatedModel->pivot->{$this->foreignKey}); - } - - $model->setRelation( - $relation, $items - ); - } - } - - return $models; - } - - /** - * Unset tertiary pivots on a collection or array of models. - * - * @param \Illuminate\Database\Eloquent\Collection $models - * @return void - */ - protected function unsetTertiaryPivots(Collection $models) { - foreach ($models as $model) { - unset($model->pivot->{$this->foreignKey}); - } - } - - /** - * Set the join clause for the relation query. - * - * @param \Illuminate\Database\Eloquent\Builder|null $query - * @return $this - */ - protected function performJoin($query = NULL) { - $query = $query ?: $this->query; - - parent::performJoin($query); - - // We need to join to the intermediate table on the related model's primary - // key column with the intermediate table's foreign key for the related - // model instance. Then we can set the "where" for the parent models. - $intermediateTable = $this->intermediateRelation->getTable(); - - $key = $this->intermediateRelation->getQualifiedRelatedKeyName(); - - $query->join($intermediateTable, $key, '=', $this->getQualifiedForeignKeyName()); - - return $this; - } - - /** - * Get the pivot columns for the relation. - * - * "pivot_" is prefixed to each column for easy removal later. - * - * @return array - */ - protected function aliasedPivotColumns() { - $defaults = [$this->foreignKey, $this->relatedKey]; - $aliasedPivotColumns = collect(array_merge($defaults, $this->pivotColumns))->map(function ($column) { - return $this->table . '.' . $column . ' as pivot_' . $column; - }); - - $parentKeyName = $this->getParentKeyName(); - - // Add pivot column for the intermediate relation - $aliasedPivotColumns[] = "{$this->intermediateRelation->getQualifiedForeignKeyName()} as pivot_$parentKeyName"; - - return $aliasedPivotColumns->unique()->all(); - } -} +intermediateRelation = $intermediateRelation; + + parent::__construct($query, $parent, $table, $foreignKey, $relatedKey, $relationName); + } + + /** + * Use the intermediate relationship to determine the "parent" pivot key name + * + * This is a crazy roundabout way to get the name of the intermediate relation's foreign key. + * It would be better if BelongsToMany had a simple accessor for its foreign key. + * @return string + */ + public function getParentKeyName() { + return $this->intermediateRelation->newExistingPivot()->getForeignKey(); + } + + /** + * Get the key for comparing against the parent key in "has" query. + * + * @see \Illuminate\Database\Eloquent\Relations\BelongsToMany + * @return string + */ + public function getExistenceCompareKey() { + return $this->intermediateRelation->getQualifiedForeignKeyName(); + } + + /** + * Add a "via" query to load the intermediate models through which the child models are related. + * + * @param string $viaRelationName + * @param callable $viaCallback + * @return $this + */ + public function withVia($viaRelationName = NULL, $viaCallback = NULL) { + $this->tertiaryRelated = $this->intermediateRelation->getRelated(); + + // Set tertiary key and related model + $this->tertiaryKey = $this->foreignKey; + + $this->tertiaryRelationName = is_null($viaRelationName) ? $this->intermediateRelation->getRelationName() . '_via' : $viaRelationName; + + $this->tertiaryCallback = is_null($viaCallback) + ? function () { + // + } + : $viaCallback; + + return $this; + } + + /** + * Set the constraints for an eager load of the relation. + * + * @param array $models + * @return void + */ + public function addEagerConstraints(array $models) { + // Constraint to only load models where the intermediate relation's foreign key matches the parent model + $intermediateForeignKeyName = $this->intermediateRelation->getQualifiedForeignKeyName(); + + return $this->query->whereIn($intermediateForeignKeyName, $this->getKeys($models)); + } + + /** + * Set the where clause for the relation query. + * + * @return $this + */ + protected function addWhereConstraints() { + $parentKeyName = $this->getParentKeyName(); + + $this->query->where( + $parentKeyName, '=', $this->parent->getKey() + ); + + return $this; + } + + /** + * Match the eagerly loaded results to their parents + * + * @param array $models + * @param \Illuminate\Database\Eloquent\Collection $results + * @param string $relation + * @return array + */ + public function match(array $models, Collection $results, $relation) { + // Build dictionary of parent (e.g. user) to related (e.g. permission) models + list($dictionary, $nestedViaDictionary) = $this->buildDictionary($results, $this->getParentKeyName()); + + // Once we have an array dictionary of child objects we can easily match the + // children back to their parent using the dictionary and the keys on the + // the parent models. Then we will return the hydrated models back out. + foreach ($models as $model) { + if (isset($dictionary[$key = $model->getKey()])) { + /** @var array */ + $items = $dictionary[$key]; + + // Eliminate any duplicates + $items = $this->related->newCollection($items)->unique(); + + // If set, match up the via models to the models in the related collection + if (!is_null($nestedViaDictionary)) { + $this->matchTertiaryModels($nestedViaDictionary[$key], $items); + } + + // Remove the tertiary pivot key from the condensed models + foreach ($items as $relatedModel) { + unset($relatedModel->pivot->{$this->foreignKey}); + } + + $model->setRelation( + $relation, $items + ); + } + } + + return $models; + } + + /** + * Unset tertiary pivots on a collection or array of models. + * + * @param \Illuminate\Database\Eloquent\Collection $models + * @return void + */ + protected function unsetTertiaryPivots(Collection $models) { + foreach ($models as $model) { + unset($model->pivot->{$this->foreignKey}); + } + } + + /** + * Set the join clause for the relation query. + * + * @param \Illuminate\Database\Eloquent\Builder|null $query + * @return $this + */ + protected function performJoin($query = NULL) { + $query = $query ?: $this->query; + + parent::performJoin($query); + + // We need to join to the intermediate table on the related model's primary + // key column with the intermediate table's foreign key for the related + // model instance. Then we can set the "where" for the parent models. + $intermediateTable = $this->intermediateRelation->getTable(); + + $key = $this->intermediateRelation->getQualifiedRelatedKeyName(); + + $query->join($intermediateTable, $key, '=', $this->getQualifiedForeignKeyName()); + + return $this; + } + + /** + * Get the pivot columns for the relation. + * + * "pivot_" is prefixed to each column for easy removal later. + * + * @return array + */ + protected function aliasedPivotColumns() { + $defaults = [$this->foreignKey, $this->relatedKey]; + $aliasedPivotColumns = collect(array_merge($defaults, $this->pivotColumns))->map(function ($column) { + return $this->table . '.' . $column . ' as pivot_' . $column; + }); + + $parentKeyName = $this->getParentKeyName(); + + // Add pivot column for the intermediate relation + $aliasedPivotColumns[] = "{$this->intermediateRelation->getQualifiedForeignKeyName()} as pivot_$parentKeyName"; + + return $aliasedPivotColumns->unique()->all(); + } +} diff --git a/main/app/sprinkles/core/src/Database/Relations/BelongsToManyUnique.php b/main/app/sprinkles/core/src/Database/Relations/BelongsToManyUnique.php index d5d473d..1bde954 100644 --- a/main/app/sprinkles/core/src/Database/Relations/BelongsToManyUnique.php +++ b/main/app/sprinkles/core/src/Database/Relations/BelongsToManyUnique.php @@ -1,23 +1,23 @@ - [], 'deleted' => [], 'updated' => [], - ]; - - if (is_null($relatedKeyName)) { - $relatedKeyName = $this->related->getKeyName(); - } - - // First we need to attach any of the associated models that are not currently - // in the child entity table. We'll spin through the given IDs, checking to see - // if they exist in the array of current ones, and if not we will insert. - $current = $this->newQuery()->pluck( - $relatedKeyName - )->all(); - - // Separate the submitted data into "update" and "new" - $updateRows = []; - $newRows = []; - foreach ($data as $row) { - // We determine "updateable" rows as those whose $relatedKeyName (usually 'id') is set, not empty, and - // match a related row in the database. - if (isset($row[$relatedKeyName]) && !empty($row[$relatedKeyName]) && in_array($row[$relatedKeyName], $current)) { - $id = $row[$relatedKeyName]; - $updateRows[$id] = $row; - } else { - $newRows[] = $row; - } - } - - // Next, we'll determine the rows in the database that aren't in the "update" list. - // These rows will be scheduled for deletion. Again, we determine based on the relatedKeyName (typically 'id'). - $updateIds = array_keys($updateRows); - $deleteIds = []; - foreach ($current as $currentId) { - if (!in_array($currentId, $updateIds)) { - $deleteIds[] = $currentId; - } - } - - // Delete any non-matching rows - if ($deleting && count($deleteIds) > 0) { - // Remove global scopes to avoid ambiguous keys - $this->getRelated() - ->withoutGlobalScopes() - ->whereIn($relatedKeyName, $deleteIds) - ->delete(); - - $changes['deleted'] = $this->castKeys($deleteIds); - } - - // Update the updatable rows - foreach ($updateRows as $id => $row) { - // Remove global scopes to avoid ambiguous keys - $this->getRelated() - ->withoutGlobalScopes() - ->where($relatedKeyName, $id) - ->update($row); - } - - $changes['updated'] = $this->castKeys($updateIds); - - // Insert the new rows - $newIds = []; - foreach ($newRows as $row) { - if ($forceCreate) { - $newModel = $this->forceCreate($row); - } else { - $newModel = $this->create($row); - } - $newIds[] = $newModel->$relatedKeyName; - } - - $changes['created'] = $this->castKeys($newIds); - - return $changes; - } - - - /** - * Cast the given keys to integers if they are numeric and string otherwise. - * - * @param array $keys - * @return array - */ - protected function castKeys(array $keys) { - return (array)array_map(function ($v) { - return $this->castKey($v); - }, $keys); - } - - /** - * Cast the given key to an integer if it is numeric. - * - * @param mixed $key - * @return mixed - */ - protected function castKey($key) { - return is_numeric($key) ? (int)$key : (string)$key; - } -} + [], 'deleted' => [], 'updated' => [], + ]; + + if (is_null($relatedKeyName)) { + $relatedKeyName = $this->related->getKeyName(); + } + + // First we need to attach any of the associated models that are not currently + // in the child entity table. We'll spin through the given IDs, checking to see + // if they exist in the array of current ones, and if not we will insert. + $current = $this->newQuery()->pluck( + $relatedKeyName + )->all(); + + // Separate the submitted data into "update" and "new" + $updateRows = []; + $newRows = []; + foreach ($data as $row) { + // We determine "updateable" rows as those whose $relatedKeyName (usually 'id') is set, not empty, and + // match a related row in the database. + if (isset($row[$relatedKeyName]) && !empty($row[$relatedKeyName]) && in_array($row[$relatedKeyName], $current)) { + $id = $row[$relatedKeyName]; + $updateRows[$id] = $row; + } else { + $newRows[] = $row; + } + } + + // Next, we'll determine the rows in the database that aren't in the "update" list. + // These rows will be scheduled for deletion. Again, we determine based on the relatedKeyName (typically 'id'). + $updateIds = array_keys($updateRows); + $deleteIds = []; + foreach ($current as $currentId) { + if (!in_array($currentId, $updateIds)) { + $deleteIds[] = $currentId; + } + } + + // Delete any non-matching rows + if ($deleting && count($deleteIds) > 0) { + // Remove global scopes to avoid ambiguous keys + $this->getRelated() + ->withoutGlobalScopes() + ->whereIn($relatedKeyName, $deleteIds) + ->delete(); + + $changes['deleted'] = $this->castKeys($deleteIds); + } + + // Update the updatable rows + foreach ($updateRows as $id => $row) { + // Remove global scopes to avoid ambiguous keys + $this->getRelated() + ->withoutGlobalScopes() + ->where($relatedKeyName, $id) + ->update($row); + } + + $changes['updated'] = $this->castKeys($updateIds); + + // Insert the new rows + $newIds = []; + foreach ($newRows as $row) { + if ($forceCreate) { + $newModel = $this->forceCreate($row); + } else { + $newModel = $this->create($row); + } + $newIds[] = $newModel->$relatedKeyName; + } + + $changes['created'] = $this->castKeys($newIds); + + return $changes; + } + + + /** + * Cast the given keys to integers if they are numeric and string otherwise. + * + * @param array $keys + * @return array + */ + protected function castKeys(array $keys) { + return (array)array_map(function ($v) { + return $this->castKey($v); + }, $keys); + } + + /** + * Cast the given key to an integer if it is numeric. + * + * @param mixed $key + * @return mixed + */ + protected function castKey($key) { + return is_numeric($key) ? (int)$key : (string)$key; + } +} diff --git a/main/app/sprinkles/core/src/Database/Relations/Concerns/Unique.php b/main/app/sprinkles/core/src/Database/Relations/Concerns/Unique.php index 3a321e4..deb2673 100644 --- a/main/app/sprinkles/core/src/Database/Relations/Concerns/Unique.php +++ b/main/app/sprinkles/core/src/Database/Relations/Concerns/Unique.php @@ -1,543 +1,543 @@ -offset($value); - } - - /** - * Set the "offset" value of the query. - * - * Implement for 'unionOffset' as well? (By checking the value of $this->query->getQuery()->unions) - * @see \Illuminate\Database\Query\Builder - * @param int $value - * @return $this - */ - public function offset($value) { - $this->offset = max(0, $value); - - return $this; - } - - /** - * Alias to set the "limit" value of the query. - * - * @param int $value - * @return $this - */ - public function take($value) { - return $this->limit($value); - } - - /** - * Set the "limit" value of the query. - * - * Implement for 'unionLimit' as well? (By checking the value of $this->query->getQuery()->unions) - * @see \Illuminate\Database\Query\Builder - * @param int $value - * @return $this - */ - public function limit($value) { - if ($value >= 0) { - $this->limit = $value; - } - - return $this; - } - - /** - * Set the limit on the number of intermediate models to load. - * - * @deprecated since 4.1.7 - * @param int $value - * @return $this - */ - public function withLimit($value) { - return $this->limit($value); - } - - /** - * Set the offset when loading the intermediate models. - * - * @deprecated since 4.1.7 - * @param int $value - * @return $this - */ - public function withOffset($value) { - return $this->offset($value); - } - - /** - * Add a query to load the nested tertiary models for this relationship. - * - * @param \Illuminate\Database\Eloquent\Model $tertiaryRelated - * @param string $tertiaryRelationName - * @param string $tertiaryKey - * @param callable $tertiaryCallback - * @return $this - */ - public function withTertiary($tertiaryRelated, $tertiaryRelationName = NULL, $tertiaryKey = NULL, $tertiaryCallback = NULL) { - $this->tertiaryRelated = new $tertiaryRelated; - - // Try to guess the tertiary related key from the tertiaryRelated model. - $this->tertiaryKey = $tertiaryKey ?: $this->tertiaryRelated->getForeignKey(); - - // Also add the tertiary key as a pivot - $this->withPivot($this->tertiaryKey); - - $this->tertiaryRelationName = is_null($tertiaryRelationName) ? $this->tertiaryRelated->getTable() : $tertiaryRelationName; - - $this->tertiaryCallback = is_null($tertiaryCallback) - ? function () { - // - } - : $tertiaryCallback; - - return $this; - } - - /** - * Return the count of child models for this relationship. - * - * @see http://stackoverflow.com/a/29728129/2970321 - * @return int - */ - public function count() { - $constrainedBuilder = clone $this->query; - - $constrainedBuilder = $constrainedBuilder->distinct(); - - return $constrainedBuilder->count($this->relatedKey); - } - - /** - * Add the constraints for a relationship count query. - * - * @see \Illuminate\Database\Eloquent\Relations\Relation - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \Illuminate\Database\Eloquent\Builder $parentQuery - * @return \Illuminate\Database\Eloquent\Builder - */ - public function getRelationExistenceCountQuery(Builder $query, Builder $parentQuery) { - return $this->getRelationExistenceQuery( - $query, $parentQuery, new Expression("count(distinct {$this->relatedKey})") - ); - } - - /** - * Match the eagerly loaded results to their parents - * - * @param array $models - * @param \Illuminate\Database\Eloquent\Collection $results - * @param string $relation - * @return array - */ - public function match(array $models, Collection $results, $relation) { - // Build dictionary of parent (e.g. user) to related (e.g. permission) models - list($dictionary, $nestedTertiaryDictionary) = $this->buildDictionary($results, $this->foreignKey); - - // Once we have an array dictionary of child objects we can easily match the - // children back to their parent using the dictionary and the keys on the - // the parent models. Then we will return the hydrated models back out. - foreach ($models as $model) { - if (isset($dictionary[$key = $model->getKey()])) { - /** @var array */ - $items = $dictionary[$key]; - - // Eliminate any duplicates - $items = $this->related->newCollection($items)->unique(); - - // If set, match up the tertiary models to the models in the related collection - if (!is_null($nestedTertiaryDictionary)) { - $this->matchTertiaryModels($nestedTertiaryDictionary[$key], $items); - } - - $model->setRelation( - $relation, $items - ); - } - } - - return $models; - } - - /** - * Execute the query as a "select" statement, getting all requested models - * and matching up any tertiary models. - * - * @param array $columns - * @return \Illuminate\Database\Eloquent\Collection - */ - public function get($columns = ['*']) { - // Get models and condense the result set - $models = $this->getModels($columns, TRUE); - - // Remove the tertiary pivot key from the condensed models - $this->unsetTertiaryPivots($models); - - return $models; - } - - /** - * If we are applying either a limit or offset, we'll first determine a limited/offset list of model ids - * to select from in the final query. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param int $limit - * @param int $offset - * @return \Illuminate\Database\Eloquent\Builder - */ - public function getPaginatedQuery(Builder $query, $limit = NULL, $offset = NULL) { - $constrainedBuilder = clone $query; - - // Since some unique models will be represented by more than one row in the database, - // we cannot apply limit/offset directly to the query. If we did that, we'd miss - // some of the records that are to be coalesced into the final set of models. - // Instead, we perform an additional query with grouping and limit/offset to determine - // the desired set of unique model _ids_, and then constrain our final query - // to these models with a whereIn clause. - $relatedKeyName = $this->related->getQualifiedKeyName(); - - // Apply an additional scope to override any selected columns in other global scopes - $uniqueIdScope = function ($subQuery) use ($relatedKeyName) { - $subQuery->select($relatedKeyName) - ->groupBy($relatedKeyName); - }; - - $identifier = spl_object_hash($uniqueIdScope); - - $constrainedBuilder->withGlobalScope($identifier, $uniqueIdScope); - - if ($limit) { - $constrainedBuilder->limit($limit); - } - - if ($offset) { - $constrainedBuilder->offset($offset); - } - - $primaryKeyName = $this->getParent()->getKeyName(); - $modelIds = $constrainedBuilder->get()->pluck($primaryKeyName)->toArray(); - - // Modify the unconstrained query to limit to these models - return $query->whereIn($relatedKeyName, $modelIds); - } - - /** - * Get the full join results for this query, overriding the default getEager() method. - * The default getEager() method would normally just call get() on this relationship. - * This is not what we want here though, because our get() method removes records before - * `match` has a chance to build out the substructures. - * - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getEager() { - return $this->getModels(['*'], FALSE); - } - - /** - * Get the hydrated models and eager load their relations, optionally - * condensing the set of models before performing the eager loads. - * - * @param array $columns - * @param bool $condenseModels - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getModels($columns = ['*'], $condenseModels = TRUE) { - // First we'll add the proper select columns onto the query so it is run with - // the proper columns. Then, we will get the results and hydrate out pivot - // models with the result of those columns as a separate model relation. - $columns = $this->query->getQuery()->columns ? [] : $columns; - - // Add any necessary pagination on the related models - if ($this->limit || $this->offset) { - $this->getPaginatedQuery($this->query, $this->limit, $this->offset); - } - - // Apply scopes to the Eloquent\Builder instance. - $builder = $this->query->applyScopes(); - - $builder = $builder->addSelect( - $this->shouldSelect($columns) - ); - - $models = $builder->getModels(); - - // Hydrate the pivot models so we can load the via models - $this->hydratePivotRelation($models); - - if ($condenseModels) { - $models = $this->condenseModels($models); - } - - // If we actually found models we will also eager load any relationships that - // have been specified as needing to be eager loaded. This will solve the - // n + 1 query problem for the developer and also increase performance. - if (count($models) > 0) { - $models = $builder->eagerLoadRelations($models); - } - - return $this->related->newCollection($models); - } - - /** - * Condense the raw join query results into a set of unique models. - * - * Before doing this, we may optionally find any tertiary models that should be - * set as sub-relations on these models. - * @param array $models - * @return array - */ - protected function condenseModels(array $models) { - // Build dictionary of tertiary models, if `withTertiary` was called - $dictionary = NULL; - if ($this->tertiaryRelated) { - $dictionary = $this->buildTertiaryDictionary($models); - } - - // Remove duplicate models from collection - $models = $this->related->newCollection($models)->unique(); - - // If using withTertiary, use the dictionary to set the tertiary relation on each model. - if (!is_null($dictionary)) { - $this->matchTertiaryModels($dictionary, $models); - } - - return $models->all(); - } - - /** - * Build dictionary of related models keyed by the top-level "parent" id. - * If there is a tertiary query set as well, then also build a two-level dictionary - * that maps parent ids to arrays of related ids, which in turn map to arrays - * of tertiary models corresponding to each relationship. - * - * @param \Illuminate\Database\Eloquent\Collection $results - * @param string $parentKey - * @return array - */ - protected function buildDictionary(Collection $results, $parentKey = NULL) { - // First we will build a dictionary of child models keyed by the "parent key" (foreign key - // of the intermediate relation) so that we will easily and quickly match them to their - // parents without having a possibly slow inner loops for every models. - $dictionary = []; - - //Example nested dictionary: - //[ - // // User 1 - // '1' => [ - // // Permission 3 - // '3' => [ - // Role1, - // Role2 - // ], - // ... - // ], - // ... - //] - $nestedTertiaryDictionary = NULL; - $tertiaryModels = NULL; - - if ($this->tertiaryRelationName) { - // Get all tertiary models from the result set matching any of the parent models. - $tertiaryModels = $this->getTertiaryModels($results->all()); - } - - foreach ($results as $result) { - $parentKeyValue = $result->pivot->$parentKey; - - // Set the related model in the main dictionary. - // Note that this can end up adding duplicate models. It's cheaper to simply - // go back and remove the duplicates when we actually use the dictionary, - // rather than check for duplicates on each insert. - $dictionary[$parentKeyValue][] = $result; - - // If we're loading tertiary models, then set the keys in the nested dictionary as well. - if (!is_null($tertiaryModels)) { - $tertiaryKeyValue = $result->pivot->{$this->tertiaryKey}; - - if (!is_null($tertiaryKeyValue)) { - $tertiaryModel = clone $tertiaryModels[$tertiaryKeyValue]; - - // We also transfer the pivot relation at this point, since we have already coalesced - // any tertiary models into the nested dictionary. - $this->transferPivotsToTertiary($result, $tertiaryModel); - - $nestedTertiaryDictionary[$parentKeyValue][$result->getKey()][] = $tertiaryModel; - } - } - } - - return [$dictionary, $nestedTertiaryDictionary]; - } - - /** - * Build dictionary of tertiary models keyed by the corresponding related model keys. - * - * @param array $models - * @return array - */ - protected function buildTertiaryDictionary(array $models) { - $dictionary = []; - - // Find the related tertiary entities (e.g. tasks) for all related models (e.g. locations) - $tertiaryModels = $this->getTertiaryModels($models); - - // Now for each related model (e.g. location), we will build out a dictionary of their tertiary models (e.g. tasks) - foreach ($models as $model) { - $tertiaryKeyValue = $model->pivot->{$this->tertiaryKey}; - - $tertiaryModel = clone $tertiaryModels[$tertiaryKeyValue]; - - $this->transferPivotsToTertiary($model, $tertiaryModel); - - $dictionary[$model->getKey()][] = $tertiaryModel; - } - - return $dictionary; - } - - protected function transferPivotsToTertiary($model, $tertiaryModel) { - $pivotAttributes = []; - foreach ($this->pivotColumns as $column) { - $pivotAttributes[$column] = $model->pivot->$column; - unset($model->pivot->$column); - } - // Copy the related key pivot as well, but don't unset on the related model - $pivotAttributes[$this->relatedKey] = $model->pivot->{$this->relatedKey}; - - // Set the tertiary key pivot as well - $pivotAttributes[$this->tertiaryKey] = $tertiaryModel->getKey(); - - $pivot = $this->newExistingPivot($pivotAttributes); - $tertiaryModel->setRelation('pivot', $pivot); - } - - /** - * Get the tertiary models for the relationship. - * - * @param array $models - * @return \Illuminate\Database\Eloquent\Collection - */ - protected function getTertiaryModels(array $models) { - $tertiaryClass = $this->tertiaryRelated; - - $keys = []; - foreach ($models as $model) { - $keys[] = $model->getRelation('pivot')->{$this->tertiaryKey}; - } - $keys = array_unique($keys); - - $query = $tertiaryClass->whereIn($tertiaryClass->getQualifiedKeyName(), $keys); - - // Add any additional constraints/eager loads to the tertiary query - $callback = $this->tertiaryCallback; - $callback($query); - - $tertiaryModels = $query - ->get() - ->keyBy($tertiaryClass->getKeyName()); - - return $tertiaryModels; - } - - /** - * Match a collection of child models into a collection of parent models using a dictionary. - * - * @param array $dictionary - * @param \Illuminate\Database\Eloquent\Collection $results - * @return void - */ - protected function matchTertiaryModels(array $dictionary, Collection $results) { - // Now go through and set the tertiary relation on each child model - foreach ($results as $model) { - if (isset($dictionary[$key = $model->getKey()])) { - $tertiaryModels = $dictionary[$key]; - - $model->setRelation( - $this->tertiaryRelationName, $this->tertiaryRelated->newCollection($tertiaryModels) - ); - } - } - } - - /** - * Unset tertiary pivots on a collection or array of models. - * - * @param \Illuminate\Database\Eloquent\Collection $models - * @return void - */ - protected function unsetTertiaryPivots(Collection $models) { - foreach ($models as $model) { - foreach ($this->pivotColumns as $column) { - unset($model->pivot->$column); - } - } - } -} +offset($value); + } + + /** + * Set the "offset" value of the query. + * + * Implement for 'unionOffset' as well? (By checking the value of $this->query->getQuery()->unions) + * @see \Illuminate\Database\Query\Builder + * @param int $value + * @return $this + */ + public function offset($value) { + $this->offset = max(0, $value); + + return $this; + } + + /** + * Alias to set the "limit" value of the query. + * + * @param int $value + * @return $this + */ + public function take($value) { + return $this->limit($value); + } + + /** + * Set the "limit" value of the query. + * + * Implement for 'unionLimit' as well? (By checking the value of $this->query->getQuery()->unions) + * @see \Illuminate\Database\Query\Builder + * @param int $value + * @return $this + */ + public function limit($value) { + if ($value >= 0) { + $this->limit = $value; + } + + return $this; + } + + /** + * Set the limit on the number of intermediate models to load. + * + * @deprecated since 4.1.7 + * @param int $value + * @return $this + */ + public function withLimit($value) { + return $this->limit($value); + } + + /** + * Set the offset when loading the intermediate models. + * + * @deprecated since 4.1.7 + * @param int $value + * @return $this + */ + public function withOffset($value) { + return $this->offset($value); + } + + /** + * Add a query to load the nested tertiary models for this relationship. + * + * @param \Illuminate\Database\Eloquent\Model $tertiaryRelated + * @param string $tertiaryRelationName + * @param string $tertiaryKey + * @param callable $tertiaryCallback + * @return $this + */ + public function withTertiary($tertiaryRelated, $tertiaryRelationName = NULL, $tertiaryKey = NULL, $tertiaryCallback = NULL) { + $this->tertiaryRelated = new $tertiaryRelated; + + // Try to guess the tertiary related key from the tertiaryRelated model. + $this->tertiaryKey = $tertiaryKey ?: $this->tertiaryRelated->getForeignKey(); + + // Also add the tertiary key as a pivot + $this->withPivot($this->tertiaryKey); + + $this->tertiaryRelationName = is_null($tertiaryRelationName) ? $this->tertiaryRelated->getTable() : $tertiaryRelationName; + + $this->tertiaryCallback = is_null($tertiaryCallback) + ? function () { + // + } + : $tertiaryCallback; + + return $this; + } + + /** + * Return the count of child models for this relationship. + * + * @see http://stackoverflow.com/a/29728129/2970321 + * @return int + */ + public function count() { + $constrainedBuilder = clone $this->query; + + $constrainedBuilder = $constrainedBuilder->distinct(); + + return $constrainedBuilder->count($this->relatedKey); + } + + /** + * Add the constraints for a relationship count query. + * + * @see \Illuminate\Database\Eloquent\Relations\Relation + * @param \Illuminate\Database\Eloquent\Builder $query + * @param \Illuminate\Database\Eloquent\Builder $parentQuery + * @return \Illuminate\Database\Eloquent\Builder + */ + public function getRelationExistenceCountQuery(Builder $query, Builder $parentQuery) { + return $this->getRelationExistenceQuery( + $query, $parentQuery, new Expression("count(distinct {$this->relatedKey})") + ); + } + + /** + * Match the eagerly loaded results to their parents + * + * @param array $models + * @param \Illuminate\Database\Eloquent\Collection $results + * @param string $relation + * @return array + */ + public function match(array $models, Collection $results, $relation) { + // Build dictionary of parent (e.g. user) to related (e.g. permission) models + list($dictionary, $nestedTertiaryDictionary) = $this->buildDictionary($results, $this->foreignKey); + + // Once we have an array dictionary of child objects we can easily match the + // children back to their parent using the dictionary and the keys on the + // the parent models. Then we will return the hydrated models back out. + foreach ($models as $model) { + if (isset($dictionary[$key = $model->getKey()])) { + /** @var array */ + $items = $dictionary[$key]; + + // Eliminate any duplicates + $items = $this->related->newCollection($items)->unique(); + + // If set, match up the tertiary models to the models in the related collection + if (!is_null($nestedTertiaryDictionary)) { + $this->matchTertiaryModels($nestedTertiaryDictionary[$key], $items); + } + + $model->setRelation( + $relation, $items + ); + } + } + + return $models; + } + + /** + * Execute the query as a "select" statement, getting all requested models + * and matching up any tertiary models. + * + * @param array $columns + * @return \Illuminate\Database\Eloquent\Collection + */ + public function get($columns = ['*']) { + // Get models and condense the result set + $models = $this->getModels($columns, TRUE); + + // Remove the tertiary pivot key from the condensed models + $this->unsetTertiaryPivots($models); + + return $models; + } + + /** + * If we are applying either a limit or offset, we'll first determine a limited/offset list of model ids + * to select from in the final query. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param int $limit + * @param int $offset + * @return \Illuminate\Database\Eloquent\Builder + */ + public function getPaginatedQuery(Builder $query, $limit = NULL, $offset = NULL) { + $constrainedBuilder = clone $query; + + // Since some unique models will be represented by more than one row in the database, + // we cannot apply limit/offset directly to the query. If we did that, we'd miss + // some of the records that are to be coalesced into the final set of models. + // Instead, we perform an additional query with grouping and limit/offset to determine + // the desired set of unique model _ids_, and then constrain our final query + // to these models with a whereIn clause. + $relatedKeyName = $this->related->getQualifiedKeyName(); + + // Apply an additional scope to override any selected columns in other global scopes + $uniqueIdScope = function ($subQuery) use ($relatedKeyName) { + $subQuery->select($relatedKeyName) + ->groupBy($relatedKeyName); + }; + + $identifier = spl_object_hash($uniqueIdScope); + + $constrainedBuilder->withGlobalScope($identifier, $uniqueIdScope); + + if ($limit) { + $constrainedBuilder->limit($limit); + } + + if ($offset) { + $constrainedBuilder->offset($offset); + } + + $primaryKeyName = $this->getParent()->getKeyName(); + $modelIds = $constrainedBuilder->get()->pluck($primaryKeyName)->toArray(); + + // Modify the unconstrained query to limit to these models + return $query->whereIn($relatedKeyName, $modelIds); + } + + /** + * Get the full join results for this query, overriding the default getEager() method. + * The default getEager() method would normally just call get() on this relationship. + * This is not what we want here though, because our get() method removes records before + * `match` has a chance to build out the substructures. + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function getEager() { + return $this->getModels(['*'], FALSE); + } + + /** + * Get the hydrated models and eager load their relations, optionally + * condensing the set of models before performing the eager loads. + * + * @param array $columns + * @param bool $condenseModels + * @return \Illuminate\Database\Eloquent\Collection + */ + public function getModels($columns = ['*'], $condenseModels = TRUE) { + // First we'll add the proper select columns onto the query so it is run with + // the proper columns. Then, we will get the results and hydrate out pivot + // models with the result of those columns as a separate model relation. + $columns = $this->query->getQuery()->columns ? [] : $columns; + + // Add any necessary pagination on the related models + if ($this->limit || $this->offset) { + $this->getPaginatedQuery($this->query, $this->limit, $this->offset); + } + + // Apply scopes to the Eloquent\Builder instance. + $builder = $this->query->applyScopes(); + + $builder = $builder->addSelect( + $this->shouldSelect($columns) + ); + + $models = $builder->getModels(); + + // Hydrate the pivot models so we can load the via models + $this->hydratePivotRelation($models); + + if ($condenseModels) { + $models = $this->condenseModels($models); + } + + // If we actually found models we will also eager load any relationships that + // have been specified as needing to be eager loaded. This will solve the + // n + 1 query problem for the developer and also increase performance. + if (count($models) > 0) { + $models = $builder->eagerLoadRelations($models); + } + + return $this->related->newCollection($models); + } + + /** + * Condense the raw join query results into a set of unique models. + * + * Before doing this, we may optionally find any tertiary models that should be + * set as sub-relations on these models. + * @param array $models + * @return array + */ + protected function condenseModels(array $models) { + // Build dictionary of tertiary models, if `withTertiary` was called + $dictionary = NULL; + if ($this->tertiaryRelated) { + $dictionary = $this->buildTertiaryDictionary($models); + } + + // Remove duplicate models from collection + $models = $this->related->newCollection($models)->unique(); + + // If using withTertiary, use the dictionary to set the tertiary relation on each model. + if (!is_null($dictionary)) { + $this->matchTertiaryModels($dictionary, $models); + } + + return $models->all(); + } + + /** + * Build dictionary of related models keyed by the top-level "parent" id. + * If there is a tertiary query set as well, then also build a two-level dictionary + * that maps parent ids to arrays of related ids, which in turn map to arrays + * of tertiary models corresponding to each relationship. + * + * @param \Illuminate\Database\Eloquent\Collection $results + * @param string $parentKey + * @return array + */ + protected function buildDictionary(Collection $results, $parentKey = NULL) { + // First we will build a dictionary of child models keyed by the "parent key" (foreign key + // of the intermediate relation) so that we will easily and quickly match them to their + // parents without having a possibly slow inner loops for every models. + $dictionary = []; + + //Example nested dictionary: + //[ + // // User 1 + // '1' => [ + // // Permission 3 + // '3' => [ + // Role1, + // Role2 + // ], + // ... + // ], + // ... + //] + $nestedTertiaryDictionary = NULL; + $tertiaryModels = NULL; + + if ($this->tertiaryRelationName) { + // Get all tertiary models from the result set matching any of the parent models. + $tertiaryModels = $this->getTertiaryModels($results->all()); + } + + foreach ($results as $result) { + $parentKeyValue = $result->pivot->$parentKey; + + // Set the related model in the main dictionary. + // Note that this can end up adding duplicate models. It's cheaper to simply + // go back and remove the duplicates when we actually use the dictionary, + // rather than check for duplicates on each insert. + $dictionary[$parentKeyValue][] = $result; + + // If we're loading tertiary models, then set the keys in the nested dictionary as well. + if (!is_null($tertiaryModels)) { + $tertiaryKeyValue = $result->pivot->{$this->tertiaryKey}; + + if (!is_null($tertiaryKeyValue)) { + $tertiaryModel = clone $tertiaryModels[$tertiaryKeyValue]; + + // We also transfer the pivot relation at this point, since we have already coalesced + // any tertiary models into the nested dictionary. + $this->transferPivotsToTertiary($result, $tertiaryModel); + + $nestedTertiaryDictionary[$parentKeyValue][$result->getKey()][] = $tertiaryModel; + } + } + } + + return [$dictionary, $nestedTertiaryDictionary]; + } + + /** + * Build dictionary of tertiary models keyed by the corresponding related model keys. + * + * @param array $models + * @return array + */ + protected function buildTertiaryDictionary(array $models) { + $dictionary = []; + + // Find the related tertiary entities (e.g. tasks) for all related models (e.g. locations) + $tertiaryModels = $this->getTertiaryModels($models); + + // Now for each related model (e.g. location), we will build out a dictionary of their tertiary models (e.g. tasks) + foreach ($models as $model) { + $tertiaryKeyValue = $model->pivot->{$this->tertiaryKey}; + + $tertiaryModel = clone $tertiaryModels[$tertiaryKeyValue]; + + $this->transferPivotsToTertiary($model, $tertiaryModel); + + $dictionary[$model->getKey()][] = $tertiaryModel; + } + + return $dictionary; + } + + protected function transferPivotsToTertiary($model, $tertiaryModel) { + $pivotAttributes = []; + foreach ($this->pivotColumns as $column) { + $pivotAttributes[$column] = $model->pivot->$column; + unset($model->pivot->$column); + } + // Copy the related key pivot as well, but don't unset on the related model + $pivotAttributes[$this->relatedKey] = $model->pivot->{$this->relatedKey}; + + // Set the tertiary key pivot as well + $pivotAttributes[$this->tertiaryKey] = $tertiaryModel->getKey(); + + $pivot = $this->newExistingPivot($pivotAttributes); + $tertiaryModel->setRelation('pivot', $pivot); + } + + /** + * Get the tertiary models for the relationship. + * + * @param array $models + * @return \Illuminate\Database\Eloquent\Collection + */ + protected function getTertiaryModels(array $models) { + $tertiaryClass = $this->tertiaryRelated; + + $keys = []; + foreach ($models as $model) { + $keys[] = $model->getRelation('pivot')->{$this->tertiaryKey}; + } + $keys = array_unique($keys); + + $query = $tertiaryClass->whereIn($tertiaryClass->getQualifiedKeyName(), $keys); + + // Add any additional constraints/eager loads to the tertiary query + $callback = $this->tertiaryCallback; + $callback($query); + + $tertiaryModels = $query + ->get() + ->keyBy($tertiaryClass->getKeyName()); + + return $tertiaryModels; + } + + /** + * Match a collection of child models into a collection of parent models using a dictionary. + * + * @param array $dictionary + * @param \Illuminate\Database\Eloquent\Collection $results + * @return void + */ + protected function matchTertiaryModels(array $dictionary, Collection $results) { + // Now go through and set the tertiary relation on each child model + foreach ($results as $model) { + if (isset($dictionary[$key = $model->getKey()])) { + $tertiaryModels = $dictionary[$key]; + + $model->setRelation( + $this->tertiaryRelationName, $this->tertiaryRelated->newCollection($tertiaryModels) + ); + } + } + } + + /** + * Unset tertiary pivots on a collection or array of models. + * + * @param \Illuminate\Database\Eloquent\Collection $models + * @return void + */ + protected function unsetTertiaryPivots(Collection $models) { + foreach ($models as $model) { + foreach ($this->pivotColumns as $column) { + unset($model->pivot->$column); + } + } + } +} diff --git a/main/app/sprinkles/core/src/Database/Relations/HasManySyncable.php b/main/app/sprinkles/core/src/Database/Relations/HasManySyncable.php index 9d85b1f..d09e25d 100644 --- a/main/app/sprinkles/core/src/Database/Relations/HasManySyncable.php +++ b/main/app/sprinkles/core/src/Database/Relations/HasManySyncable.php @@ -1,23 +1,23 @@ -ci = $ci; - $this->displayErrorDetails = (bool)$displayErrorDetails; - } - - /** - * Invoke error handler - * - * @param ServerRequestInterface $request The most recent Request object - * @param ResponseInterface $response The most recent Response object - * @param Throwable $exception The caught Exception object - * - * @return ResponseInterface - */ - public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $exception) { - // Default exception handler class - $handlerClass = '\UserFrosting\Sprinkle\Core\Error\Handler\ExceptionHandler'; - - // Get the last matching registered handler class, and instantiate it - foreach ($this->exceptionHandlers as $exceptionClass => $matchedHandlerClass) { - if ($exception instanceof $exceptionClass) { - $handlerClass = $matchedHandlerClass; - } - } - - $handler = new $handlerClass($this->ci, $request, $response, $exception, $this->displayErrorDetails); - - return $handler->handle(); - } - - /** - * Register an exception handler for a specified exception class. - * - * The exception handler must implement \UserFrosting\Sprinkle\Core\Handler\ExceptionHandlerInterface. - * - * @param string $exceptionClass The fully qualified class name of the exception to handle. - * @param string $handlerClass The fully qualified class name of the assigned handler. - * @throws InvalidArgumentException If the registered handler fails to implement ExceptionHandlerInterface - */ - public function registerHandler($exceptionClass, $handlerClass) { - if (!is_a($handlerClass, '\UserFrosting\Sprinkle\Core\Error\Handler\ExceptionHandlerInterface', TRUE)) { - throw new \InvalidArgumentException("Registered exception handler must implement ExceptionHandlerInterface!"); - } - - $this->exceptionHandlers[$exceptionClass] = $handlerClass; - } -} +ci = $ci; + $this->displayErrorDetails = (bool)$displayErrorDetails; + } + + /** + * Invoke error handler + * + * @param ServerRequestInterface $request The most recent Request object + * @param ResponseInterface $response The most recent Response object + * @param Throwable $exception The caught Exception object + * + * @return ResponseInterface + */ + public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $exception) { + // Default exception handler class + $handlerClass = '\UserFrosting\Sprinkle\Core\Error\Handler\ExceptionHandler'; + + // Get the last matching registered handler class, and instantiate it + foreach ($this->exceptionHandlers as $exceptionClass => $matchedHandlerClass) { + if ($exception instanceof $exceptionClass) { + $handlerClass = $matchedHandlerClass; + } + } + + $handler = new $handlerClass($this->ci, $request, $response, $exception, $this->displayErrorDetails); + + return $handler->handle(); + } + + /** + * Register an exception handler for a specified exception class. + * + * The exception handler must implement \UserFrosting\Sprinkle\Core\Handler\ExceptionHandlerInterface. + * + * @param string $exceptionClass The fully qualified class name of the exception to handle. + * @param string $handlerClass The fully qualified class name of the assigned handler. + * @throws InvalidArgumentException If the registered handler fails to implement ExceptionHandlerInterface + */ + public function registerHandler($exceptionClass, $handlerClass) { + if (!is_a($handlerClass, '\UserFrosting\Sprinkle\Core\Error\Handler\ExceptionHandlerInterface', TRUE)) { + throw new \InvalidArgumentException("Registered exception handler must implement ExceptionHandlerInterface!"); + } + + $this->exceptionHandlers[$exceptionClass] = $handlerClass; + } +} diff --git a/main/app/sprinkles/core/src/Error/Handler/ExceptionHandler.php b/main/app/sprinkles/core/src/Error/Handler/ExceptionHandler.php index 89e890e..1ce5954 100644 --- a/main/app/sprinkles/core/src/Error/Handler/ExceptionHandler.php +++ b/main/app/sprinkles/core/src/Error/Handler/ExceptionHandler.php @@ -1,267 +1,267 @@ -ci = $ci; - $this->request = $request; - $this->response = $response; - $this->exception = $exception; - $this->displayErrorDetails = $displayErrorDetails; - $this->statusCode = $this->determineStatusCode(); - $this->contentType = $this->determineContentType($request, $this->ci->config['site.debug.ajax']); - $this->renderer = $this->determineRenderer(); - } - - /** - * Handle the caught exception. - * The handler may render a detailed debugging error page, a generic error page, write to logs, and/or add messages to the alert stream. - * - * @return ResponseInterface - */ - public function handle() { - // If displayErrorDetails is set to true, we'll halt and immediately respond with a detailed debugging page. - // We do not log errors in this case. - if ($this->displayErrorDetails) { - $response = $this->renderDebugResponse(); - } else { - // Write exception to log - $this->writeToErrorLog(); - - // Render generic error page - $response = $this->renderGenericResponse(); - } - - // If this is an AJAX request and AJAX debugging is turned off, write messages to the alert stream - if ($this->request->isXhr() && !$this->ci->config['site.debug.ajax']) { - $this->writeAlerts(); - } - - return $response; - } - - /** - * Render a detailed response with debugging information. - * - * @return ResponseInterface - */ - public function renderDebugResponse() { - $body = $this->renderer->renderWithBody(); - - return $this->response - ->withStatus($this->statusCode) - ->withHeader('Content-type', $this->contentType) - ->withBody($body); - } - - /** - * Render a generic, user-friendly response without sensitive debugging information. - * - * @return ResponseInterface - */ - public function renderGenericResponse() { - $messages = $this->determineUserMessages(); - $httpCode = $this->statusCode; - - try { - $template = $this->ci->view->getEnvironment()->loadTemplate("pages/error/$httpCode.html.twig"); - } catch (\Twig_Error_Loader $e) { - $template = $this->ci->view->getEnvironment()->loadTemplate("pages/abstract/error.html.twig"); - } - - return $this->response - ->withStatus($httpCode) - ->withHeader('Content-type', $this->contentType) - ->write($template->render([ - 'messages' => $messages - ])); - } - - /** - * Write to the error log - * - * @return void - */ - public function writeToErrorLog() { - $renderer = new PlainTextRenderer($this->request, $this->response, $this->exception, TRUE); - $error = $renderer->render(); - $error .= PHP_EOL . 'View in rendered output by enabling the "displayErrorDetails" setting.' . PHP_EOL; - $this->logError($error); - } - - /** - * Write user-friendly error messages to the alert message stream. - * - * @return void - */ - public function writeAlerts() { - $messages = $this->determineUserMessages(); - - foreach ($messages as $message) { - $this->ci->alerts->addMessageTranslated('danger', $message->message, $message->parameters); - } - } - - /** - * Determine which renderer to use based on content type - * Overloaded $renderer from calling class takes precedence over all - * - * @return ErrorRendererInterface - * - * @throws \RuntimeException - */ - protected function determineRenderer() { - $renderer = $this->renderer; - - if ((!is_null($renderer) && !class_exists($renderer)) - || (!is_null($renderer) && !in_array('UserFrosting\Sprinkle\Core\Error\Renderer\ErrorRendererInterface', class_implements($renderer))) - ) { - throw new \RuntimeException(sprintf( - 'Non compliant error renderer provided (%s). ' . - 'Renderer must implement the ErrorRendererInterface', - $renderer - )); - } - - if (is_null($renderer)) { - switch ($this->contentType) { - case 'application/json': - $renderer = JsonRenderer::class; - break; - - case 'text/xml': - case 'application/xml': - $renderer = XmlRenderer::class; - break; - - case 'text/plain': - $renderer = PlainTextRenderer::class; - break; - - default: - case 'text/html': - $renderer = WhoopsRenderer::class; - break; - } - } - - return new $renderer($this->request, $this->response, $this->exception, $this->displayErrorDetails); - } - - /** - * Resolve the status code to return in the response from this handler. - * - * @return int - */ - protected function determineStatusCode() { - if ($this->request->getMethod() === 'OPTIONS') { - return 200; - } - return 500; - } - - /** - * Resolve a list of error messages to present to the end user. - * - * @return array - */ - protected function determineUserMessages() { - return [ - new UserMessage("ERROR.SERVER") - ]; - } - - /** - * Monolog logging for errors - * - * @param $message - * @return void - */ - protected function logError($message) { - $this->ci->errorLogger->error($message); - } -} +ci = $ci; + $this->request = $request; + $this->response = $response; + $this->exception = $exception; + $this->displayErrorDetails = $displayErrorDetails; + $this->statusCode = $this->determineStatusCode(); + $this->contentType = $this->determineContentType($request, $this->ci->config['site.debug.ajax']); + $this->renderer = $this->determineRenderer(); + } + + /** + * Handle the caught exception. + * The handler may render a detailed debugging error page, a generic error page, write to logs, and/or add messages to the alert stream. + * + * @return ResponseInterface + */ + public function handle() { + // If displayErrorDetails is set to true, we'll halt and immediately respond with a detailed debugging page. + // We do not log errors in this case. + if ($this->displayErrorDetails) { + $response = $this->renderDebugResponse(); + } else { + // Write exception to log + $this->writeToErrorLog(); + + // Render generic error page + $response = $this->renderGenericResponse(); + } + + // If this is an AJAX request and AJAX debugging is turned off, write messages to the alert stream + if ($this->request->isXhr() && !$this->ci->config['site.debug.ajax']) { + $this->writeAlerts(); + } + + return $response; + } + + /** + * Render a detailed response with debugging information. + * + * @return ResponseInterface + */ + public function renderDebugResponse() { + $body = $this->renderer->renderWithBody(); + + return $this->response + ->withStatus($this->statusCode) + ->withHeader('Content-type', $this->contentType) + ->withBody($body); + } + + /** + * Render a generic, user-friendly response without sensitive debugging information. + * + * @return ResponseInterface + */ + public function renderGenericResponse() { + $messages = $this->determineUserMessages(); + $httpCode = $this->statusCode; + + try { + $template = $this->ci->view->getEnvironment()->loadTemplate("pages/error/$httpCode.html.twig"); + } catch (\Twig_Error_Loader $e) { + $template = $this->ci->view->getEnvironment()->loadTemplate("pages/abstract/error.html.twig"); + } + + return $this->response + ->withStatus($httpCode) + ->withHeader('Content-type', $this->contentType) + ->write($template->render([ + 'messages' => $messages + ])); + } + + /** + * Write to the error log + * + * @return void + */ + public function writeToErrorLog() { + $renderer = new PlainTextRenderer($this->request, $this->response, $this->exception, TRUE); + $error = $renderer->render(); + $error .= PHP_EOL . 'View in rendered output by enabling the "displayErrorDetails" setting.' . PHP_EOL; + $this->logError($error); + } + + /** + * Write user-friendly error messages to the alert message stream. + * + * @return void + */ + public function writeAlerts() { + $messages = $this->determineUserMessages(); + + foreach ($messages as $message) { + $this->ci->alerts->addMessageTranslated('danger', $message->message, $message->parameters); + } + } + + /** + * Determine which renderer to use based on content type + * Overloaded $renderer from calling class takes precedence over all + * + * @return ErrorRendererInterface + * + * @throws \RuntimeException + */ + protected function determineRenderer() { + $renderer = $this->renderer; + + if ((!is_null($renderer) && !class_exists($renderer)) + || (!is_null($renderer) && !in_array('UserFrosting\Sprinkle\Core\Error\Renderer\ErrorRendererInterface', class_implements($renderer))) + ) { + throw new \RuntimeException(sprintf( + 'Non compliant error renderer provided (%s). ' . + 'Renderer must implement the ErrorRendererInterface', + $renderer + )); + } + + if (is_null($renderer)) { + switch ($this->contentType) { + case 'application/json': + $renderer = JsonRenderer::class; + break; + + case 'text/xml': + case 'application/xml': + $renderer = XmlRenderer::class; + break; + + case 'text/plain': + $renderer = PlainTextRenderer::class; + break; + + default: + case 'text/html': + $renderer = WhoopsRenderer::class; + break; + } + } + + return new $renderer($this->request, $this->response, $this->exception, $this->displayErrorDetails); + } + + /** + * Resolve the status code to return in the response from this handler. + * + * @return int + */ + protected function determineStatusCode() { + if ($this->request->getMethod() === 'OPTIONS') { + return 200; + } + return 500; + } + + /** + * Resolve a list of error messages to present to the end user. + * + * @return array + */ + protected function determineUserMessages() { + return [ + new UserMessage("ERROR.SERVER") + ]; + } + + /** + * Monolog logging for errors + * + * @param $message + * @return void + */ + protected function logError($message) { + $this->ci->errorLogger->error($message); + } +} diff --git a/main/app/sprinkles/core/src/Error/Handler/ExceptionHandlerInterface.php b/main/app/sprinkles/core/src/Error/Handler/ExceptionHandlerInterface.php index 2ac9ada..2905382 100644 --- a/main/app/sprinkles/core/src/Error/Handler/ExceptionHandlerInterface.php +++ b/main/app/sprinkles/core/src/Error/Handler/ExceptionHandlerInterface.php @@ -1,33 +1,33 @@ -statusCode != 500) { - return; - } - - parent::writeToErrorLog(); - } - - /** - * Resolve the status code to return in the response from this handler. - * - * @return int - */ - protected function determineStatusCode() { - if ($this->request->getMethod() === 'OPTIONS') { - return 200; - } else if ($this->exception instanceof HttpException) { - return $this->exception->getHttpErrorCode(); - } - return 500; - } - - /** - * Resolve a list of error messages to present to the end user. - * - * @return array - */ - protected function determineUserMessages() { - if ($this->exception instanceof HttpException) { - return $this->exception->getUserMessages(); - } - - // Fallback - return [ - new UserMessage("ERROR.SERVER") - ]; - } -} +statusCode != 500) { + return; + } + + parent::writeToErrorLog(); + } + + /** + * Resolve the status code to return in the response from this handler. + * + * @return int + */ + protected function determineStatusCode() { + if ($this->request->getMethod() === 'OPTIONS') { + return 200; + } else if ($this->exception instanceof HttpException) { + return $this->exception->getHttpErrorCode(); + } + return 500; + } + + /** + * Resolve a list of error messages to present to the end user. + * + * @return array + */ + protected function determineUserMessages() { + if ($this->exception instanceof HttpException) { + return $this->exception->getUserMessages(); + } + + // Fallback + return [ + new UserMessage("ERROR.SERVER") + ]; + } +} diff --git a/main/app/sprinkles/core/src/Error/Handler/NotFoundExceptionHandler.php b/main/app/sprinkles/core/src/Error/Handler/NotFoundExceptionHandler.php index a866cc3..e243a02 100644 --- a/main/app/sprinkles/core/src/Error/Handler/NotFoundExceptionHandler.php +++ b/main/app/sprinkles/core/src/Error/Handler/NotFoundExceptionHandler.php @@ -1,38 +1,38 @@ -renderGenericResponse(); - - // If this is an AJAX request and AJAX debugging is turned off, write messages to the alert stream - if ($this->request->isXhr() && !$this->ci->config['site.debug.ajax']) { - $this->writeAlerts(); - } - - return $response; - } -} +renderGenericResponse(); + + // If this is an AJAX request and AJAX debugging is turned off, write messages to the alert stream + if ($this->request->isXhr() && !$this->ci->config['site.debug.ajax']) { + $this->writeAlerts(); + } + + return $response; + } +} diff --git a/main/app/sprinkles/core/src/Error/Handler/PhpMailerExceptionHandler.php b/main/app/sprinkles/core/src/Error/Handler/PhpMailerExceptionHandler.php index e7117e9..15e16f8 100644 --- a/main/app/sprinkles/core/src/Error/Handler/PhpMailerExceptionHandler.php +++ b/main/app/sprinkles/core/src/Error/Handler/PhpMailerExceptionHandler.php @@ -1,30 +1,30 @@ -request = $request; - $this->response = $response; - $this->exception = $exception; - $this->displayErrorDetails = $displayErrorDetails; - } - - abstract public function render(); - - /** - * @return Body - */ - public function renderWithBody() { - $body = new Body(fopen('php://temp', 'r+')); - $body->write($this->render()); - return $body; - } -} +request = $request; + $this->response = $response; + $this->exception = $exception; + $this->displayErrorDetails = $displayErrorDetails; + } + + abstract public function render(); + + /** + * @return Body + */ + public function renderWithBody() { + $body = new Body(fopen('php://temp', 'r+')); + $body->write($this->render()); + return $body; + } +} diff --git a/main/app/sprinkles/core/src/Error/Renderer/ErrorRendererInterface.php b/main/app/sprinkles/core/src/Error/Renderer/ErrorRendererInterface.php index efb0bd6..1633a8b 100644 --- a/main/app/sprinkles/core/src/Error/Renderer/ErrorRendererInterface.php +++ b/main/app/sprinkles/core/src/Error/Renderer/ErrorRendererInterface.php @@ -1,30 +1,30 @@ -displayErrorDetails) { - $html = '

The application could not run because of the following error:

'; - $html .= '

Details

'; - $html .= $this->renderException($this->exception); - - $html .= '

Your request

'; - $html .= $this->renderRequest(); - - $html .= '

Response headers

'; - $html .= $this->renderResponseHeaders(); - - $exception = $this->exception; - while ($exception = $exception->getPrevious()) { - $html .= '

Previous exception

'; - $html .= $this->renderException($exception); - } - } else { - $html = '

A website error has occurred. Sorry for the temporary inconvenience.

'; - } - - $output = sprintf( - "" . - "%s

%s

%s", - $title, - $title, - $html - ); - - return $output; - } - - /** - * Render a summary of the exception. - * - * @param Exception $exception - * @return string - */ - public function renderException($exception) { - $html = sprintf('
Type: %s
', get_class($exception)); - - if (($code = $exception->getCode())) { - $html .= sprintf('
Code: %s
', $code); - } - - if (($message = $exception->getMessage())) { - $html .= sprintf('
Message: %s
', htmlentities($message)); - } - - if (($file = $exception->getFile())) { - $html .= sprintf('
File: %s
', $file); - } - - if (($line = $exception->getLine())) { - $html .= sprintf('
Line: %s
', $line); - } - - if (($trace = $exception->getTraceAsString())) { - $html .= '

Trace

'; - $html .= sprintf('
%s
', htmlentities($trace)); - } - - return $html; - } - - /** - * Render HTML representation of original request. - * - * @return string - */ - public function renderRequest() { - $method = $this->request->getMethod(); - $uri = $this->request->getUri(); - $params = $this->request->getParams(); - $requestHeaders = $this->request->getHeaders(); - - $html = '

Request URI:

'; - - $html .= sprintf('
%s %s
', $method, $uri); - - $html .= '

Request parameters:

'; - - $html .= $this->renderTable($params); - - $html .= '

Request headers:

'; - - $html .= $this->renderTable($requestHeaders); - - return $html; - } - - /** - * Render HTML representation of response headers. - * - * @return string - */ - public function renderResponseHeaders() { - $html = '

Response headers:

'; - $html .= 'Additional response headers may have been set by Slim after the error handling routine. Please check your browser console for a complete list.
'; - - $html .= $this->renderTable($this->response->getHeaders()); - - return $html; - } - - /** - * Render HTML representation of a table of data. - * - * @param mixed[] $data the array of data to render. - * - * @return string - */ - protected function renderTable($data) { - $html = ''; - foreach ($data as $name => $value) { - $value = print_r($value, TRUE); - $html .= ""; - } - $html .= '
NameValue
$name$value
'; - - return $html; - } -} +displayErrorDetails) { + $html = '

The application could not run because of the following error:

'; + $html .= '

Details

'; + $html .= $this->renderException($this->exception); + + $html .= '

Your request

'; + $html .= $this->renderRequest(); + + $html .= '

Response headers

'; + $html .= $this->renderResponseHeaders(); + + $exception = $this->exception; + while ($exception = $exception->getPrevious()) { + $html .= '

Previous exception

'; + $html .= $this->renderException($exception); + } + } else { + $html = '

A website error has occurred. Sorry for the temporary inconvenience.

'; + } + + $output = sprintf( + "" . + "%s

%s

%s", + $title, + $title, + $html + ); + + return $output; + } + + /** + * Render a summary of the exception. + * + * @param Exception $exception + * @return string + */ + public function renderException($exception) { + $html = sprintf('
Type: %s
', get_class($exception)); + + if (($code = $exception->getCode())) { + $html .= sprintf('
Code: %s
', $code); + } + + if (($message = $exception->getMessage())) { + $html .= sprintf('
Message: %s
', htmlentities($message)); + } + + if (($file = $exception->getFile())) { + $html .= sprintf('
File: %s
', $file); + } + + if (($line = $exception->getLine())) { + $html .= sprintf('
Line: %s
', $line); + } + + if (($trace = $exception->getTraceAsString())) { + $html .= '

Trace

'; + $html .= sprintf('
%s
', htmlentities($trace)); + } + + return $html; + } + + /** + * Render HTML representation of original request. + * + * @return string + */ + public function renderRequest() { + $method = $this->request->getMethod(); + $uri = $this->request->getUri(); + $params = $this->request->getParams(); + $requestHeaders = $this->request->getHeaders(); + + $html = '

Request URI:

'; + + $html .= sprintf('
%s %s
', $method, $uri); + + $html .= '

Request parameters:

'; + + $html .= $this->renderTable($params); + + $html .= '

Request headers:

'; + + $html .= $this->renderTable($requestHeaders); + + return $html; + } + + /** + * Render HTML representation of response headers. + * + * @return string + */ + public function renderResponseHeaders() { + $html = '

Response headers:

'; + $html .= 'Additional response headers may have been set by Slim after the error handling routine. Please check your browser console for a complete list.
'; + + $html .= $this->renderTable($this->response->getHeaders()); + + return $html; + } + + /** + * Render HTML representation of a table of data. + * + * @param mixed[] $data the array of data to render. + * + * @return string + */ + protected function renderTable($data) { + $html = ''; + foreach ($data as $name => $value) { + $value = print_r($value, TRUE); + $html .= ""; + } + $html .= '
NameValue
$name$value
'; + + return $html; + } +} diff --git a/main/app/sprinkles/core/src/Error/Renderer/JsonRenderer.php b/main/app/sprinkles/core/src/Error/Renderer/JsonRenderer.php index 6a96780..eb1ddd2 100644 --- a/main/app/sprinkles/core/src/Error/Renderer/JsonRenderer.php +++ b/main/app/sprinkles/core/src/Error/Renderer/JsonRenderer.php @@ -1,55 +1,55 @@ -exception->getMessage(); - return $this->formatExceptionPayload($message); - } - - /** - * @param $message - * @return string - */ - public function formatExceptionPayload($message) { - $e = $this->exception; - $error = ['message' => $message]; - - if ($this->displayErrorDetails) { - $error['exception'] = []; - do { - $error['exception'][] = $this->formatExceptionFragment($e); - } while ($e = $e->getPrevious()); - } - - return json_encode($error, JSON_PRETTY_PRINT); - } - - /** - * @param \Exception|\Throwable $e - * @return array - */ - public function formatExceptionFragment($e) { - return [ - 'type' => get_class($e), - 'code' => $e->getCode(), - 'message' => $e->getMessage(), - 'file' => $e->getFile(), - 'line' => $e->getLine(), - ]; - } -} +exception->getMessage(); + return $this->formatExceptionPayload($message); + } + + /** + * @param $message + * @return string + */ + public function formatExceptionPayload($message) { + $e = $this->exception; + $error = ['message' => $message]; + + if ($this->displayErrorDetails) { + $error['exception'] = []; + do { + $error['exception'][] = $this->formatExceptionFragment($e); + } while ($e = $e->getPrevious()); + } + + return json_encode($error, JSON_PRETTY_PRINT); + } + + /** + * @param \Exception|\Throwable $e + * @return array + */ + public function formatExceptionFragment($e) { + return [ + 'type' => get_class($e), + 'code' => $e->getCode(), + 'message' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + ]; + } +} diff --git a/main/app/sprinkles/core/src/Error/Renderer/PlainTextRenderer.php b/main/app/sprinkles/core/src/Error/Renderer/PlainTextRenderer.php index 9922f22..847681e 100644 --- a/main/app/sprinkles/core/src/Error/Renderer/PlainTextRenderer.php +++ b/main/app/sprinkles/core/src/Error/Renderer/PlainTextRenderer.php @@ -1,63 +1,63 @@ -displayErrorDetails) { - return $this->formatExceptionBody(); - } - - return $this->exception->getMessage(); - } - - public function formatExceptionBody() { - $e = $this->exception; - - $text = 'UserFrosting Application Error:' . PHP_EOL; - $text .= $this->formatExceptionFragment($e); - - while ($e = $e->getPrevious()) { - $text .= PHP_EOL . 'Previous Error:' . PHP_EOL; - $text .= $this->formatExceptionFragment($e); - } - - return $text; - } - - /** - * @param \Exception|\Throwable $e - * @return string - */ - public function formatExceptionFragment($e) { - $text = sprintf('Type: %s' . PHP_EOL, get_class($e)); - - if ($code = $e->getCode()) { - $text .= sprintf('Code: %s' . PHP_EOL, $code); - } - if ($message = $e->getMessage()) { - $text .= sprintf('Message: %s' . PHP_EOL, htmlentities($message)); - } - if ($file = $e->getFile()) { - $text .= sprintf('File: %s' . PHP_EOL, $file); - } - if ($line = $e->getLine()) { - $text .= sprintf('Line: %s' . PHP_EOL, $line); - } - if ($trace = $e->getTraceAsString()) { - $text .= sprintf('Trace: %s', $trace); - } - - return $text; - } -} +displayErrorDetails) { + return $this->formatExceptionBody(); + } + + return $this->exception->getMessage(); + } + + public function formatExceptionBody() { + $e = $this->exception; + + $text = 'UserFrosting Application Error:' . PHP_EOL; + $text .= $this->formatExceptionFragment($e); + + while ($e = $e->getPrevious()) { + $text .= PHP_EOL . 'Previous Error:' . PHP_EOL; + $text .= $this->formatExceptionFragment($e); + } + + return $text; + } + + /** + * @param \Exception|\Throwable $e + * @return string + */ + public function formatExceptionFragment($e) { + $text = sprintf('Type: %s' . PHP_EOL, get_class($e)); + + if ($code = $e->getCode()) { + $text .= sprintf('Code: %s' . PHP_EOL, $code); + } + if ($message = $e->getMessage()) { + $text .= sprintf('Message: %s' . PHP_EOL, htmlentities($message)); + } + if ($file = $e->getFile()) { + $text .= sprintf('File: %s' . PHP_EOL, $file); + } + if ($line = $e->getLine()) { + $text .= sprintf('Line: %s' . PHP_EOL, $line); + } + if ($trace = $e->getTraceAsString()) { + $text .= sprintf('Trace: %s', $trace); + } + + return $text; + } +} diff --git a/main/app/sprinkles/core/src/Error/Renderer/WhoopsRenderer.php b/main/app/sprinkles/core/src/Error/Renderer/WhoopsRenderer.php index 4113470..d16d048 100644 --- a/main/app/sprinkles/core/src/Error/Renderer/WhoopsRenderer.php +++ b/main/app/sprinkles/core/src/Error/Renderer/WhoopsRenderer.php @@ -1,688 +1,688 @@ - [], - '_POST' => [], - '_FILES' => [], - '_COOKIE' => [], - '_SESSION' => [], - '_SERVER' => ['DB_PASSWORD', 'SMTP_PASSWORD'], - '_ENV' => ['DB_PASSWORD', 'SMTP_PASSWORD'], - ]; - - /** - * A string identifier for a known IDE/text editor, or a closure - * that resolves a string that can be used to open a given file - * in an editor. If the string contains the special substrings - * %file or %line, they will be replaced with the correct data. - * - * @example - * "txmt://open?url=%file&line=%line" - * @var mixed $editor - */ - protected $editor; - - /** - * A list of known editor strings - * @var array - */ - protected $editors = [ - "sublime" => "subl://open?url=file://%file&line=%line", - "textmate" => "txmt://open?url=file://%file&line=%line", - "emacs" => "emacs://open?url=file://%file&line=%line", - "macvim" => "mvim://open/?url=file://%file&line=%line", - "phpstorm" => "phpstorm://open?file=%file&line=%line", - "idea" => "idea://open?file=%file&line=%line", - ]; - - /** - * @var Inspector - */ - protected $inspector; - - /** - * @var TemplateHelper - */ - private $templateHelper; - - /** - * {@inheritDoc} - */ - public function __construct($request, $response, $exception, $displayErrorDetails = FALSE) { - $this->request = $request; - $this->response = $response; - $this->exception = $exception; - $this->displayErrorDetails = $displayErrorDetails; - - if (ini_get('xdebug.file_link_format') || extension_loaded('xdebug')) { - // Register editor using xdebug's file_link_format option. - $this->editors['xdebug'] = function ($file, $line) { - return str_replace(['%f', '%l'], [$file, $line], ini_get('xdebug.file_link_format')); - }; - } - - // Add the default, local resource search path: - $this->searchPaths[] = \UserFrosting\VENDOR_DIR . '/filp/whoops/src/Whoops/Resources'; - - // blacklist php provided auth based values - $this->blacklist('_SERVER', 'PHP_AUTH_PW'); - - $this->templateHelper = new TemplateHelper(); - - // Set up dummy inspector - $this->inspector = new Inspector($exception); - - if (class_exists('Symfony\Component\VarDumper\Cloner\VarCloner')) { - $cloner = new VarCloner(); - // Only dump object internals if a custom caster exists. - $cloner->addCasters(['*' => function ($obj, $a, $stub, $isNested, $filter = 0) { - $class = $stub->class; - $classes = [$class => $class] + class_parents($class) + class_implements($class); - - foreach ($classes as $class) { - if (isset(AbstractCloner::$defaultCasters[$class])) { - return $a; - } - } - - // Remove all internals - return []; - }]); - $this->templateHelper->setCloner($cloner); - } - } - - /** - * {@inheritDoc} - */ - public function render() { - if (!$this->handleUnconditionally()) { - // Check conditions for outputting HTML: - // : Make this more robust - if (php_sapi_name() === 'cli') { - // Help users who have been relying on an internal test value - // fix their code to the proper method - if (isset($_ENV['whoops-test'])) { - throw new \Exception( - 'Use handleUnconditionally instead of whoops-test' - . ' environment variable' - ); - } - - return Handler::DONE; - } - } - - $templateFile = $this->getResource("views/layout.html.php"); - $cssFile = $this->getResource("css/whoops.base.css"); - $zeptoFile = $this->getResource("js/zepto.min.js"); - $clipboard = $this->getResource("js/clipboard.min.js"); - $jsFile = $this->getResource("js/whoops.base.js"); - - if ($this->customCss) { - $customCssFile = $this->getResource($this->customCss); - } - - $inspector = $this->getInspector(); - $frames = $inspector->getFrames(); - - $code = $inspector->getException()->getCode(); - - if ($inspector->getException() instanceof \ErrorException) { - // ErrorExceptions wrap the php-error types within the "severity" property - $code = Misc::translateErrorCode($inspector->getException()->getSeverity()); - } - - // Detect frames that belong to the application. - if ($this->applicationPaths) { - /* @var \Whoops\Exception\Frame $frame */ - foreach ($frames as $frame) { - foreach ($this->applicationPaths as $path) { - if (substr($frame->getFile(), 0, strlen($path)) === $path) { - $frame->setApplication(TRUE); - break; - } - } - } - } - - // Nicely format the session object - $session = isset($_SESSION) ? $this->masked($_SESSION, '_SESSION') : []; - $session = ['session' => Util::prettyPrintArray($session)]; - - // List of variables that will be passed to the layout template. - $vars = [ - "page_title" => $this->getPageTitle(), - - // : Asset compiler - "stylesheet" => file_get_contents($cssFile), - "zepto" => file_get_contents($zeptoFile), - "clipboard" => file_get_contents($clipboard), - "javascript" => file_get_contents($jsFile), - - // Template paths: - "header" => $this->getResource("views/header.html.php"), - "header_outer" => $this->getResource("views/header_outer.html.php"), - "frame_list" => $this->getResource("views/frame_list.html.php"), - "frames_description" => $this->getResource("views/frames_description.html.php"), - "frames_container" => $this->getResource("views/frames_container.html.php"), - "panel_details" => $this->getResource("views/panel_details.html.php"), - "panel_details_outer" => $this->getResource("views/panel_details_outer.html.php"), - "panel_left" => $this->getResource("views/panel_left.html.php"), - "panel_left_outer" => $this->getResource("views/panel_left_outer.html.php"), - "frame_code" => $this->getResource("views/frame_code.html.php"), - "env_details" => $this->getResource("views/env_details.html.php"), - - "title" => $this->getPageTitle(), - "name" => explode("\\", $inspector->getExceptionName()), - "message" => $inspector->getException()->getMessage(), - "code" => $code, - "plain_exception" => Formatter::formatExceptionPlain($inspector), - "frames" => $frames, - "has_frames" => !!count($frames), - "handler" => $this, - "handlers" => [$this], - - "active_frames_tab" => count($frames) && $frames->offsetGet(0)->isApplication() ? 'application' : 'all', - "has_frames_tabs" => $this->getApplicationPaths(), - - "tables" => [ - "GET Data" => $this->masked($_GET, '_GET'), - "POST Data" => $this->masked($_POST, '_POST'), - "Files" => isset($_FILES) ? $this->masked($_FILES, '_FILES') : [], - "Cookies" => $this->masked($_COOKIE, '_COOKIE'), - "Session" => $session, - "Server/Request Data" => $this->masked($_SERVER, '_SERVER'), - "Environment Variables" => $this->masked($_ENV, '_ENV'), - ], - ]; - - if (isset($customCssFile)) { - $vars["stylesheet"] .= file_get_contents($customCssFile); - } - - // Add extra entries list of data tables: - // : Consolidate addDataTable and addDataTableCallback - $extraTables = array_map(function ($table) use ($inspector) { - return $table instanceof \Closure ? $table($inspector) : $table; - }, $this->getDataTables()); - $vars["tables"] = array_merge($extraTables, $vars["tables"]); - - $plainTextHandler = new PlainTextHandler(); - $plainTextHandler->setException($this->getException()); - $plainTextHandler->setInspector($this->getInspector()); - $vars["preface"] = ""; - - $this->templateHelper->setVariables($vars); - - ob_start(); - $this->templateHelper->render($templateFile); - - $result = ob_get_clean(); - return $result; - } - - /** - * Adds an entry to the list of tables displayed in the template. - * The expected data is a simple associative array. Any nested arrays - * will be flattened with print_r - * @param string $label - * @param array $data - */ - public function addDataTable($label, array $data) { - $this->extraTables[$label] = $data; - } - - /** - * Lazily adds an entry to the list of tables displayed in the table. - * The supplied callback argument will be called when the error is rendered, - * it should produce a simple associative array. Any nested arrays will - * be flattened with print_r. - * - * @throws InvalidArgumentException If $callback is not callable - * @param string $label - * @param callable $callback Callable returning an associative array - */ - public function addDataTableCallback($label, /* callable */ - $callback) { - if (!is_callable($callback)) { - throw new InvalidArgumentException('Expecting callback argument to be callable'); - } - - $this->extraTables[$label] = function (\Whoops\Exception\Inspector $inspector = NULL) use ($callback) { - try { - $result = call_user_func($callback, $inspector); - - // Only return the result if it can be iterated over by foreach(). - return is_array($result) || $result instanceof \Traversable ? $result : []; - } catch (\Exception $e) { - // Don't allow failure to break the rendering of the original exception. - return []; - } - }; - } - - /** - * blacklist a sensitive value within one of the superglobal arrays. - * - * @param $superGlobalName string the name of the superglobal array, e.g. '_GET' - * @param $key string the key within the superglobal - */ - public function blacklist($superGlobalName, $key) { - $this->blacklist[$superGlobalName][] = $key; - } - - /** - * Returns all the extra data tables registered with this handler. - * Optionally accepts a 'label' parameter, to only return the data - * table under that label. - * @param string|null $label - * @return array[]|callable - */ - public function getDataTables($label = NULL) { - if ($label !== NULL) { - return isset($this->extraTables[$label]) ? - $this->extraTables[$label] : []; - } - - return $this->extraTables; - } - - /** - * Allows to disable all attempts to dynamically decide whether to - * handle or return prematurely. - * Set this to ensure that the handler will perform no matter what. - * @param bool|null $value - * @return bool|null - */ - public function handleUnconditionally($value = NULL) { - if (func_num_args() == 0) { - return $this->handleUnconditionally; - } - - $this->handleUnconditionally = (bool)$value; - } - - /** - * Adds an editor resolver, identified by a string - * name, and that may be a string path, or a callable - * resolver. If the callable returns a string, it will - * be set as the file reference's href attribute. - * - * @example - * $run->addEditor('macvim', "mvim://open?url=file://%file&line=%line") - * @example - * $run->addEditor('remove-it', function($file, $line) { - * unlink($file); - * return "http://stackoverflow.com"; - * }); - * @param string $identifier - * @param string $resolver - */ - public function addEditor($identifier, $resolver) { - $this->editors[$identifier] = $resolver; - } - - /** - * Set the editor to use to open referenced files, by a string - * identifier, or a callable that will be executed for every - * file reference, with a $file and $line argument, and should - * return a string. - * - * @example - * $run->setEditor(function($file, $line) { return "file:///{$file}"; }); - * @example - * $run->setEditor('sublime'); - * - * @throws InvalidArgumentException If invalid argument identifier provided - * @param string|callable $editor - */ - public function setEditor($editor) { - if (!is_callable($editor) && !isset($this->editors[$editor])) { - throw new InvalidArgumentException( - "Unknown editor identifier: $editor. Known editors:" . - implode(",", array_keys($this->editors)) - ); - } - - $this->editor = $editor; - } - - /** - * Given a string file path, and an integer file line, - * executes the editor resolver and returns, if available, - * a string that may be used as the href property for that - * file reference. - * - * @throws InvalidArgumentException If editor resolver does not return a string - * @param string $filePath - * @param int $line - * @return string|bool - */ - public function getEditorHref($filePath, $line) { - $editor = $this->getEditor($filePath, $line); - - if (empty($editor)) { - return FALSE; - } - - // Check that the editor is a string, and replace the - // %line and %file placeholders: - if (!isset($editor['url']) || !is_string($editor['url'])) { - throw new UnexpectedValueException( - __METHOD__ . " should always resolve to a string or a valid editor array; got something else instead." - ); - } - - $editor['url'] = str_replace("%line", rawurlencode($line), $editor['url']); - $editor['url'] = str_replace("%file", rawurlencode($filePath), $editor['url']); - - return $editor['url']; - } - - /** - * Given a boolean if the editor link should - * act as an Ajax request. The editor must be a - * valid callable function/closure - * - * @throws UnexpectedValueException If editor resolver does not return a boolean - * @param string $filePath - * @param int $line - * @return bool - */ - public function getEditorAjax($filePath, $line) { - $editor = $this->getEditor($filePath, $line); - - // Check that the ajax is a bool - if (!isset($editor['ajax']) || !is_bool($editor['ajax'])) { - throw new UnexpectedValueException( - __METHOD__ . " should always resolve to a bool; got something else instead." - ); - } - return $editor['ajax']; - } - - /** - * @param string $title - * @return void - */ - public function setPageTitle($title) { - $this->pageTitle = (string)$title; - } - - /** - * @return string - */ - public function getPageTitle() { - return $this->pageTitle; - } - - /** - * Adds a path to the list of paths to be searched for - * resources. - * - * @throws InvalidArgumentException If $path is not a valid directory - * - * @param string $path - * @return void - */ - public function addResourcePath($path) { - if (!is_dir($path)) { - throw new InvalidArgumentException( - "'$path' is not a valid directory" - ); - } - - array_unshift($this->searchPaths, $path); - } - - /** - * Adds a custom css file to be loaded. - * - * @param string $name - * @return void - */ - public function addCustomCss($name) { - $this->customCss = $name; - } - - /** - * @return array - */ - public function getResourcePaths() { - return $this->searchPaths; - } - - /** - * @deprecated - * - * @return string - */ - public function getResourcesPath() { - $allPaths = $this->getResourcePaths(); - - // Compat: return only the first path added - return end($allPaths) ?: NULL; - } - - /** - * @deprecated - * - * @param string $resourcesPath - * @return void - */ - public function setResourcesPath($resourcesPath) { - $this->addResourcePath($resourcesPath); - } - - /** - * Return the application paths. - * - * @return array - */ - public function getApplicationPaths() { - return $this->applicationPaths; - } - - /** - * Set the application paths. - * - * @param array $applicationPaths - */ - public function setApplicationPaths($applicationPaths) { - $this->applicationPaths = $applicationPaths; - } - - /** - * Set the application root path. - * - * @param string $applicationRootPath - */ - public function setApplicationRootPath($applicationRootPath) { - $this->templateHelper->setApplicationRootPath($applicationRootPath); - } - - /** - * Given a boolean if the editor link should - * act as an Ajax request. The editor must be a - * valid callable function/closure - * - * @param string $filePath - * @param int $line - * @return array - */ - protected function getEditor($filePath, $line) { - if (!$this->editor || (!is_string($this->editor) && !is_callable($this->editor))) { - return []; - } - - if (is_string($this->editor) && isset($this->editors[$this->editor]) && !is_callable($this->editors[$this->editor])) { - return [ - 'ajax' => FALSE, - 'url' => $this->editors[$this->editor], - ]; - } - - if (is_callable($this->editor) || (isset($this->editors[$this->editor]) && is_callable($this->editors[$this->editor]))) { - if (is_callable($this->editor)) { - $callback = call_user_func($this->editor, $filePath, $line); - } else { - $callback = call_user_func($this->editors[$this->editor], $filePath, $line); - } - - if (is_string($callback)) { - return [ - 'ajax' => FALSE, - 'url' => $callback, - ]; - } - - return [ - 'ajax' => isset($callback['ajax']) ? $callback['ajax'] : FALSE, - 'url' => isset($callback['url']) ? $callback['url'] : $callback, - ]; - } - - return []; - } - - /** - * @return \Throwable - */ - protected function getException() { - return $this->exception; - } - - /** - * @return Inspector - */ - protected function getInspector() { - return $this->inspector; - } - - /** - * Finds a resource, by its relative path, in all available search paths. - * The search is performed starting at the last search path, and all the - * way back to the first, enabling a cascading-type system of overrides - * for all resources. - * - * @throws RuntimeException If resource cannot be found in any of the available paths - * - * @param string $resource - * @return string - */ - protected function getResource($resource) { - // If the resource was found before, we can speed things up - // by caching its absolute, resolved path: - if (isset($this->resourceCache[$resource])) { - return $this->resourceCache[$resource]; - } - - // Search through available search paths, until we find the - // resource we're after: - foreach ($this->searchPaths as $path) { - $fullPath = $path . "/$resource"; - - if (is_file($fullPath)) { - // Cache the result: - $this->resourceCache[$resource] = $fullPath; - return $fullPath; - } - } - - // If we got this far, nothing was found. - throw new RuntimeException( - "Could not find resource '$resource' in any resource paths." - . "(searched: " . join(", ", $this->searchPaths) . ")" - ); - } - - /** - * Checks all values within the given superGlobal array. - * Blacklisted values will be replaced by a equal length string cointaining only '*' characters. - * - * We intentionally dont rely on $GLOBALS as it depends on 'auto_globals_jit' php.ini setting. - * - * @param array $superGlobal One of the superglobal arrays - * @param string $superGlobalName the name of the superglobal array, e.g. '_GET' - * @return array $values without sensitive data - */ - private function masked(array $superGlobal, $superGlobalName) { - $blacklisted = $this->blacklist[$superGlobalName]; - - $values = $superGlobal; - foreach ($blacklisted as $key) { - if (isset($superGlobal[$key])) { - $values[$key] = str_repeat('*', strlen($superGlobal[$key])); - } - } - return $values; - } -} + [], + '_POST' => [], + '_FILES' => [], + '_COOKIE' => [], + '_SESSION' => [], + '_SERVER' => ['DB_PASSWORD', 'SMTP_PASSWORD'], + '_ENV' => ['DB_PASSWORD', 'SMTP_PASSWORD'], + ]; + + /** + * A string identifier for a known IDE/text editor, or a closure + * that resolves a string that can be used to open a given file + * in an editor. If the string contains the special substrings + * %file or %line, they will be replaced with the correct data. + * + * @example + * "txmt://open?url=%file&line=%line" + * @var mixed $editor + */ + protected $editor; + + /** + * A list of known editor strings + * @var array + */ + protected $editors = [ + "sublime" => "subl://open?url=file://%file&line=%line", + "textmate" => "txmt://open?url=file://%file&line=%line", + "emacs" => "emacs://open?url=file://%file&line=%line", + "macvim" => "mvim://open/?url=file://%file&line=%line", + "phpstorm" => "phpstorm://open?file=%file&line=%line", + "idea" => "idea://open?file=%file&line=%line", + ]; + + /** + * @var Inspector + */ + protected $inspector; + + /** + * @var TemplateHelper + */ + private $templateHelper; + + /** + * {@inheritDoc} + */ + public function __construct($request, $response, $exception, $displayErrorDetails = FALSE) { + $this->request = $request; + $this->response = $response; + $this->exception = $exception; + $this->displayErrorDetails = $displayErrorDetails; + + if (ini_get('xdebug.file_link_format') || extension_loaded('xdebug')) { + // Register editor using xdebug's file_link_format option. + $this->editors['xdebug'] = function ($file, $line) { + return str_replace(['%f', '%l'], [$file, $line], ini_get('xdebug.file_link_format')); + }; + } + + // Add the default, local resource search path: + $this->searchPaths[] = \UserFrosting\VENDOR_DIR . '/filp/whoops/src/Whoops/Resources'; + + // blacklist php provided auth based values + $this->blacklist('_SERVER', 'PHP_AUTH_PW'); + + $this->templateHelper = new TemplateHelper(); + + // Set up dummy inspector + $this->inspector = new Inspector($exception); + + if (class_exists('Symfony\Component\VarDumper\Cloner\VarCloner')) { + $cloner = new VarCloner(); + // Only dump object internals if a custom caster exists. + $cloner->addCasters(['*' => function ($obj, $a, $stub, $isNested, $filter = 0) { + $class = $stub->class; + $classes = [$class => $class] + class_parents($class) + class_implements($class); + + foreach ($classes as $class) { + if (isset(AbstractCloner::$defaultCasters[$class])) { + return $a; + } + } + + // Remove all internals + return []; + }]); + $this->templateHelper->setCloner($cloner); + } + } + + /** + * {@inheritDoc} + */ + public function render() { + if (!$this->handleUnconditionally()) { + // Check conditions for outputting HTML: + // : Make this more robust + if (php_sapi_name() === 'cli') { + // Help users who have been relying on an internal test value + // fix their code to the proper method + if (isset($_ENV['whoops-test'])) { + throw new \Exception( + 'Use handleUnconditionally instead of whoops-test' + . ' environment variable' + ); + } + + return Handler::DONE; + } + } + + $templateFile = $this->getResource("views/layout.html.php"); + $cssFile = $this->getResource("css/whoops.base.css"); + $zeptoFile = $this->getResource("js/zepto.min.js"); + $clipboard = $this->getResource("js/clipboard.min.js"); + $jsFile = $this->getResource("js/whoops.base.js"); + + if ($this->customCss) { + $customCssFile = $this->getResource($this->customCss); + } + + $inspector = $this->getInspector(); + $frames = $inspector->getFrames(); + + $code = $inspector->getException()->getCode(); + + if ($inspector->getException() instanceof \ErrorException) { + // ErrorExceptions wrap the php-error types within the "severity" property + $code = Misc::translateErrorCode($inspector->getException()->getSeverity()); + } + + // Detect frames that belong to the application. + if ($this->applicationPaths) { + /* @var \Whoops\Exception\Frame $frame */ + foreach ($frames as $frame) { + foreach ($this->applicationPaths as $path) { + if (substr($frame->getFile(), 0, strlen($path)) === $path) { + $frame->setApplication(TRUE); + break; + } + } + } + } + + // Nicely format the session object + $session = isset($_SESSION) ? $this->masked($_SESSION, '_SESSION') : []; + $session = ['session' => Util::prettyPrintArray($session)]; + + // List of variables that will be passed to the layout template. + $vars = [ + "page_title" => $this->getPageTitle(), + + // : Asset compiler + "stylesheet" => file_get_contents($cssFile), + "zepto" => file_get_contents($zeptoFile), + "clipboard" => file_get_contents($clipboard), + "javascript" => file_get_contents($jsFile), + + // Template paths: + "header" => $this->getResource("views/header.html.php"), + "header_outer" => $this->getResource("views/header_outer.html.php"), + "frame_list" => $this->getResource("views/frame_list.html.php"), + "frames_description" => $this->getResource("views/frames_description.html.php"), + "frames_container" => $this->getResource("views/frames_container.html.php"), + "panel_details" => $this->getResource("views/panel_details.html.php"), + "panel_details_outer" => $this->getResource("views/panel_details_outer.html.php"), + "panel_left" => $this->getResource("views/panel_left.html.php"), + "panel_left_outer" => $this->getResource("views/panel_left_outer.html.php"), + "frame_code" => $this->getResource("views/frame_code.html.php"), + "env_details" => $this->getResource("views/env_details.html.php"), + + "title" => $this->getPageTitle(), + "name" => explode("\\", $inspector->getExceptionName()), + "message" => $inspector->getException()->getMessage(), + "code" => $code, + "plain_exception" => Formatter::formatExceptionPlain($inspector), + "frames" => $frames, + "has_frames" => !!count($frames), + "handler" => $this, + "handlers" => [$this], + + "active_frames_tab" => count($frames) && $frames->offsetGet(0)->isApplication() ? 'application' : 'all', + "has_frames_tabs" => $this->getApplicationPaths(), + + "tables" => [ + "GET Data" => $this->masked($_GET, '_GET'), + "POST Data" => $this->masked($_POST, '_POST'), + "Files" => isset($_FILES) ? $this->masked($_FILES, '_FILES') : [], + "Cookies" => $this->masked($_COOKIE, '_COOKIE'), + "Session" => $session, + "Server/Request Data" => $this->masked($_SERVER, '_SERVER'), + "Environment Variables" => $this->masked($_ENV, '_ENV'), + ], + ]; + + if (isset($customCssFile)) { + $vars["stylesheet"] .= file_get_contents($customCssFile); + } + + // Add extra entries list of data tables: + // : Consolidate addDataTable and addDataTableCallback + $extraTables = array_map(function ($table) use ($inspector) { + return $table instanceof \Closure ? $table($inspector) : $table; + }, $this->getDataTables()); + $vars["tables"] = array_merge($extraTables, $vars["tables"]); + + $plainTextHandler = new PlainTextHandler(); + $plainTextHandler->setException($this->getException()); + $plainTextHandler->setInspector($this->getInspector()); + $vars["preface"] = ""; + + $this->templateHelper->setVariables($vars); + + ob_start(); + $this->templateHelper->render($templateFile); + + $result = ob_get_clean(); + return $result; + } + + /** + * Adds an entry to the list of tables displayed in the template. + * The expected data is a simple associative array. Any nested arrays + * will be flattened with print_r + * @param string $label + * @param array $data + */ + public function addDataTable($label, array $data) { + $this->extraTables[$label] = $data; + } + + /** + * Lazily adds an entry to the list of tables displayed in the table. + * The supplied callback argument will be called when the error is rendered, + * it should produce a simple associative array. Any nested arrays will + * be flattened with print_r. + * + * @throws InvalidArgumentException If $callback is not callable + * @param string $label + * @param callable $callback Callable returning an associative array + */ + public function addDataTableCallback($label, /* callable */ + $callback) { + if (!is_callable($callback)) { + throw new InvalidArgumentException('Expecting callback argument to be callable'); + } + + $this->extraTables[$label] = function (\Whoops\Exception\Inspector $inspector = NULL) use ($callback) { + try { + $result = call_user_func($callback, $inspector); + + // Only return the result if it can be iterated over by foreach(). + return is_array($result) || $result instanceof \Traversable ? $result : []; + } catch (\Exception $e) { + // Don't allow failure to break the rendering of the original exception. + return []; + } + }; + } + + /** + * blacklist a sensitive value within one of the superglobal arrays. + * + * @param $superGlobalName string the name of the superglobal array, e.g. '_GET' + * @param $key string the key within the superglobal + */ + public function blacklist($superGlobalName, $key) { + $this->blacklist[$superGlobalName][] = $key; + } + + /** + * Returns all the extra data tables registered with this handler. + * Optionally accepts a 'label' parameter, to only return the data + * table under that label. + * @param string|null $label + * @return array[]|callable + */ + public function getDataTables($label = NULL) { + if ($label !== NULL) { + return isset($this->extraTables[$label]) ? + $this->extraTables[$label] : []; + } + + return $this->extraTables; + } + + /** + * Allows to disable all attempts to dynamically decide whether to + * handle or return prematurely. + * Set this to ensure that the handler will perform no matter what. + * @param bool|null $value + * @return bool|null + */ + public function handleUnconditionally($value = NULL) { + if (func_num_args() == 0) { + return $this->handleUnconditionally; + } + + $this->handleUnconditionally = (bool)$value; + } + + /** + * Adds an editor resolver, identified by a string + * name, and that may be a string path, or a callable + * resolver. If the callable returns a string, it will + * be set as the file reference's href attribute. + * + * @example + * $run->addEditor('macvim', "mvim://open?url=file://%file&line=%line") + * @example + * $run->addEditor('remove-it', function($file, $line) { + * unlink($file); + * return "http://stackoverflow.com"; + * }); + * @param string $identifier + * @param string $resolver + */ + public function addEditor($identifier, $resolver) { + $this->editors[$identifier] = $resolver; + } + + /** + * Set the editor to use to open referenced files, by a string + * identifier, or a callable that will be executed for every + * file reference, with a $file and $line argument, and should + * return a string. + * + * @example + * $run->setEditor(function($file, $line) { return "file:///{$file}"; }); + * @example + * $run->setEditor('sublime'); + * + * @throws InvalidArgumentException If invalid argument identifier provided + * @param string|callable $editor + */ + public function setEditor($editor) { + if (!is_callable($editor) && !isset($this->editors[$editor])) { + throw new InvalidArgumentException( + "Unknown editor identifier: $editor. Known editors:" . + implode(",", array_keys($this->editors)) + ); + } + + $this->editor = $editor; + } + + /** + * Given a string file path, and an integer file line, + * executes the editor resolver and returns, if available, + * a string that may be used as the href property for that + * file reference. + * + * @throws InvalidArgumentException If editor resolver does not return a string + * @param string $filePath + * @param int $line + * @return string|bool + */ + public function getEditorHref($filePath, $line) { + $editor = $this->getEditor($filePath, $line); + + if (empty($editor)) { + return FALSE; + } + + // Check that the editor is a string, and replace the + // %line and %file placeholders: + if (!isset($editor['url']) || !is_string($editor['url'])) { + throw new UnexpectedValueException( + __METHOD__ . " should always resolve to a string or a valid editor array; got something else instead." + ); + } + + $editor['url'] = str_replace("%line", rawurlencode($line), $editor['url']); + $editor['url'] = str_replace("%file", rawurlencode($filePath), $editor['url']); + + return $editor['url']; + } + + /** + * Given a boolean if the editor link should + * act as an Ajax request. The editor must be a + * valid callable function/closure + * + * @throws UnexpectedValueException If editor resolver does not return a boolean + * @param string $filePath + * @param int $line + * @return bool + */ + public function getEditorAjax($filePath, $line) { + $editor = $this->getEditor($filePath, $line); + + // Check that the ajax is a bool + if (!isset($editor['ajax']) || !is_bool($editor['ajax'])) { + throw new UnexpectedValueException( + __METHOD__ . " should always resolve to a bool; got something else instead." + ); + } + return $editor['ajax']; + } + + /** + * @param string $title + * @return void + */ + public function setPageTitle($title) { + $this->pageTitle = (string)$title; + } + + /** + * @return string + */ + public function getPageTitle() { + return $this->pageTitle; + } + + /** + * Adds a path to the list of paths to be searched for + * resources. + * + * @throws InvalidArgumentException If $path is not a valid directory + * + * @param string $path + * @return void + */ + public function addResourcePath($path) { + if (!is_dir($path)) { + throw new InvalidArgumentException( + "'$path' is not a valid directory" + ); + } + + array_unshift($this->searchPaths, $path); + } + + /** + * Adds a custom css file to be loaded. + * + * @param string $name + * @return void + */ + public function addCustomCss($name) { + $this->customCss = $name; + } + + /** + * @return array + */ + public function getResourcePaths() { + return $this->searchPaths; + } + + /** + * @deprecated + * + * @return string + */ + public function getResourcesPath() { + $allPaths = $this->getResourcePaths(); + + // Compat: return only the first path added + return end($allPaths) ?: NULL; + } + + /** + * @deprecated + * + * @param string $resourcesPath + * @return void + */ + public function setResourcesPath($resourcesPath) { + $this->addResourcePath($resourcesPath); + } + + /** + * Return the application paths. + * + * @return array + */ + public function getApplicationPaths() { + return $this->applicationPaths; + } + + /** + * Set the application paths. + * + * @param array $applicationPaths + */ + public function setApplicationPaths($applicationPaths) { + $this->applicationPaths = $applicationPaths; + } + + /** + * Set the application root path. + * + * @param string $applicationRootPath + */ + public function setApplicationRootPath($applicationRootPath) { + $this->templateHelper->setApplicationRootPath($applicationRootPath); + } + + /** + * Given a boolean if the editor link should + * act as an Ajax request. The editor must be a + * valid callable function/closure + * + * @param string $filePath + * @param int $line + * @return array + */ + protected function getEditor($filePath, $line) { + if (!$this->editor || (!is_string($this->editor) && !is_callable($this->editor))) { + return []; + } + + if (is_string($this->editor) && isset($this->editors[$this->editor]) && !is_callable($this->editors[$this->editor])) { + return [ + 'ajax' => FALSE, + 'url' => $this->editors[$this->editor], + ]; + } + + if (is_callable($this->editor) || (isset($this->editors[$this->editor]) && is_callable($this->editors[$this->editor]))) { + if (is_callable($this->editor)) { + $callback = call_user_func($this->editor, $filePath, $line); + } else { + $callback = call_user_func($this->editors[$this->editor], $filePath, $line); + } + + if (is_string($callback)) { + return [ + 'ajax' => FALSE, + 'url' => $callback, + ]; + } + + return [ + 'ajax' => isset($callback['ajax']) ? $callback['ajax'] : FALSE, + 'url' => isset($callback['url']) ? $callback['url'] : $callback, + ]; + } + + return []; + } + + /** + * @return \Throwable + */ + protected function getException() { + return $this->exception; + } + + /** + * @return Inspector + */ + protected function getInspector() { + return $this->inspector; + } + + /** + * Finds a resource, by its relative path, in all available search paths. + * The search is performed starting at the last search path, and all the + * way back to the first, enabling a cascading-type system of overrides + * for all resources. + * + * @throws RuntimeException If resource cannot be found in any of the available paths + * + * @param string $resource + * @return string + */ + protected function getResource($resource) { + // If the resource was found before, we can speed things up + // by caching its absolute, resolved path: + if (isset($this->resourceCache[$resource])) { + return $this->resourceCache[$resource]; + } + + // Search through available search paths, until we find the + // resource we're after: + foreach ($this->searchPaths as $path) { + $fullPath = $path . "/$resource"; + + if (is_file($fullPath)) { + // Cache the result: + $this->resourceCache[$resource] = $fullPath; + return $fullPath; + } + } + + // If we got this far, nothing was found. + throw new RuntimeException( + "Could not find resource '$resource' in any resource paths." + . "(searched: " . join(", ", $this->searchPaths) . ")" + ); + } + + /** + * Checks all values within the given superGlobal array. + * Blacklisted values will be replaced by a equal length string cointaining only '*' characters. + * + * We intentionally dont rely on $GLOBALS as it depends on 'auto_globals_jit' php.ini setting. + * + * @param array $superGlobal One of the superglobal arrays + * @param string $superGlobalName the name of the superglobal array, e.g. '_GET' + * @return array $values without sensitive data + */ + private function masked(array $superGlobal, $superGlobalName) { + $blacklisted = $this->blacklist[$superGlobalName]; + + $values = $superGlobal; + foreach ($blacklisted as $key) { + if (isset($superGlobal[$key])) { + $values[$key] = str_repeat('*', strlen($superGlobal[$key])); + } + } + return $values; + } +} diff --git a/main/app/sprinkles/core/src/Error/Renderer/XmlRenderer.php b/main/app/sprinkles/core/src/Error/Renderer/XmlRenderer.php index 5c51d8d..8e17554 100644 --- a/main/app/sprinkles/core/src/Error/Renderer/XmlRenderer.php +++ b/main/app/sprinkles/core/src/Error/Renderer/XmlRenderer.php @@ -1,47 +1,47 @@ -exception; - $xml = "\n UserFrosting Application Error\n"; - if ($this->displayErrorDetails) { - do { - $xml .= " \n"; - $xml .= " " . get_class($e) . "\n"; - $xml .= " " . $e->getCode() . "\n"; - $xml .= " " . $this->createCdataSection($e->getMessage()) . "\n"; - $xml .= " " . $e->getFile() . "\n"; - $xml .= " " . $e->getLine() . "\n"; - $xml .= " \n"; - } while ($e = $e->getPrevious()); - } - $xml .= ""; - - return $xml; - } - - /** - * Returns a CDATA section with the given content. - * - * @param string $content - * @return string - */ - private function createCdataSection($content) { - return sprintf('', str_replace(']]>', ']]]]>', $content)); - } -} +exception; + $xml = "\n UserFrosting Application Error\n"; + if ($this->displayErrorDetails) { + do { + $xml .= " \n"; + $xml .= " " . get_class($e) . "\n"; + $xml .= " " . $e->getCode() . "\n"; + $xml .= " " . $this->createCdataSection($e->getMessage()) . "\n"; + $xml .= " " . $e->getFile() . "\n"; + $xml .= " " . $e->getLine() . "\n"; + $xml .= " \n"; + } while ($e = $e->getPrevious()); + } + $xml .= ""; + + return $xml; + } + + /** + * Returns a CDATA section with the given content. + * + * @param string $content + * @return string + */ + private function createCdataSection($content) { + return sprintf('', str_replace(']]>', ']]]]>', $content)); + } +} diff --git a/main/app/sprinkles/core/src/Facades/Debug.php b/main/app/sprinkles/core/src/Facades/Debug.php index 40cc263..58e4302 100644 --- a/main/app/sprinkles/core/src/Facades/Debug.php +++ b/main/app/sprinkles/core/src/Facades/Debug.php @@ -1,28 +1,28 @@ -isXhr()) { - return 'text/html'; - } - - $acceptHeader = $request->getHeaderLine('Accept'); - $selectedContentTypes = array_intersect(explode(',', $acceptHeader), $this->knownContentTypes); - $count = count($selectedContentTypes); - - if ($count) { - $current = current($selectedContentTypes); - - /** - * Ensure other supported content types take precedence over text/plain - * when multiple content types are provided via Accept header. - */ - if ($current === 'text/plain' && $count > 1) { - return next($selectedContentTypes); - } - - return $current; - } - - if (preg_match('/\+(json|xml)/', $acceptHeader, $matches)) { - $mediaType = 'application/' . $matches[1]; - if (in_array($mediaType, $this->knownContentTypes)) { - return $mediaType; - } - } - - return 'text/html'; - } -} +isXhr()) { + return 'text/html'; + } + + $acceptHeader = $request->getHeaderLine('Accept'); + $selectedContentTypes = array_intersect(explode(',', $acceptHeader), $this->knownContentTypes); + $count = count($selectedContentTypes); + + if ($count) { + $current = current($selectedContentTypes); + + /** + * Ensure other supported content types take precedence over text/plain + * when multiple content types are provided via Accept header. + */ + if ($current === 'text/plain' && $count > 1) { + return next($selectedContentTypes); + } + + return $current; + } + + if (preg_match('/\+(json|xml)/', $acceptHeader, $matches)) { + $mediaType = 'application/' . $matches[1]; + if (in_array($mediaType, $this->knownContentTypes)) { + return $mediaType; + } + } + + return 'text/html'; + } +} diff --git a/main/app/sprinkles/core/src/Log/DatabaseHandler.php b/main/app/sprinkles/core/src/Log/DatabaseHandler.php index d4c9fce..49eb5c2 100644 --- a/main/app/sprinkles/core/src/Log/DatabaseHandler.php +++ b/main/app/sprinkles/core/src/Log/DatabaseHandler.php @@ -1,52 +1,52 @@ -classMapper = $classMapper; - $this->modelName = $modelIdentifier; - parent::__construct($level, $bubble); - } - - /** - * {@inheritDoc} - */ - protected function write(array $record) { - $log = $this->classMapper->createInstance($this->modelName, $record['extra']); - $log->save(); - } -} +classMapper = $classMapper; + $this->modelName = $modelIdentifier; + parent::__construct($level, $bubble); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) { + $log = $this->classMapper->createInstance($this->modelName, $record['extra']); + $log->save(); + } +} diff --git a/main/app/sprinkles/core/src/Log/MixedFormatter.php b/main/app/sprinkles/core/src/Log/MixedFormatter.php index ce21879..ef70268 100644 --- a/main/app/sprinkles/core/src/Log/MixedFormatter.php +++ b/main/app/sprinkles/core/src/Log/MixedFormatter.php @@ -1,58 +1,58 @@ -jsonEncodePretty($data); - } - - $json = $this->jsonEncodePretty($data); - - if ($json === FALSE) { - $json = $this->handleJsonError(json_last_error(), $data); - } - - return $json; - } - - /** - * @param mixed $data - * @return string JSON encoded data or null on failure - */ - private function jsonEncodePretty($data) { - if (version_compare(PHP_VERSION, '5.4.0', '>=')) { - return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); - } - - return json_encode($data); - } -} +jsonEncodePretty($data); + } + + $json = $this->jsonEncodePretty($data); + + if ($json === FALSE) { + $json = $this->handleJsonError(json_last_error(), $data); + } + + return $json; + } + + /** + * @param mixed $data + * @return string JSON encoded data or null on failure + */ + private function jsonEncodePretty($data) { + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); + } + + return json_encode($data); + } +} diff --git a/main/app/sprinkles/core/src/Mail/EmailRecipient.php b/main/app/sprinkles/core/src/Mail/EmailRecipient.php index 33b7db7..29b5de8 100644 --- a/main/app/sprinkles/core/src/Mail/EmailRecipient.php +++ b/main/app/sprinkles/core/src/Mail/EmailRecipient.php @@ -1,129 +1,129 @@ - value) to use when rendering an email template for this recipient. - */ - protected $params = []; - - /** - * @var array A list of CCs for this recipient. Each CC is an associative array with `email` and `name` properties. - */ - protected $cc = []; - - /** - * @var array A list of BCCs for this recipient. Each BCC is an associative array with `email` and `name` properties. - */ - protected $bcc = []; - - /** - * Create a new EmailRecipient instance. - * - * @param string $email The primary recipient email address. - * @param string $name The primary recipient name. - * @param array $params An array of template parameters to render the email message with for this particular recipient. - */ - public function __construct($email, $name = "", $params = []) { - $this->email = $email; - $this->name = $name; - $this->params = $params; - } - - /** - * Add a CC for this primary recipient. - * - * @param string $email The CC recipient email address. - * @param string $name The CC recipient name. - */ - public function cc($email, $name = "") { - $this->cc[] = [ - "email" => $email, - "name" => $name - ]; - } - - /** - * Add a BCC for this primary recipient. - * - * @param string $email The BCC recipient email address. - * @param string $name The BCC recipient name. - */ - public function bcc($email, $name = "") { - $this->bcc[] = [ - "email" => $email, - "name" => $name - ]; - } - - /** - * Get the primary recipient email address. - * - * @return string the primary recipient email address. - */ - public function getEmail() { - return $this->email; - } - - /** - * Get the primary recipient name. - * - * @return string the primary recipient name. - */ - public function getName() { - return $this->name; - } - - /** - * Get the parameters to use when rendering the template this recipient. - * - * @return array The parameters (name => value) to use when rendering an email template for this recipient. - */ - public function getParams() { - return $this->params; - } - - /** - * Get the list of CCs for this recipient. - * - * @return array A list of CCs for this recipient. Each CC is an associative array with `email` and `name` properties. - */ - public function getCCs() { - return $this->cc; - } - - /** - * Get the list of BCCs for this recipient. - * - * @return array A list of BCCs for this recipient. Each BCC is an associative array with `email` and `name` properties. - */ - public function getBCCs() { - return $this->bcc; - } -} + value) to use when rendering an email template for this recipient. + */ + protected $params = []; + + /** + * @var array A list of CCs for this recipient. Each CC is an associative array with `email` and `name` properties. + */ + protected $cc = []; + + /** + * @var array A list of BCCs for this recipient. Each BCC is an associative array with `email` and `name` properties. + */ + protected $bcc = []; + + /** + * Create a new EmailRecipient instance. + * + * @param string $email The primary recipient email address. + * @param string $name The primary recipient name. + * @param array $params An array of template parameters to render the email message with for this particular recipient. + */ + public function __construct($email, $name = "", $params = []) { + $this->email = $email; + $this->name = $name; + $this->params = $params; + } + + /** + * Add a CC for this primary recipient. + * + * @param string $email The CC recipient email address. + * @param string $name The CC recipient name. + */ + public function cc($email, $name = "") { + $this->cc[] = [ + "email" => $email, + "name" => $name + ]; + } + + /** + * Add a BCC for this primary recipient. + * + * @param string $email The BCC recipient email address. + * @param string $name The BCC recipient name. + */ + public function bcc($email, $name = "") { + $this->bcc[] = [ + "email" => $email, + "name" => $name + ]; + } + + /** + * Get the primary recipient email address. + * + * @return string the primary recipient email address. + */ + public function getEmail() { + return $this->email; + } + + /** + * Get the primary recipient name. + * + * @return string the primary recipient name. + */ + public function getName() { + return $this->name; + } + + /** + * Get the parameters to use when rendering the template this recipient. + * + * @return array The parameters (name => value) to use when rendering an email template for this recipient. + */ + public function getParams() { + return $this->params; + } + + /** + * Get the list of CCs for this recipient. + * + * @return array A list of CCs for this recipient. Each CC is an associative array with `email` and `name` properties. + */ + public function getCCs() { + return $this->cc; + } + + /** + * Get the list of BCCs for this recipient. + * + * @return array A list of BCCs for this recipient. Each BCC is an associative array with `email` and `name` properties. + */ + public function getBCCs() { + return $this->bcc; + } +} diff --git a/main/app/sprinkles/core/src/Mail/MailMessage.php b/main/app/sprinkles/core/src/Mail/MailMessage.php index 6aea56d..c16d1ad 100644 --- a/main/app/sprinkles/core/src/Mail/MailMessage.php +++ b/main/app/sprinkles/core/src/Mail/MailMessage.php @@ -1,175 +1,175 @@ -recipients[] = $recipient; - return $this; - } - - /** - * Clears out all recipients for this message. - */ - public function clearRecipients() { - $this->recipients = array(); - } - - /** - * Set sender information for this message. - * - * This is a shortcut for calling setFromEmail, setFromName, setReplyEmail, and setReplyName. - * @param string $fromInfo An array containing 'email', 'name', 'reply_email', and 'reply_name'. - */ - public function from($fromInfo = []) { - $this->setFromEmail(isset($fromInfo['email']) ? $fromInfo['email'] : ""); - $this->setFromName(isset($fromInfo['name']) ? $fromInfo['name'] : NULL); - $this->setReplyEmail(isset($fromInfo['reply_email']) ? $fromInfo['reply_email'] : NULL); - $this->setReplyName(isset($fromInfo['reply_name']) ? $fromInfo['reply_name'] : NULL); - - return $this; - } - - /** - * Get the sender email address. - * - * @return string - */ - public function getFromEmail() { - return $this->fromEmail; - } - - /** - * Get the sender name. Defaults to the email address if name is not set. - * - * @return string - */ - public function getFromName() { - return isset($this->fromName) ? $this->fromName : $this->getFromEmail(); - } - - /** - * Get the list of recipients for this message. - * - * @return EmailRecipient[] - */ - public function getRecipients() { - return $this->recipients; - } - - /** - * Get the 'reply-to' address for this message. Defaults to the sender email. - * - * @return string - */ - public function getReplyEmail() { - return isset($this->replyEmail) ? $this->replyEmail : $this->getFromEmail(); - } - - /** - * Get the 'reply-to' name for this message. Defaults to the sender name. - * - * @return string - */ - public function getReplyName() { - return isset($this->replyName) ? $this->replyName : $this->getFromName(); - } - - /** - * Set the sender email address. - * - * @param string $fromEmail - */ - public function setFromEmail($fromEmail) { - $this->fromEmail = $fromEmail; - return $this; - } - - /** - * Set the sender name. - * - * @param string $fromName - */ - public function setFromName($fromName) { - $this->fromName = $fromName; - return $this; - } - - /** - * Set the sender 'reply-to' address. - * - * @param string $replyEmail - */ - public function setReplyEmail($replyEmail) { - $this->replyEmail = $replyEmail; - return $this; - } - - /** - * Set the sender 'reply-to' name. - * - * @param string $replyName - */ - public function setReplyName($replyName) { - $this->replyName = $replyName; - return $this; - } -} +recipients[] = $recipient; + return $this; + } + + /** + * Clears out all recipients for this message. + */ + public function clearRecipients() { + $this->recipients = array(); + } + + /** + * Set sender information for this message. + * + * This is a shortcut for calling setFromEmail, setFromName, setReplyEmail, and setReplyName. + * @param string $fromInfo An array containing 'email', 'name', 'reply_email', and 'reply_name'. + */ + public function from($fromInfo = []) { + $this->setFromEmail(isset($fromInfo['email']) ? $fromInfo['email'] : ""); + $this->setFromName(isset($fromInfo['name']) ? $fromInfo['name'] : NULL); + $this->setReplyEmail(isset($fromInfo['reply_email']) ? $fromInfo['reply_email'] : NULL); + $this->setReplyName(isset($fromInfo['reply_name']) ? $fromInfo['reply_name'] : NULL); + + return $this; + } + + /** + * Get the sender email address. + * + * @return string + */ + public function getFromEmail() { + return $this->fromEmail; + } + + /** + * Get the sender name. Defaults to the email address if name is not set. + * + * @return string + */ + public function getFromName() { + return isset($this->fromName) ? $this->fromName : $this->getFromEmail(); + } + + /** + * Get the list of recipients for this message. + * + * @return EmailRecipient[] + */ + public function getRecipients() { + return $this->recipients; + } + + /** + * Get the 'reply-to' address for this message. Defaults to the sender email. + * + * @return string + */ + public function getReplyEmail() { + return isset($this->replyEmail) ? $this->replyEmail : $this->getFromEmail(); + } + + /** + * Get the 'reply-to' name for this message. Defaults to the sender name. + * + * @return string + */ + public function getReplyName() { + return isset($this->replyName) ? $this->replyName : $this->getFromName(); + } + + /** + * Set the sender email address. + * + * @param string $fromEmail + */ + public function setFromEmail($fromEmail) { + $this->fromEmail = $fromEmail; + return $this; + } + + /** + * Set the sender name. + * + * @param string $fromName + */ + public function setFromName($fromName) { + $this->fromName = $fromName; + return $this; + } + + /** + * Set the sender 'reply-to' address. + * + * @param string $replyEmail + */ + public function setReplyEmail($replyEmail) { + $this->replyEmail = $replyEmail; + return $this; + } + + /** + * Set the sender 'reply-to' name. + * + * @param string $replyName + */ + public function setReplyName($replyName) { + $this->replyName = $replyName; + return $this; + } +} diff --git a/main/app/sprinkles/core/src/Mail/Mailer.php b/main/app/sprinkles/core/src/Mail/Mailer.php index 761d15a..5331107 100644 --- a/main/app/sprinkles/core/src/Mail/Mailer.php +++ b/main/app/sprinkles/core/src/Mail/Mailer.php @@ -1,200 +1,200 @@ -logger = $logger; - - // 'true' tells PHPMailer to use exceptions instead of error codes - $this->phpMailer = new \PHPMailer(TRUE); - - // Configuration options - if (isset($config['mailer'])) { - if (!in_array($config['mailer'], ['smtp', 'mail', 'qmail', 'sendmail'])) { - throw new \phpmailerException("'mailer' must be one of 'smtp', 'mail', 'qmail', or 'sendmail'."); - } - - if ($config['mailer'] == 'smtp') { - $this->phpMailer->isSMTP(TRUE); - $this->phpMailer->Host = $config['host']; - $this->phpMailer->Port = $config['port']; - $this->phpMailer->SMTPAuth = $config['auth']; - $this->phpMailer->SMTPSecure = $config['secure']; - $this->phpMailer->Username = $config['username']; - $this->phpMailer->Password = $config['password']; - $this->phpMailer->SMTPDebug = $config['smtp_debug']; - - if (isset($config['smtp_options'])) { - $this->phpMailer->SMTPOptions = $config['smtp_options']; - } - } - - // Set any additional message-specific options - // enforce which options can be set through this subarray - if (isset($config['message_options'])) { - $this->setOptions($config['message_options']); - } - } - - // Pass logger into phpMailer object - $this->phpMailer->Debugoutput = function ($message, $level) { - $this->logger->debug($message); - }; - } - - /** - * Get the underlying PHPMailer object. - * - * @return \PHPMailer - */ - public function getPhpMailer() { - return $this->phpMailer; - } - - /** - * Send a MailMessage message. - * - * Sends a single email to all recipients, as well as their CCs and BCCs. - * Since it is a single-header message, recipient-specific template data will not be included. - * @param MailMessage $message - * @param bool $clearRecipients Set to true to clear the list of recipients in the message after calling send(). This helps avoid accidentally sending a message multiple times. - * @throws \phpmailerException The message could not be sent. - */ - public function send(MailMessage $message, $clearRecipients = TRUE) { - $this->phpMailer->From = $message->getFromEmail(); - $this->phpMailer->FromName = $message->getFromName(); - $this->phpMailer->addReplyTo($message->getReplyEmail(), $message->getReplyName()); - - // Add all email recipients, as well as their CCs and BCCs - foreach ($message->getRecipients() as $recipient) { - $this->phpMailer->addAddress($recipient->getEmail(), $recipient->getName()); - - // Add any CCs and BCCs - if ($recipient->getCCs()) { - foreach ($recipient->getCCs() as $cc) { - $this->phpMailer->addCC($cc['email'], $cc['name']); - } - } - - if ($recipient->getBCCs()) { - foreach ($recipient->getBCCs() as $bcc) { - $this->phpMailer->addBCC($bcc['email'], $bcc['name']); - } - } - } - - $this->phpMailer->Subject = $message->renderSubject(); - $this->phpMailer->Body = $message->renderBody(); - - // Try to send the mail. Will throw an exception on failure. - $this->phpMailer->send(); - - // Clear recipients from the PHPMailer object for this iteration, - // so that we can use the same object for other emails. - $this->phpMailer->clearAllRecipients(); - - // Clear out the MailMessage's internal recipient list - if ($clearRecipients) { - $message->clearRecipients(); - } - } - - /** - * Send a MailMessage message, sending a separate email to each recipient. - * - * If the message object supports message templates, this will render the template with the corresponding placeholder values for each recipient. - * @param MailMessage $message - * @param bool $clearRecipients Set to true to clear the list of recipients in the message after calling send(). This helps avoid accidentally sending a message multiple times. - * @throws \phpmailerException The message could not be sent. - */ - public function sendDistinct(MailMessage $message, $clearRecipients = TRUE) { - $this->phpMailer->From = $message->getFromEmail(); - $this->phpMailer->FromName = $message->getFromName(); - $this->phpMailer->addReplyTo($message->getReplyEmail(), $message->getReplyName()); - - // Loop through email recipients, sending customized content to each one - foreach ($message->getRecipients() as $recipient) { - $this->phpMailer->addAddress($recipient->getEmail(), $recipient->getName()); - - // Add any CCs and BCCs - if ($recipient->getCCs()) { - foreach ($recipient->getCCs() as $cc) { - $this->phpMailer->addCC($cc['email'], $cc['name']); - } - } - - if ($recipient->getBCCs()) { - foreach ($recipient->getBCCs() as $bcc) { - $this->phpMailer->addBCC($bcc['email'], $bcc['name']); - } - } - - $this->phpMailer->Subject = $message->renderSubject($recipient->getParams()); - $this->phpMailer->Body = $message->renderBody($recipient->getParams()); - - // Try to send the mail. Will throw an exception on failure. - $this->phpMailer->send(); - - // Clear recipients from the PHPMailer object for this iteration, - // so that we can send a separate email to the next recipient. - $this->phpMailer->clearAllRecipients(); - } - - // Clear out the MailMessage's internal recipient list - if ($clearRecipients) { - $message->clearRecipients(); - } - } - - /** - * Set option(s) on the underlying phpMailer object. - * - * @param mixed[] $options - * @return Mailer - */ - public function setOptions($options) { - if (isset($options['isHtml'])) { - $this->phpMailer->isHTML($options['isHtml']); - } - - foreach ($options as $name => $value) { - $this->phpMailer->set($name, $value); - } - - return $this; - } -} +logger = $logger; + + // 'true' tells PHPMailer to use exceptions instead of error codes + $this->phpMailer = new \PHPMailer(TRUE); + + // Configuration options + if (isset($config['mailer'])) { + if (!in_array($config['mailer'], ['smtp', 'mail', 'qmail', 'sendmail'])) { + throw new \phpmailerException("'mailer' must be one of 'smtp', 'mail', 'qmail', or 'sendmail'."); + } + + if ($config['mailer'] == 'smtp') { + $this->phpMailer->isSMTP(TRUE); + $this->phpMailer->Host = $config['host']; + $this->phpMailer->Port = $config['port']; + $this->phpMailer->SMTPAuth = $config['auth']; + $this->phpMailer->SMTPSecure = $config['secure']; + $this->phpMailer->Username = $config['username']; + $this->phpMailer->Password = $config['password']; + $this->phpMailer->SMTPDebug = $config['smtp_debug']; + + if (isset($config['smtp_options'])) { + $this->phpMailer->SMTPOptions = $config['smtp_options']; + } + } + + // Set any additional message-specific options + // enforce which options can be set through this subarray + if (isset($config['message_options'])) { + $this->setOptions($config['message_options']); + } + } + + // Pass logger into phpMailer object + $this->phpMailer->Debugoutput = function ($message, $level) { + $this->logger->debug($message); + }; + } + + /** + * Get the underlying PHPMailer object. + * + * @return \PHPMailer + */ + public function getPhpMailer() { + return $this->phpMailer; + } + + /** + * Send a MailMessage message. + * + * Sends a single email to all recipients, as well as their CCs and BCCs. + * Since it is a single-header message, recipient-specific template data will not be included. + * @param MailMessage $message + * @param bool $clearRecipients Set to true to clear the list of recipients in the message after calling send(). This helps avoid accidentally sending a message multiple times. + * @throws \phpmailerException The message could not be sent. + */ + public function send(MailMessage $message, $clearRecipients = TRUE) { + $this->phpMailer->From = $message->getFromEmail(); + $this->phpMailer->FromName = $message->getFromName(); + $this->phpMailer->addReplyTo($message->getReplyEmail(), $message->getReplyName()); + + // Add all email recipients, as well as their CCs and BCCs + foreach ($message->getRecipients() as $recipient) { + $this->phpMailer->addAddress($recipient->getEmail(), $recipient->getName()); + + // Add any CCs and BCCs + if ($recipient->getCCs()) { + foreach ($recipient->getCCs() as $cc) { + $this->phpMailer->addCC($cc['email'], $cc['name']); + } + } + + if ($recipient->getBCCs()) { + foreach ($recipient->getBCCs() as $bcc) { + $this->phpMailer->addBCC($bcc['email'], $bcc['name']); + } + } + } + + $this->phpMailer->Subject = $message->renderSubject(); + $this->phpMailer->Body = $message->renderBody(); + + // Try to send the mail. Will throw an exception on failure. + $this->phpMailer->send(); + + // Clear recipients from the PHPMailer object for this iteration, + // so that we can use the same object for other emails. + $this->phpMailer->clearAllRecipients(); + + // Clear out the MailMessage's internal recipient list + if ($clearRecipients) { + $message->clearRecipients(); + } + } + + /** + * Send a MailMessage message, sending a separate email to each recipient. + * + * If the message object supports message templates, this will render the template with the corresponding placeholder values for each recipient. + * @param MailMessage $message + * @param bool $clearRecipients Set to true to clear the list of recipients in the message after calling send(). This helps avoid accidentally sending a message multiple times. + * @throws \phpmailerException The message could not be sent. + */ + public function sendDistinct(MailMessage $message, $clearRecipients = TRUE) { + $this->phpMailer->From = $message->getFromEmail(); + $this->phpMailer->FromName = $message->getFromName(); + $this->phpMailer->addReplyTo($message->getReplyEmail(), $message->getReplyName()); + + // Loop through email recipients, sending customized content to each one + foreach ($message->getRecipients() as $recipient) { + $this->phpMailer->addAddress($recipient->getEmail(), $recipient->getName()); + + // Add any CCs and BCCs + if ($recipient->getCCs()) { + foreach ($recipient->getCCs() as $cc) { + $this->phpMailer->addCC($cc['email'], $cc['name']); + } + } + + if ($recipient->getBCCs()) { + foreach ($recipient->getBCCs() as $bcc) { + $this->phpMailer->addBCC($bcc['email'], $bcc['name']); + } + } + + $this->phpMailer->Subject = $message->renderSubject($recipient->getParams()); + $this->phpMailer->Body = $message->renderBody($recipient->getParams()); + + // Try to send the mail. Will throw an exception on failure. + $this->phpMailer->send(); + + // Clear recipients from the PHPMailer object for this iteration, + // so that we can send a separate email to the next recipient. + $this->phpMailer->clearAllRecipients(); + } + + // Clear out the MailMessage's internal recipient list + if ($clearRecipients) { + $message->clearRecipients(); + } + } + + /** + * Set option(s) on the underlying phpMailer object. + * + * @param mixed[] $options + * @return Mailer + */ + public function setOptions($options) { + if (isset($options['isHtml'])) { + $this->phpMailer->isHTML($options['isHtml']); + } + + foreach ($options as $name => $value) { + $this->phpMailer->set($name, $value); + } + + return $this; + } +} diff --git a/main/app/sprinkles/core/src/Mail/StaticMailMessage.php b/main/app/sprinkles/core/src/Mail/StaticMailMessage.php index 482226c..17758db 100644 --- a/main/app/sprinkles/core/src/Mail/StaticMailMessage.php +++ b/main/app/sprinkles/core/src/Mail/StaticMailMessage.php @@ -1,74 +1,74 @@ -subject = $subject; - $this->body = $body; - } - - /** - * {@inheritDoc} - */ - public function renderBody($params = []) { - return $this->body; - } - - /** - * {@inheritDoc} - */ - public function renderSubject($params = []) { - return $this->subject; - } - - /** - * Set the text of the message subject. - * - * @param string $subject - */ - public function setSubject($subject) { - $this->subject = $subject; - return $this; - } - - /** - * Set the text of the message body. - * - * @param string $body - */ - public function setBody($body) { - $this->body = $body; - return $this; - } -} +subject = $subject; + $this->body = $body; + } + + /** + * {@inheritDoc} + */ + public function renderBody($params = []) { + return $this->body; + } + + /** + * {@inheritDoc} + */ + public function renderSubject($params = []) { + return $this->subject; + } + + /** + * Set the text of the message subject. + * + * @param string $subject + */ + public function setSubject($subject) { + $this->subject = $subject; + return $this; + } + + /** + * Set the text of the message body. + * + * @param string $body + */ + public function setBody($body) { + $this->body = $body; + return $this; + } +} diff --git a/main/app/sprinkles/core/src/Mail/TwigMailMessage.php b/main/app/sprinkles/core/src/Mail/TwigMailMessage.php index aa4daea..7197f75 100644 --- a/main/app/sprinkles/core/src/Mail/TwigMailMessage.php +++ b/main/app/sprinkles/core/src/Mail/TwigMailMessage.php @@ -1,89 +1,89 @@ -view = $view; - - $twig = $this->view->getEnvironment(); - // Must manually merge in global variables for block rendering - // should we keep this separate from the local parameters? - $this->params = $twig->getGlobals(); - - if ($filename !== NULL) { - $this->template = $twig->loadTemplate($filename); - } - } - - /** - * Merge in any additional global Twig variables to use when rendering this message. - * - * @param mixed[] $params - */ - public function addParams($params = []) { - $this->params = array_replace_recursive($this->params, $params); - return $this; - } - - /** - * {@inheritDoc} - */ - public function renderSubject($params = []) { - $params = array_replace_recursive($this->params, $params); - return $this->template->renderBlock('subject', $params); - } - - /** - * {@inheritDoc} - */ - public function renderBody($params = []) { - $params = array_replace_recursive($this->params, $params); - return $this->template->renderBlock('body', $params); - } - - /** - * Sets the Twig template object for this message. - * - * @param Twig_Template $template The Twig template object, to source the content for this message. - */ - public function setTemplate($template) { - $this->template = $template; - return $this; - } -} +view = $view; + + $twig = $this->view->getEnvironment(); + // Must manually merge in global variables for block rendering + // should we keep this separate from the local parameters? + $this->params = $twig->getGlobals(); + + if ($filename !== NULL) { + $this->template = $twig->loadTemplate($filename); + } + } + + /** + * Merge in any additional global Twig variables to use when rendering this message. + * + * @param mixed[] $params + */ + public function addParams($params = []) { + $this->params = array_replace_recursive($this->params, $params); + return $this; + } + + /** + * {@inheritDoc} + */ + public function renderSubject($params = []) { + $params = array_replace_recursive($this->params, $params); + return $this->template->renderBlock('subject', $params); + } + + /** + * {@inheritDoc} + */ + public function renderBody($params = []) { + $params = array_replace_recursive($this->params, $params); + return $this->template->renderBlock('body', $params); + } + + /** + * Sets the Twig template object for this message. + * + * @param Twig_Template $template The Twig template object, to source the content for this message. + */ + public function setTemplate($template) { + $this->template = $template; + return $this; + } +} diff --git a/main/app/sprinkles/core/src/Model/UFModel.php b/main/app/sprinkles/core/src/Model/UFModel.php index d852606..fb01357 100644 --- a/main/app/sprinkles/core/src/Model/UFModel.php +++ b/main/app/sprinkles/core/src/Model/UFModel.php @@ -1,27 +1,27 @@ -routeGroups) { - $pattern = $this->processGroups() . $pattern; - } - - // According to RFC methods are defined in uppercase (See RFC 7231) - $methods = array_map("strtoupper", $methods); - - // Determine route signature - $signature = implode('-', $methods) . '-' . $pattern; - - // If a route with the same signature already exists, then we must replace it - if (isset($this->identifiers[$signature])) { - $route = new \Slim\Route($methods, $pattern, $handler, $this->routeGroups, str_replace('route', '', $this->identifiers[$signature])); - } else { - $route = new \Slim\Route($methods, $pattern, $handler, $this->routeGroups, $this->routeCounter); - } - - $this->routes[$route->getIdentifier()] = $route; - - // Record identifier in reverse lookup array - $this->identifiers[$signature] = $route->getIdentifier(); - - $this->routeCounter++; - - return $route; - } - - /** - * Delete the cache file - * - * @access public - * @return bool true/false if operation is successfull - */ - public function clearCache() { - // Get Filesystem instance - $fs = new FileSystem; - - // Make sure file exist and delete it - if ($fs->exists($this->cacheFile)) { - return $fs->delete($this->cacheFile); - } - - // It's still considered a success if file doesn't exist - return TRUE; - } -} +routeGroups) { + $pattern = $this->processGroups() . $pattern; + } + + // According to RFC methods are defined in uppercase (See RFC 7231) + $methods = array_map("strtoupper", $methods); + + // Determine route signature + $signature = implode('-', $methods) . '-' . $pattern; + + // If a route with the same signature already exists, then we must replace it + if (isset($this->identifiers[$signature])) { + $route = new \Slim\Route($methods, $pattern, $handler, $this->routeGroups, str_replace('route', '', $this->identifiers[$signature])); + } else { + $route = new \Slim\Route($methods, $pattern, $handler, $this->routeGroups, $this->routeCounter); + } + + $this->routes[$route->getIdentifier()] = $route; + + // Record identifier in reverse lookup array + $this->identifiers[$signature] = $route->getIdentifier(); + + $this->routeCounter++; + + return $route; + } + + /** + * Delete the cache file + * + * @access public + * @return bool true/false if operation is successfull + */ + public function clearCache() { + // Get Filesystem instance + $fs = new FileSystem; + + // Make sure file exist and delete it + if ($fs->exists($this->cacheFile)) { + return $fs->delete($this->cacheFile); + } + + // It's still considered a success if file doesn't exist + return TRUE; + } +} diff --git a/main/app/sprinkles/core/src/ServicesProvider/ServicesProvider.php b/main/app/sprinkles/core/src/ServicesProvider/ServicesProvider.php index 6ac8c41..0adc75a 100644 --- a/main/app/sprinkles/core/src/ServicesProvider/ServicesProvider.php +++ b/main/app/sprinkles/core/src/ServicesProvider/ServicesProvider.php @@ -1,621 +1,621 @@ -config; - - if ($config['alert.storage'] == 'cache') { - return new CacheAlertStream($config['alert.key'], $c->translator, $c->cache, $c->config); - } else if ($config['alert.storage'] == 'session') { - return new SessionAlertStream($config['alert.key'], $c->translator, $c->session); - } else { - throw new \Exception("Bad alert storage handler type '{$config['alert.storage']}' specified in configuration file."); - } - }; - - /** - * Asset loader service. - * - * Loads assets from a specified relative location. - * Assets are Javascript, CSS, image, and other files used by your site. - */ - $container['assetLoader'] = function ($c) { - $basePath = \UserFrosting\SPRINKLES_DIR; - $pattern = "/^[A-Za-z0-9_\-]+\/assets\//"; - - $al = new AssetLoader($basePath, $pattern); - return $al; - }; - - /** - * Asset manager service. - * - * Loads raw or compiled asset information from your bundle.config.json schema file. - * Assets are Javascript, CSS, image, and other files used by your site. - */ - $container['assets'] = function ($c) { - $config = $c->config; - $locator = $c->locator; - - // Load asset schema - if ($config['assets.use_raw']) { - $baseUrl = $config['site.uri.public'] . '/' . $config['assets.raw.path']; - $removePrefix = \UserFrosting\APP_DIR_NAME . \UserFrosting\DS . \UserFrosting\SPRINKLES_DIR_NAME; - $aub = new AssetUrlBuilder($locator, $baseUrl, $removePrefix, 'assets'); - - $as = new AssetBundleSchema($aub); - - // Load Sprinkle assets - $sprinkles = $c->sprinkleManager->getSprinkleNames(); - - // move this out into PathBuilder and Loader classes in userfrosting/assets - // This would also allow us to define and load bundles in themes - $bundleSchemas = array_reverse($locator->findResources('sprinkles://' . $config['assets.raw.schema'], TRUE, TRUE)); - - foreach ($bundleSchemas as $schema) { - if (file_exists($schema)) { - $as->loadRawSchemaFile($schema); - } - } - } else { - $baseUrl = $config['site.uri.public'] . '/' . $config['assets.compiled.path']; - $aub = new CompiledAssetUrlBuilder($baseUrl); - - $as = new AssetBundleSchema($aub); - $as->loadCompiledSchemaFile($locator->findResource("build://" . $config['assets.compiled.schema'], TRUE, TRUE)); - } - - $am = new AssetManager($aub, $as); - - return $am; - }; - - /** - * Cache service. - * - * @return \Illuminate\Cache\Repository - */ - $container['cache'] = function ($c) { - - $config = $c->config; - - if ($config['cache.driver'] == 'file') { - $path = $c->locator->findResource('cache://', TRUE, TRUE); - $cacheStore = new TaggableFileStore($path); - } else if ($config['cache.driver'] == 'memcached') { - // We need to inject the prefix in the memcached config - $config = array_merge($config['cache.memcached'], ['prefix' => $config['cache.prefix']]); - $cacheStore = new MemcachedStore($config); - } else if ($config['cache.driver'] == 'redis') { - // We need to inject the prefix in the redis config - $config = array_merge($config['cache.redis'], ['prefix' => $config['cache.prefix']]); - $cacheStore = new RedisStore($config); - } else { - throw new \Exception("Bad cache store type '{$config['cache.driver']}' specified in configuration file."); - } - - return $cacheStore->instance(); - }; - - /** - * Middleware to check environment. - * - * We should cache the results of this, the first time that it succeeds. - */ - $container['checkEnvironment'] = function ($c) { - $checkEnvironment = new CheckEnvironment($c->view, $c->locator, $c->cache); - return $checkEnvironment; - }; - - /** - * Class mapper. - * - * Creates an abstraction on top of class names to allow extending them in sprinkles. - */ - $container['classMapper'] = function ($c) { - $classMapper = new ClassMapper(); - $classMapper->setClassMapping('query_builder', 'UserFrosting\Sprinkle\Core\Database\Builder'); - $classMapper->setClassMapping('throttle', 'UserFrosting\Sprinkle\Core\Database\Models\Throttle'); - return $classMapper; - }; - - /** - * Site config service (separate from Slim settings). - * - * Will attempt to automatically determine which config file(s) to use based on the value of the UF_MODE environment variable. - */ - $container['config'] = function ($c) { - // Grab any relevant dotenv variables from the .env file - try { - $dotenv = new Dotenv(\UserFrosting\APP_DIR); - $dotenv->load(); - } catch (InvalidPathException $e) { - // Skip loading the environment config file if it doesn't exist. - } - - // Get configuration mode from environment - $mode = getenv('UF_MODE') ?: ''; - - // Construct and load config repository - $builder = new ConfigPathBuilder($c->locator, 'config://'); - $loader = new ArrayFileLoader($builder->buildPaths($mode)); - $config = new Repository($loader->load()); - - // Construct base url from components, if not explicitly specified - if (!isset($config['site.uri.public'])) { - $base_uri = $config['site.uri.base']; - - $public = new Uri( - $base_uri['scheme'], - $base_uri['host'], - $base_uri['port'], - $base_uri['path'] - ); - - // Slim\Http\Uri likes to add trailing slashes when the path is empty, so this fixes that. - $config['site.uri.public'] = trim($public, '/'); - } - - // Hacky fix to prevent sessions from being hit too much: ignore CSRF middleware for requests for raw assets ;-) - // See https://github.com/laravel/framework/issues/8172#issuecomment-99112012 for more information on why it's bad to hit Laravel sessions multiple times in rapid succession. - $csrfBlacklist = $config['csrf.blacklist']; - $csrfBlacklist['^/' . $config['assets.raw.path']] = [ - 'GET' - ]; - $csrfBlacklist['^/wormhole'] = [ - 'POST' - ]; - - $config->set('csrf.blacklist', $csrfBlacklist); - - return $config; - }; - - /** - * Initialize CSRF guard middleware. - * - * @see https://github.com/slimphp/Slim-Csrf - */ - $container['csrf'] = function ($c) { - $csrfKey = $c->config['session.keys.csrf']; - - // Workaround so that we can pass storage into CSRF guard. - // If we tried to directly pass the indexed portion of `session` (for example, $c->session['site.csrf']), - // we would get an 'Indirect modification of overloaded element of UserFrosting\Session\Session' error. - // If we tried to assign an array and use that, PHP would only modify the local variable, and not the session. - // Since ArrayObject is an object, PHP will modify the object itself, allowing it to persist in the session. - if (!$c->session->has($csrfKey)) { - $c->session[$csrfKey] = new \ArrayObject(); - } - $csrfStorage = $c->session[$csrfKey]; - - $onFailure = function ($request, $response, $next) { - $e = new BadRequestException("The CSRF code was invalid or not provided."); - $e->addUserMessage('CSRF_MISSING'); - throw $e; - - return $next($request, $response); - }; - - return new Guard($c->config['csrf.name'], $csrfStorage, $onFailure, $c->config['csrf.storage_limit'], $c->config['csrf.strength'], $c->config['csrf.persistent_token']); - }; - - /** - * Initialize Eloquent Capsule, which provides the database layer for UF. - * - * construct the individual objects rather than using the facade - */ - $container['db'] = function ($c) { - $config = $c->config; - - $capsule = new Capsule; - - foreach ($config['db'] as $name => $dbConfig) { - $capsule->addConnection($dbConfig, $name); - } - - $queryEventDispatcher = new Dispatcher(new Container); - - $capsule->setEventDispatcher($queryEventDispatcher); - - // Register as global connection - $capsule->setAsGlobal(); - - // Start Eloquent - $capsule->bootEloquent(); - - if ($config['debug.queries']) { - $logger = $c->queryLogger; - - foreach ($config['db'] as $name => $dbConfig) { - $capsule->connection($name)->enableQueryLog(); - } - - // Register listener - $queryEventDispatcher->listen(QueryExecuted::class, function ($query) use ($logger) { - $logger->debug("Query executed on database [{$query->connectionName}]:", [ - 'query' => $query->sql, - 'bindings' => $query->bindings, - 'time' => $query->time . ' ms' - ]); - }); - } - - return $capsule; - }; - - /** - * Debug logging with Monolog. - * - * Extend this service to push additional handlers onto the 'debug' log stack. - */ - $container['debugLogger'] = function ($c) { - $logger = new Logger('debug'); - - $logFile = $c->locator->findResource('log://userfrosting.log', TRUE, TRUE); - - $handler = new StreamHandler($logFile); - - $formatter = new MixedFormatter(NULL, NULL, TRUE); - - $handler->setFormatter($formatter); - $logger->pushHandler($handler); - - return $logger; - }; - - /** - * Custom error-handler for recoverable errors. - */ - $container['errorHandler'] = function ($c) { - $settings = $c->settings; - - $handler = new ExceptionHandlerManager($c, $settings['displayErrorDetails']); - - // Register the base HttpExceptionHandler. - $handler->registerHandler('\UserFrosting\Support\Exception\HttpException', '\UserFrosting\Sprinkle\Core\Error\Handler\HttpExceptionHandler'); - - // Register the NotFoundExceptionHandler. - $handler->registerHandler('\UserFrosting\Support\Exception\NotFoundException', '\UserFrosting\Sprinkle\Core\Error\Handler\NotFoundExceptionHandler'); - - // Register the PhpMailerExceptionHandler. - $handler->registerHandler('\phpmailerException', '\UserFrosting\Sprinkle\Core\Error\Handler\PhpMailerExceptionHandler'); - - return $handler; - }; - - /** - * Error logging with Monolog. - * - * Extend this service to push additional handlers onto the 'error' log stack. - */ - $container['errorLogger'] = function ($c) { - $log = new Logger('errors'); - - $logFile = $c->locator->findResource('log://userfrosting.log', TRUE, TRUE); - - $handler = new StreamHandler($logFile, Logger::WARNING); - - $formatter = new LineFormatter(NULL, NULL, TRUE); - - $handler->setFormatter($formatter); - $log->pushHandler($handler); - - return $log; - }; - - /** - * Factory service with FactoryMuffin. - * - * Provide access to factories for the rapid creation of objects for the purpose of testing - */ - $container['factory'] = function ($c) { - - // Get the path of all of the sprinkle's factories - $factoriesPath = $c->locator->findResources('factories://', TRUE, TRUE); - - // Create a new Factory Muffin instance - $fm = new FactoryMuffin(); - - // Load all of the model definitions - $fm->loadFactories($factoriesPath); - - // Set the locale. Could be the config one, but for testing English should do - Faker::setLocale('en_EN'); - - return $fm; - }; - - /** - * Builds search paths for locales in all Sprinkles. - */ - $container['localePathBuilder'] = function ($c) { - $config = $c->config; - - // Make sure the locale config is a valid string - if (!is_string($config['site.locales.default']) || $config['site.locales.default'] == '') { - throw new \UnexpectedValueException('The locale config is not a valid string.'); - } - - // Load the base locale file(s) as specified in the configuration - $locales = explode(',', $config['site.locales.default']); - - return new LocalePathBuilder($c->locator, 'locale://', $locales); - }; - - /** - * Mail service. - */ - $container['mailer'] = function ($c) { - $mailer = new Mailer($c->mailLogger, $c->config['mail']); - - // Use UF debug settings to override any service-specific log settings. - if (!$c->config['debug.smtp']) { - $mailer->getPhpMailer()->SMTPDebug = 0; - } - - return $mailer; - }; - - /** - * Mail logging service. - * - * PHPMailer will use this to log SMTP activity. - * Extend this service to push additional handlers onto the 'mail' log stack. - */ - $container['mailLogger'] = function ($c) { - $log = new Logger('mail'); - - $logFile = $c->locator->findResource('log://userfrosting.log', TRUE, TRUE); - - $handler = new StreamHandler($logFile); - $formatter = new LineFormatter(NULL, NULL, TRUE); - - $handler->setFormatter($formatter); - $log->pushHandler($handler); - - return $log; - }; - - /** - * Error-handler for 404 errors. Notice that we manually create a UserFrosting NotFoundException, - * and a NotFoundExceptionHandler. This lets us pass through to the UF error handling system. - */ - $container['notFoundHandler'] = function ($c) { - return function ($request, $response) use ($c) { - $exception = new NotFoundException; - $handler = new NotFoundExceptionHandler($c, $request, $response, $exception, $c->settings['displayErrorDetails']); - return $handler->handle(); - }; - }; - - /** - * Error-handler for PHP runtime errors. Notice that we just pass this through to our general-purpose - * error-handling service. - */ - $container['phpErrorHandler'] = function ($c) { - return $c->errorHandler; - }; - - /** - * Laravel query logging with Monolog. - * - * Extend this service to push additional handlers onto the 'query' log stack. - */ - $container['queryLogger'] = function ($c) { - $logger = new Logger('query'); - - $logFile = $c->locator->findResource('log://userfrosting.log', TRUE, TRUE); - - $handler = new StreamHandler($logFile); - - $formatter = new MixedFormatter(NULL, NULL, TRUE); - - $handler->setFormatter($formatter); - $logger->pushHandler($handler); - - return $logger; - }; - - /** - * Override Slim's default router with the UF router. - */ - $container['router'] = function ($c) { - $routerCacheFile = FALSE; - if (isset($c->config['settings.routerCacheFile'])) { - $routerCacheFile = $c->config['settings.routerCacheFile']; - } - - return (new Router)->setCacheFile($routerCacheFile); - }; - - /** - * Start the PHP session, with the name and parameters specified in the configuration file. - */ - $container['session'] = function ($c) { - $config = $c->config; - - // Create appropriate handler based on config - if ($config['session.handler'] == 'file') { - $fs = new FileSystem; - $handler = new FileSessionHandler($fs, $c->locator->findResource('session://'), $config['session.minutes']); - } else if ($config['session.handler'] == 'database') { - $connection = $c->db->connection(); - // Table must exist, otherwise an exception will be thrown - $handler = new DatabaseSessionHandler($connection, $config['session.database.table'], $config['session.minutes']); - } else { - throw new \Exception("Bad session handler type '{$config['session.handler']}' specified in configuration file."); - } - - // Create, start and return a new wrapper for $_SESSION - $session = new Session($handler, $config['session']); - $session->start(); - - return $session; - }; - - /** - * Request throttler. - * - * Throttles (rate-limits) requests of a predefined type, with rules defined in site config. - */ - $container['throttler'] = function ($c) { - $throttler = new Throttler($c->classMapper); - - $config = $c->config; - - if ($config->has('throttles') && ($config['throttles'] !== NULL)) { - foreach ($config['throttles'] as $type => $rule) { - if ($rule) { - $throttleRule = new ThrottleRule($rule['method'], $rule['interval'], $rule['delays']); - $throttler->addThrottleRule($type, $throttleRule); - } else { - $throttler->addThrottleRule($type, NULL); - } - } - } - - return $throttler; - }; - - /** - * Translation service, for translating message tokens. - */ - $container['translator'] = function ($c) { - // Load the translations - $paths = $c->localePathBuilder->buildPaths(); - $loader = new ArrayFileLoader($paths); - - // Create the $translator object - $translator = new MessageTranslator($loader->load()); - - return $translator; - }; - - /** - * Set up Twig as the view, adding template paths for all sprinkles and the Slim Twig extension. - * - * Also adds the UserFrosting core Twig extension, which provides additional functions, filters, global variables, etc. - */ - $container['view'] = function ($c) { - $templatePaths = $c->locator->findResources('templates://', TRUE, TRUE); - - $view = new Twig($templatePaths); - - $loader = $view->getLoader(); - - $sprinkles = $c->sprinkleManager->getSprinkleNames(); - - // Add Sprinkles' templates namespaces - foreach ($sprinkles as $sprinkle) { - $path = \UserFrosting\SPRINKLES_DIR . \UserFrosting\DS . - $sprinkle . \UserFrosting\DS . - \UserFrosting\TEMPLATE_DIR_NAME . \UserFrosting\DS; - - if (is_dir($path)) { - $loader->addPath($path, $sprinkle); - } - } - - $twig = $view->getEnvironment(); - - if ($c->config['cache.twig']) { - $twig->setCache($c->locator->findResource('cache://twig', TRUE, TRUE)); - } - - if ($c->config['debug.twig']) { - $twig->enableDebug(); - $view->addExtension(new \Twig_Extension_Debug()); - } - - // Register the Slim extension with Twig - $slimExtension = new TwigExtension( - $c->router, - $c->request->getUri() - ); - $view->addExtension($slimExtension); - - // Register the core UF extension with Twig - $coreExtension = new CoreExtension($c); - $view->addExtension($coreExtension); - - return $view; - }; - } -} +config; + + if ($config['alert.storage'] == 'cache') { + return new CacheAlertStream($config['alert.key'], $c->translator, $c->cache, $c->config); + } else if ($config['alert.storage'] == 'session') { + return new SessionAlertStream($config['alert.key'], $c->translator, $c->session); + } else { + throw new \Exception("Bad alert storage handler type '{$config['alert.storage']}' specified in configuration file."); + } + }; + + /** + * Asset loader service. + * + * Loads assets from a specified relative location. + * Assets are Javascript, CSS, image, and other files used by your site. + */ + $container['assetLoader'] = function ($c) { + $basePath = \UserFrosting\SPRINKLES_DIR; + $pattern = "/^[A-Za-z0-9_\-]+\/assets\//"; + + $al = new AssetLoader($basePath, $pattern); + return $al; + }; + + /** + * Asset manager service. + * + * Loads raw or compiled asset information from your bundle.config.json schema file. + * Assets are Javascript, CSS, image, and other files used by your site. + */ + $container['assets'] = function ($c) { + $config = $c->config; + $locator = $c->locator; + + // Load asset schema + if ($config['assets.use_raw']) { + $baseUrl = $config['site.uri.public'] . '/' . $config['assets.raw.path']; + $removePrefix = \UserFrosting\APP_DIR_NAME . \UserFrosting\DS . \UserFrosting\SPRINKLES_DIR_NAME; + $aub = new AssetUrlBuilder($locator, $baseUrl, $removePrefix, 'assets'); + + $as = new AssetBundleSchema($aub); + + // Load Sprinkle assets + $sprinkles = $c->sprinkleManager->getSprinkleNames(); + + // move this out into PathBuilder and Loader classes in userfrosting/assets + // This would also allow us to define and load bundles in themes + $bundleSchemas = array_reverse($locator->findResources('sprinkles://' . $config['assets.raw.schema'], TRUE, TRUE)); + + foreach ($bundleSchemas as $schema) { + if (file_exists($schema)) { + $as->loadRawSchemaFile($schema); + } + } + } else { + $baseUrl = $config['site.uri.public'] . '/' . $config['assets.compiled.path']; + $aub = new CompiledAssetUrlBuilder($baseUrl); + + $as = new AssetBundleSchema($aub); + $as->loadCompiledSchemaFile($locator->findResource("build://" . $config['assets.compiled.schema'], TRUE, TRUE)); + } + + $am = new AssetManager($aub, $as); + + return $am; + }; + + /** + * Cache service. + * + * @return \Illuminate\Cache\Repository + */ + $container['cache'] = function ($c) { + + $config = $c->config; + + if ($config['cache.driver'] == 'file') { + $path = $c->locator->findResource('cache://', TRUE, TRUE); + $cacheStore = new TaggableFileStore($path); + } else if ($config['cache.driver'] == 'memcached') { + // We need to inject the prefix in the memcached config + $config = array_merge($config['cache.memcached'], ['prefix' => $config['cache.prefix']]); + $cacheStore = new MemcachedStore($config); + } else if ($config['cache.driver'] == 'redis') { + // We need to inject the prefix in the redis config + $config = array_merge($config['cache.redis'], ['prefix' => $config['cache.prefix']]); + $cacheStore = new RedisStore($config); + } else { + throw new \Exception("Bad cache store type '{$config['cache.driver']}' specified in configuration file."); + } + + return $cacheStore->instance(); + }; + + /** + * Middleware to check environment. + * + * We should cache the results of this, the first time that it succeeds. + */ + $container['checkEnvironment'] = function ($c) { + $checkEnvironment = new CheckEnvironment($c->view, $c->locator, $c->cache); + return $checkEnvironment; + }; + + /** + * Class mapper. + * + * Creates an abstraction on top of class names to allow extending them in sprinkles. + */ + $container['classMapper'] = function ($c) { + $classMapper = new ClassMapper(); + $classMapper->setClassMapping('query_builder', 'UserFrosting\Sprinkle\Core\Database\Builder'); + $classMapper->setClassMapping('throttle', 'UserFrosting\Sprinkle\Core\Database\Models\Throttle'); + return $classMapper; + }; + + /** + * Site config service (separate from Slim settings). + * + * Will attempt to automatically determine which config file(s) to use based on the value of the UF_MODE environment variable. + */ + $container['config'] = function ($c) { + // Grab any relevant dotenv variables from the .env file + try { + $dotenv = new Dotenv(\UserFrosting\APP_DIR); + $dotenv->load(); + } catch (InvalidPathException $e) { + // Skip loading the environment config file if it doesn't exist. + } + + // Get configuration mode from environment + $mode = getenv('UF_MODE') ?: ''; + + // Construct and load config repository + $builder = new ConfigPathBuilder($c->locator, 'config://'); + $loader = new ArrayFileLoader($builder->buildPaths($mode)); + $config = new Repository($loader->load()); + + // Construct base url from components, if not explicitly specified + if (!isset($config['site.uri.public'])) { + $base_uri = $config['site.uri.base']; + + $public = new Uri( + $base_uri['scheme'], + $base_uri['host'], + $base_uri['port'], + $base_uri['path'] + ); + + // Slim\Http\Uri likes to add trailing slashes when the path is empty, so this fixes that. + $config['site.uri.public'] = trim($public, '/'); + } + + // Hacky fix to prevent sessions from being hit too much: ignore CSRF middleware for requests for raw assets ;-) + // See https://github.com/laravel/framework/issues/8172#issuecomment-99112012 for more information on why it's bad to hit Laravel sessions multiple times in rapid succession. + $csrfBlacklist = $config['csrf.blacklist']; + $csrfBlacklist['^/' . $config['assets.raw.path']] = [ + 'GET' + ]; + $csrfBlacklist['^/wormhole'] = [ + 'POST' + ]; + + $config->set('csrf.blacklist', $csrfBlacklist); + + return $config; + }; + + /** + * Initialize CSRF guard middleware. + * + * @see https://github.com/slimphp/Slim-Csrf + */ + $container['csrf'] = function ($c) { + $csrfKey = $c->config['session.keys.csrf']; + + // Workaround so that we can pass storage into CSRF guard. + // If we tried to directly pass the indexed portion of `session` (for example, $c->session['site.csrf']), + // we would get an 'Indirect modification of overloaded element of UserFrosting\Session\Session' error. + // If we tried to assign an array and use that, PHP would only modify the local variable, and not the session. + // Since ArrayObject is an object, PHP will modify the object itself, allowing it to persist in the session. + if (!$c->session->has($csrfKey)) { + $c->session[$csrfKey] = new \ArrayObject(); + } + $csrfStorage = $c->session[$csrfKey]; + + $onFailure = function ($request, $response, $next) { + $e = new BadRequestException("The CSRF code was invalid or not provided."); + $e->addUserMessage('CSRF_MISSING'); + throw $e; + + return $next($request, $response); + }; + + return new Guard($c->config['csrf.name'], $csrfStorage, $onFailure, $c->config['csrf.storage_limit'], $c->config['csrf.strength'], $c->config['csrf.persistent_token']); + }; + + /** + * Initialize Eloquent Capsule, which provides the database layer for UF. + * + * construct the individual objects rather than using the facade + */ + $container['db'] = function ($c) { + $config = $c->config; + + $capsule = new Capsule; + + foreach ($config['db'] as $name => $dbConfig) { + $capsule->addConnection($dbConfig, $name); + } + + $queryEventDispatcher = new Dispatcher(new Container); + + $capsule->setEventDispatcher($queryEventDispatcher); + + // Register as global connection + $capsule->setAsGlobal(); + + // Start Eloquent + $capsule->bootEloquent(); + + if ($config['debug.queries']) { + $logger = $c->queryLogger; + + foreach ($config['db'] as $name => $dbConfig) { + $capsule->connection($name)->enableQueryLog(); + } + + // Register listener + $queryEventDispatcher->listen(QueryExecuted::class, function ($query) use ($logger) { + $logger->debug("Query executed on database [{$query->connectionName}]:", [ + 'query' => $query->sql, + 'bindings' => $query->bindings, + 'time' => $query->time . ' ms' + ]); + }); + } + + return $capsule; + }; + + /** + * Debug logging with Monolog. + * + * Extend this service to push additional handlers onto the 'debug' log stack. + */ + $container['debugLogger'] = function ($c) { + $logger = new Logger('debug'); + + $logFile = $c->locator->findResource('log://userfrosting.log', TRUE, TRUE); + + $handler = new StreamHandler($logFile); + + $formatter = new MixedFormatter(NULL, NULL, TRUE); + + $handler->setFormatter($formatter); + $logger->pushHandler($handler); + + return $logger; + }; + + /** + * Custom error-handler for recoverable errors. + */ + $container['errorHandler'] = function ($c) { + $settings = $c->settings; + + $handler = new ExceptionHandlerManager($c, $settings['displayErrorDetails']); + + // Register the base HttpExceptionHandler. + $handler->registerHandler('\UserFrosting\Support\Exception\HttpException', '\UserFrosting\Sprinkle\Core\Error\Handler\HttpExceptionHandler'); + + // Register the NotFoundExceptionHandler. + $handler->registerHandler('\UserFrosting\Support\Exception\NotFoundException', '\UserFrosting\Sprinkle\Core\Error\Handler\NotFoundExceptionHandler'); + + // Register the PhpMailerExceptionHandler. + $handler->registerHandler('\phpmailerException', '\UserFrosting\Sprinkle\Core\Error\Handler\PhpMailerExceptionHandler'); + + return $handler; + }; + + /** + * Error logging with Monolog. + * + * Extend this service to push additional handlers onto the 'error' log stack. + */ + $container['errorLogger'] = function ($c) { + $log = new Logger('errors'); + + $logFile = $c->locator->findResource('log://userfrosting.log', TRUE, TRUE); + + $handler = new StreamHandler($logFile, Logger::WARNING); + + $formatter = new LineFormatter(NULL, NULL, TRUE); + + $handler->setFormatter($formatter); + $log->pushHandler($handler); + + return $log; + }; + + /** + * Factory service with FactoryMuffin. + * + * Provide access to factories for the rapid creation of objects for the purpose of testing + */ + $container['factory'] = function ($c) { + + // Get the path of all of the sprinkle's factories + $factoriesPath = $c->locator->findResources('factories://', TRUE, TRUE); + + // Create a new Factory Muffin instance + $fm = new FactoryMuffin(); + + // Load all of the model definitions + $fm->loadFactories($factoriesPath); + + // Set the locale. Could be the config one, but for testing English should do + Faker::setLocale('en_EN'); + + return $fm; + }; + + /** + * Builds search paths for locales in all Sprinkles. + */ + $container['localePathBuilder'] = function ($c) { + $config = $c->config; + + // Make sure the locale config is a valid string + if (!is_string($config['site.locales.default']) || $config['site.locales.default'] == '') { + throw new \UnexpectedValueException('The locale config is not a valid string.'); + } + + // Load the base locale file(s) as specified in the configuration + $locales = explode(',', $config['site.locales.default']); + + return new LocalePathBuilder($c->locator, 'locale://', $locales); + }; + + /** + * Mail service. + */ + $container['mailer'] = function ($c) { + $mailer = new Mailer($c->mailLogger, $c->config['mail']); + + // Use UF debug settings to override any service-specific log settings. + if (!$c->config['debug.smtp']) { + $mailer->getPhpMailer()->SMTPDebug = 0; + } + + return $mailer; + }; + + /** + * Mail logging service. + * + * PHPMailer will use this to log SMTP activity. + * Extend this service to push additional handlers onto the 'mail' log stack. + */ + $container['mailLogger'] = function ($c) { + $log = new Logger('mail'); + + $logFile = $c->locator->findResource('log://userfrosting.log', TRUE, TRUE); + + $handler = new StreamHandler($logFile); + $formatter = new LineFormatter(NULL, NULL, TRUE); + + $handler->setFormatter($formatter); + $log->pushHandler($handler); + + return $log; + }; + + /** + * Error-handler for 404 errors. Notice that we manually create a UserFrosting NotFoundException, + * and a NotFoundExceptionHandler. This lets us pass through to the UF error handling system. + */ + $container['notFoundHandler'] = function ($c) { + return function ($request, $response) use ($c) { + $exception = new NotFoundException; + $handler = new NotFoundExceptionHandler($c, $request, $response, $exception, $c->settings['displayErrorDetails']); + return $handler->handle(); + }; + }; + + /** + * Error-handler for PHP runtime errors. Notice that we just pass this through to our general-purpose + * error-handling service. + */ + $container['phpErrorHandler'] = function ($c) { + return $c->errorHandler; + }; + + /** + * Laravel query logging with Monolog. + * + * Extend this service to push additional handlers onto the 'query' log stack. + */ + $container['queryLogger'] = function ($c) { + $logger = new Logger('query'); + + $logFile = $c->locator->findResource('log://userfrosting.log', TRUE, TRUE); + + $handler = new StreamHandler($logFile); + + $formatter = new MixedFormatter(NULL, NULL, TRUE); + + $handler->setFormatter($formatter); + $logger->pushHandler($handler); + + return $logger; + }; + + /** + * Override Slim's default router with the UF router. + */ + $container['router'] = function ($c) { + $routerCacheFile = FALSE; + if (isset($c->config['settings.routerCacheFile'])) { + $routerCacheFile = $c->config['settings.routerCacheFile']; + } + + return (new Router)->setCacheFile($routerCacheFile); + }; + + /** + * Start the PHP session, with the name and parameters specified in the configuration file. + */ + $container['session'] = function ($c) { + $config = $c->config; + + // Create appropriate handler based on config + if ($config['session.handler'] == 'file') { + $fs = new FileSystem; + $handler = new FileSessionHandler($fs, $c->locator->findResource('session://'), $config['session.minutes']); + } else if ($config['session.handler'] == 'database') { + $connection = $c->db->connection(); + // Table must exist, otherwise an exception will be thrown + $handler = new DatabaseSessionHandler($connection, $config['session.database.table'], $config['session.minutes']); + } else { + throw new \Exception("Bad session handler type '{$config['session.handler']}' specified in configuration file."); + } + + // Create, start and return a new wrapper for $_SESSION + $session = new Session($handler, $config['session']); + $session->start(); + + return $session; + }; + + /** + * Request throttler. + * + * Throttles (rate-limits) requests of a predefined type, with rules defined in site config. + */ + $container['throttler'] = function ($c) { + $throttler = new Throttler($c->classMapper); + + $config = $c->config; + + if ($config->has('throttles') && ($config['throttles'] !== NULL)) { + foreach ($config['throttles'] as $type => $rule) { + if ($rule) { + $throttleRule = new ThrottleRule($rule['method'], $rule['interval'], $rule['delays']); + $throttler->addThrottleRule($type, $throttleRule); + } else { + $throttler->addThrottleRule($type, NULL); + } + } + } + + return $throttler; + }; + + /** + * Translation service, for translating message tokens. + */ + $container['translator'] = function ($c) { + // Load the translations + $paths = $c->localePathBuilder->buildPaths(); + $loader = new ArrayFileLoader($paths); + + // Create the $translator object + $translator = new MessageTranslator($loader->load()); + + return $translator; + }; + + /** + * Set up Twig as the view, adding template paths for all sprinkles and the Slim Twig extension. + * + * Also adds the UserFrosting core Twig extension, which provides additional functions, filters, global variables, etc. + */ + $container['view'] = function ($c) { + $templatePaths = $c->locator->findResources('templates://', TRUE, TRUE); + + $view = new Twig($templatePaths); + + $loader = $view->getLoader(); + + $sprinkles = $c->sprinkleManager->getSprinkleNames(); + + // Add Sprinkles' templates namespaces + foreach ($sprinkles as $sprinkle) { + $path = \UserFrosting\SPRINKLES_DIR . \UserFrosting\DS . + $sprinkle . \UserFrosting\DS . + \UserFrosting\TEMPLATE_DIR_NAME . \UserFrosting\DS; + + if (is_dir($path)) { + $loader->addPath($path, $sprinkle); + } + } + + $twig = $view->getEnvironment(); + + if ($c->config['cache.twig']) { + $twig->setCache($c->locator->findResource('cache://twig', TRUE, TRUE)); + } + + if ($c->config['debug.twig']) { + $twig->enableDebug(); + $view->addExtension(new \Twig_Extension_Debug()); + } + + // Register the Slim extension with Twig + $slimExtension = new TwigExtension( + $c->router, + $c->request->getUri() + ); + $view->addExtension($slimExtension); + + // Register the core UF extension with Twig + $coreExtension = new CoreExtension($c); + $view->addExtension($coreExtension); + + return $view; + }; + } +} diff --git a/main/app/sprinkles/core/src/Sprunje/Sprunje.php b/main/app/sprinkles/core/src/Sprunje/Sprunje.php index ea066a3..b81d266 100644 --- a/main/app/sprinkles/core/src/Sprunje/Sprunje.php +++ b/main/app/sprinkles/core/src/Sprunje/Sprunje.php @@ -1,547 +1,547 @@ - [], - 'filters' => [], - 'lists' => [], - 'size' => 'all', - 'page' => NULL, - 'format' => 'json' - ]; - - /** - * Fields to allow filtering upon. - * - * @var array[string] - */ - protected $filterable = []; - - /** - * Fields to allow listing (enumeration) upon. - * - * @var array[string] - */ - protected $listable = []; - - /** - * Fields to allow sorting upon. - * - * @var array[string] - */ - protected $sortable = []; - - /** - * List of fields to exclude when processing an "_all" filter. - * - * @var array[string] - */ - protected $excludeForAll = []; - - /** - * Separator to use when splitting filter values to treat them as ORs. - * - * @var string - */ - protected $orSeparator = '||'; - - /** - * Array key for the total unfiltered object count. - * - * @var string - */ - protected $countKey = 'count'; - - /** - * Array key for the filtered object count. - * - * @var string - */ - protected $countFilteredKey = 'count_filtered'; - - /** - * Array key for the actual result set. - * - * @var string - */ - protected $rowsKey = 'rows'; - - /** - * Array key for the list of enumerated columns and their enumerations. - * - * @var string - */ - protected $listableKey = 'listable'; - - /** - * Constructor. - * - * @param ClassMapper $classMapper - * @param mixed[] $options - */ - public function __construct(ClassMapper $classMapper, array $options) { - $this->classMapper = $classMapper; - - // Validation on input data - $v = new Validator($options); - $v->rule('array', ['sorts', 'filters', 'lists']); - $v->rule('regex', 'sorts.*', '/asc|desc/i'); - $v->rule('regex', 'size', '/all|[0-9]+/i'); - $v->rule('integer', 'page'); - $v->rule('regex', 'format', '/json|csv/i'); - - // translated rules - if (!$v->validate()) { - $e = new BadRequestException(); - foreach ($v->errors() as $idx => $field) { - foreach ($field as $eidx => $error) { - $e->addUserMessage($error); - } - } - throw $e; - } - - $this->options = array_replace_recursive($this->options, $options); - - $this->query = $this->baseQuery(); - - // Start a new query on any Model instances - if (is_a($this->baseQuery(), '\Illuminate\Database\Eloquent\Model')) { - $this->query = $this->baseQuery()->newQuery(); - } - } - - /** - * Extend the query by providing a callback. - * - * @param callable $callback A callback which accepts and returns a Builder instance. - * @return $this - */ - public function extendQuery(callable $callback) { - $this->query = $callback($this->query); - return $this; - } - - /** - * Execute the query and build the results, and append them in the appropriate format to the response. - * - * @param ResponseInterface $response - * @return ResponseInterface - */ - public function toResponse(Response $response) { - $format = $this->options['format']; - - if ($format == 'csv') { - $result = $this->getCsv(); - - // Prepare response - $settings = http_build_query($this->options); - $date = Carbon::now()->format('Ymd'); - $response = $response->withAddedHeader('Content-Disposition', "attachment;filename=$date-{$this->name}-$settings.csv"); - $response = $response->withAddedHeader('Content-Type', 'text/csv; charset=utf-8'); - return $response->write($result); - // Default to JSON - } else { - $result = $this->getArray(); - return $response->withJson($result, 200, JSON_PRETTY_PRINT); - } - } - - /** - * Executes the sprunje query, applying all sorts, filters, and pagination. - * - * Returns an array containing `count` (the total number of rows, before filtering), `count_filtered` (the total number of rows after filtering), - * and `rows` (the filtered result set). - * @return mixed[] - */ - public function getArray() { - list($count, $countFiltered, $rows) = $this->getModels(); - - // Return sprunjed results - return [ - $this->countKey => $count, - $this->countFilteredKey => $countFiltered, - $this->rowsKey => $rows->values()->toArray(), - $this->listableKey => $this->getListable() - ]; - } - - /** - * Run the query and build a CSV object by flattening the resulting collection. Ignores any pagination. - * - * @return SplTempFileObject - */ - public function getCsv() { - $filteredQuery = clone $this->query; - - // Apply filters - $this->applyFilters($filteredQuery); - - // Apply sorts - $this->applySorts($filteredQuery); - - $collection = collect($filteredQuery->get()); - - // Perform any additional transformations on the dataset - $this->applyTransformations($collection); - - $csv = Writer::createFromFileObject(new \SplTempFileObject()); - - $columnNames = []; - - // Flatten collection while simultaneously building the column names from the union of each element's keys - $collection->transform(function ($item, $key) use (&$columnNames) { - $item = array_dot($item->toArray()); - foreach ($item as $itemKey => $itemValue) { - if (!in_array($itemKey, $columnNames)) { - $columnNames[] = $itemKey; - } - } - return $item; - }); - - $csv->insertOne($columnNames); - - // Insert the data as rows in the CSV document - $collection->each(function ($item) use ($csv, $columnNames) { - $row = []; - foreach ($columnNames as $itemKey) { - // Only add the value if it is set and not an array. Laravel's array_dot sometimes creates empty child arrays :( - // See https://github.com/laravel/framework/pull/13009 - if (isset($item[$itemKey]) && !is_array($item[$itemKey])) { - $row[] = $item[$itemKey]; - } else { - $row[] = ''; - } - } - - $csv->insertOne($row); - }); - - return $csv; - } - - /** - * Executes the sprunje query, applying all sorts, filters, and pagination. - * - * Returns the filtered, paginated result set and the counts. - * @return mixed[] - */ - public function getModels() { - // Count unfiltered total - $count = $this->count($this->query); - - // Clone the Query\Builder, Eloquent\Builder, or Relation - $filteredQuery = clone $this->query; - - // Apply filters - $this->applyFilters($filteredQuery); - - // Count filtered total - $countFiltered = $this->countFiltered($filteredQuery); - - // Apply sorts - $this->applySorts($filteredQuery); - - // Paginate - $this->applyPagination($filteredQuery); - - $collection = collect($filteredQuery->get()); - - // Perform any additional transformations on the dataset - $this->applyTransformations($collection); - - return [$count, $countFiltered, $collection]; - } - - /** - * Get lists of values for specified fields in 'lists' option, calling a custom lister callback when appropriate. - * - * @return array - */ - public function getListable() { - $result = []; - foreach ($this->listable as $name) { - - // Determine if a custom filter method has been defined - $methodName = 'list' . studly_case($name); - - if (method_exists($this, $methodName)) { - $result[$name] = $this->$methodName(); - } else { - $result[$name] = $this->getColumnValues($name); - } - } - - return $result; - } - - /** - * Get the underlying queriable object in its current state. - * - * @return Builder - */ - public function getQuery() { - return $this->query; - } - - /** - * Set the underlying QueryBuilder object. - * - * @param Builder $query - * @return $this - */ - public function setQuery($query) { - $this->query = $query; - return $this; - } - - /** - * Apply any filters from the options, calling a custom filter callback when appropriate. - * - * @param Builder $query - * @return $this - */ - public function applyFilters($query) { - foreach ($this->options['filters'] as $name => $value) { - // Check that this filter is allowed - if (($name != '_all') && !in_array($name, $this->filterable)) { - $e = new BadRequestException(); - $e->addUserMessage('VALIDATE.SPRUNJE.BAD_FILTER', ['name' => $name]); - throw $e; - } - // Since we want to match _all_ of the fields, we wrap the field callback in a 'where' callback - $query->where(function ($fieldQuery) use ($name, $value) { - $this->buildFilterQuery($fieldQuery, $name, $value); - }); - } - - return $this; - } - - /** - * Apply any sorts from the options, calling a custom sorter callback when appropriate. - * - * @param Builder $query - * @return $this - */ - public function applySorts($query) { - foreach ($this->options['sorts'] as $name => $direction) { - // Check that this sort is allowed - if (!in_array($name, $this->sortable)) { - $e = new BadRequestException(); - $e->addUserMessage('VALIDATE.SPRUNJE.BAD_SORT', ['name' => $name]); - throw $e; - } - - // Determine if a custom sort method has been defined - $methodName = 'sort' . studly_case($name); - - if (method_exists($this, $methodName)) { - $this->$methodName($query, $direction); - } else { - $query->orderBy($name, $direction); - } - } - - return $this; - } - - /** - * Apply pagination based on the `page` and `size` options. - * - * @param Builder $query - * @return $this - */ - public function applyPagination($query) { - if ( - ($this->options['page'] !== NULL) && - ($this->options['size'] !== NULL) && - ($this->options['size'] != 'all') - ) { - $offset = $this->options['size'] * $this->options['page']; - $query->skip($offset) - ->take($this->options['size']); - } - - return $this; - } - - /** - * Match any filter in `filterable`. - * - * @param Builder $query - * @param mixed $value - * @return $this - */ - protected function filterAll($query, $value) { - foreach ($this->filterable as $name) { - if (studly_case($name) != 'all' && !in_array($name, $this->excludeForAll)) { - // Since we want to match _any_ of the fields, we wrap the field callback in a 'orWhere' callback - $query->orWhere(function ($fieldQuery) use ($name, $value) { - $this->buildFilterQuery($fieldQuery, $name, $value); - }); - } - } - - return $this; - } - - /** - * Build the filter query for a single field. - * - * @param Builder $query - * @param string $name - * @param mixed $value - * @return $this - */ - protected function buildFilterQuery($query, $name, $value) { - $methodName = 'filter' . studly_case($name); - - // Determine if a custom filter method has been defined - if (method_exists($this, $methodName)) { - $this->$methodName($query, $value); - } else { - $this->buildFilterDefaultFieldQuery($query, $name, $value); - } - - return $this; - } - - /** - * Perform a 'like' query on a single field, separating the value string on the or separator and - * matching any of the supplied values. - * - * @param Builder $query - * @param string $name - * @param mixed $value - * @return $this - */ - protected function buildFilterDefaultFieldQuery($query, $name, $value) { - // Default filter - split value on separator for OR queries - // and search by column name - $values = explode($this->orSeparator, $value); - foreach ($values as $value) { - $query->orLike($name, $value); - } - - return $this; - } - - /** - * Set any transformations you wish to apply to the collection, after the query is executed. - * - * @param \Illuminate\Database\Eloquent\Collection $collection - * @return \Illuminate\Database\Eloquent\Collection - */ - protected function applyTransformations($collection) { - return $collection; - } - - /** - * Set the initial query used by your Sprunje. - * - * @return Builder|Relation|Model - */ - abstract protected function baseQuery(); - - /** - * Returns a list of distinct values for a specified column. - * Formats results to have a "value" and "text" attribute. - * - * @param string $column - * @return array - */ - protected function getColumnValues($column) { - $rawValues = $this->query->select($column)->distinct()->orderBy($column, 'asc')->get(); - $values = []; - foreach ($rawValues as $raw) { - $values[] = [ - 'value' => $raw[$column], - 'text' => $raw[$column] - ]; - } - return $values; - } - - /** - * Get the unpaginated count of items (before filtering) in this query. - * - * @param Builder $query - * @return int - */ - protected function count($query) { - return $query->count(); - } - - /** - * Get the unpaginated count of items (after filtering) in this query. - * - * @param Builder $query - * @return int - */ - protected function countFiltered($query) { - return $query->count(); - } - - /** - * Executes the sprunje query, applying all sorts, filters, and pagination. - * - * Returns an array containing `count` (the total number of rows, before filtering), `count_filtered` (the total number of rows after filtering), - * and `rows` (the filtered result set). - * @deprecated since 4.1.7 Use getArray() instead. - * @return mixed[] - */ - public function getResults() { - return $this->getArray(); - } -} + [], + 'filters' => [], + 'lists' => [], + 'size' => 'all', + 'page' => NULL, + 'format' => 'json' + ]; + + /** + * Fields to allow filtering upon. + * + * @var array[string] + */ + protected $filterable = []; + + /** + * Fields to allow listing (enumeration) upon. + * + * @var array[string] + */ + protected $listable = []; + + /** + * Fields to allow sorting upon. + * + * @var array[string] + */ + protected $sortable = []; + + /** + * List of fields to exclude when processing an "_all" filter. + * + * @var array[string] + */ + protected $excludeForAll = []; + + /** + * Separator to use when splitting filter values to treat them as ORs. + * + * @var string + */ + protected $orSeparator = '||'; + + /** + * Array key for the total unfiltered object count. + * + * @var string + */ + protected $countKey = 'count'; + + /** + * Array key for the filtered object count. + * + * @var string + */ + protected $countFilteredKey = 'count_filtered'; + + /** + * Array key for the actual result set. + * + * @var string + */ + protected $rowsKey = 'rows'; + + /** + * Array key for the list of enumerated columns and their enumerations. + * + * @var string + */ + protected $listableKey = 'listable'; + + /** + * Constructor. + * + * @param ClassMapper $classMapper + * @param mixed[] $options + */ + public function __construct(ClassMapper $classMapper, array $options) { + $this->classMapper = $classMapper; + + // Validation on input data + $v = new Validator($options); + $v->rule('array', ['sorts', 'filters', 'lists']); + $v->rule('regex', 'sorts.*', '/asc|desc/i'); + $v->rule('regex', 'size', '/all|[0-9]+/i'); + $v->rule('integer', 'page'); + $v->rule('regex', 'format', '/json|csv/i'); + + // translated rules + if (!$v->validate()) { + $e = new BadRequestException(); + foreach ($v->errors() as $idx => $field) { + foreach ($field as $eidx => $error) { + $e->addUserMessage($error); + } + } + throw $e; + } + + $this->options = array_replace_recursive($this->options, $options); + + $this->query = $this->baseQuery(); + + // Start a new query on any Model instances + if (is_a($this->baseQuery(), '\Illuminate\Database\Eloquent\Model')) { + $this->query = $this->baseQuery()->newQuery(); + } + } + + /** + * Extend the query by providing a callback. + * + * @param callable $callback A callback which accepts and returns a Builder instance. + * @return $this + */ + public function extendQuery(callable $callback) { + $this->query = $callback($this->query); + return $this; + } + + /** + * Execute the query and build the results, and append them in the appropriate format to the response. + * + * @param ResponseInterface $response + * @return ResponseInterface + */ + public function toResponse(Response $response) { + $format = $this->options['format']; + + if ($format == 'csv') { + $result = $this->getCsv(); + + // Prepare response + $settings = http_build_query($this->options); + $date = Carbon::now()->format('Ymd'); + $response = $response->withAddedHeader('Content-Disposition', "attachment;filename=$date-{$this->name}-$settings.csv"); + $response = $response->withAddedHeader('Content-Type', 'text/csv; charset=utf-8'); + return $response->write($result); + // Default to JSON + } else { + $result = $this->getArray(); + return $response->withJson($result, 200, JSON_PRETTY_PRINT); + } + } + + /** + * Executes the sprunje query, applying all sorts, filters, and pagination. + * + * Returns an array containing `count` (the total number of rows, before filtering), `count_filtered` (the total number of rows after filtering), + * and `rows` (the filtered result set). + * @return mixed[] + */ + public function getArray() { + list($count, $countFiltered, $rows) = $this->getModels(); + + // Return sprunjed results + return [ + $this->countKey => $count, + $this->countFilteredKey => $countFiltered, + $this->rowsKey => $rows->values()->toArray(), + $this->listableKey => $this->getListable() + ]; + } + + /** + * Run the query and build a CSV object by flattening the resulting collection. Ignores any pagination. + * + * @return SplTempFileObject + */ + public function getCsv() { + $filteredQuery = clone $this->query; + + // Apply filters + $this->applyFilters($filteredQuery); + + // Apply sorts + $this->applySorts($filteredQuery); + + $collection = collect($filteredQuery->get()); + + // Perform any additional transformations on the dataset + $this->applyTransformations($collection); + + $csv = Writer::createFromFileObject(new \SplTempFileObject()); + + $columnNames = []; + + // Flatten collection while simultaneously building the column names from the union of each element's keys + $collection->transform(function ($item, $key) use (&$columnNames) { + $item = array_dot($item->toArray()); + foreach ($item as $itemKey => $itemValue) { + if (!in_array($itemKey, $columnNames)) { + $columnNames[] = $itemKey; + } + } + return $item; + }); + + $csv->insertOne($columnNames); + + // Insert the data as rows in the CSV document + $collection->each(function ($item) use ($csv, $columnNames) { + $row = []; + foreach ($columnNames as $itemKey) { + // Only add the value if it is set and not an array. Laravel's array_dot sometimes creates empty child arrays :( + // See https://github.com/laravel/framework/pull/13009 + if (isset($item[$itemKey]) && !is_array($item[$itemKey])) { + $row[] = $item[$itemKey]; + } else { + $row[] = ''; + } + } + + $csv->insertOne($row); + }); + + return $csv; + } + + /** + * Executes the sprunje query, applying all sorts, filters, and pagination. + * + * Returns the filtered, paginated result set and the counts. + * @return mixed[] + */ + public function getModels() { + // Count unfiltered total + $count = $this->count($this->query); + + // Clone the Query\Builder, Eloquent\Builder, or Relation + $filteredQuery = clone $this->query; + + // Apply filters + $this->applyFilters($filteredQuery); + + // Count filtered total + $countFiltered = $this->countFiltered($filteredQuery); + + // Apply sorts + $this->applySorts($filteredQuery); + + // Paginate + $this->applyPagination($filteredQuery); + + $collection = collect($filteredQuery->get()); + + // Perform any additional transformations on the dataset + $this->applyTransformations($collection); + + return [$count, $countFiltered, $collection]; + } + + /** + * Get lists of values for specified fields in 'lists' option, calling a custom lister callback when appropriate. + * + * @return array + */ + public function getListable() { + $result = []; + foreach ($this->listable as $name) { + + // Determine if a custom filter method has been defined + $methodName = 'list' . studly_case($name); + + if (method_exists($this, $methodName)) { + $result[$name] = $this->$methodName(); + } else { + $result[$name] = $this->getColumnValues($name); + } + } + + return $result; + } + + /** + * Get the underlying queriable object in its current state. + * + * @return Builder + */ + public function getQuery() { + return $this->query; + } + + /** + * Set the underlying QueryBuilder object. + * + * @param Builder $query + * @return $this + */ + public function setQuery($query) { + $this->query = $query; + return $this; + } + + /** + * Apply any filters from the options, calling a custom filter callback when appropriate. + * + * @param Builder $query + * @return $this + */ + public function applyFilters($query) { + foreach ($this->options['filters'] as $name => $value) { + // Check that this filter is allowed + if (($name != '_all') && !in_array($name, $this->filterable)) { + $e = new BadRequestException(); + $e->addUserMessage('VALIDATE.SPRUNJE.BAD_FILTER', ['name' => $name]); + throw $e; + } + // Since we want to match _all_ of the fields, we wrap the field callback in a 'where' callback + $query->where(function ($fieldQuery) use ($name, $value) { + $this->buildFilterQuery($fieldQuery, $name, $value); + }); + } + + return $this; + } + + /** + * Apply any sorts from the options, calling a custom sorter callback when appropriate. + * + * @param Builder $query + * @return $this + */ + public function applySorts($query) { + foreach ($this->options['sorts'] as $name => $direction) { + // Check that this sort is allowed + if (!in_array($name, $this->sortable)) { + $e = new BadRequestException(); + $e->addUserMessage('VALIDATE.SPRUNJE.BAD_SORT', ['name' => $name]); + throw $e; + } + + // Determine if a custom sort method has been defined + $methodName = 'sort' . studly_case($name); + + if (method_exists($this, $methodName)) { + $this->$methodName($query, $direction); + } else { + $query->orderBy($name, $direction); + } + } + + return $this; + } + + /** + * Apply pagination based on the `page` and `size` options. + * + * @param Builder $query + * @return $this + */ + public function applyPagination($query) { + if ( + ($this->options['page'] !== NULL) && + ($this->options['size'] !== NULL) && + ($this->options['size'] != 'all') + ) { + $offset = $this->options['size'] * $this->options['page']; + $query->skip($offset) + ->take($this->options['size']); + } + + return $this; + } + + /** + * Match any filter in `filterable`. + * + * @param Builder $query + * @param mixed $value + * @return $this + */ + protected function filterAll($query, $value) { + foreach ($this->filterable as $name) { + if (studly_case($name) != 'all' && !in_array($name, $this->excludeForAll)) { + // Since we want to match _any_ of the fields, we wrap the field callback in a 'orWhere' callback + $query->orWhere(function ($fieldQuery) use ($name, $value) { + $this->buildFilterQuery($fieldQuery, $name, $value); + }); + } + } + + return $this; + } + + /** + * Build the filter query for a single field. + * + * @param Builder $query + * @param string $name + * @param mixed $value + * @return $this + */ + protected function buildFilterQuery($query, $name, $value) { + $methodName = 'filter' . studly_case($name); + + // Determine if a custom filter method has been defined + if (method_exists($this, $methodName)) { + $this->$methodName($query, $value); + } else { + $this->buildFilterDefaultFieldQuery($query, $name, $value); + } + + return $this; + } + + /** + * Perform a 'like' query on a single field, separating the value string on the or separator and + * matching any of the supplied values. + * + * @param Builder $query + * @param string $name + * @param mixed $value + * @return $this + */ + protected function buildFilterDefaultFieldQuery($query, $name, $value) { + // Default filter - split value on separator for OR queries + // and search by column name + $values = explode($this->orSeparator, $value); + foreach ($values as $value) { + $query->orLike($name, $value); + } + + return $this; + } + + /** + * Set any transformations you wish to apply to the collection, after the query is executed. + * + * @param \Illuminate\Database\Eloquent\Collection $collection + * @return \Illuminate\Database\Eloquent\Collection + */ + protected function applyTransformations($collection) { + return $collection; + } + + /** + * Set the initial query used by your Sprunje. + * + * @return Builder|Relation|Model + */ + abstract protected function baseQuery(); + + /** + * Returns a list of distinct values for a specified column. + * Formats results to have a "value" and "text" attribute. + * + * @param string $column + * @return array + */ + protected function getColumnValues($column) { + $rawValues = $this->query->select($column)->distinct()->orderBy($column, 'asc')->get(); + $values = []; + foreach ($rawValues as $raw) { + $values[] = [ + 'value' => $raw[$column], + 'text' => $raw[$column] + ]; + } + return $values; + } + + /** + * Get the unpaginated count of items (before filtering) in this query. + * + * @param Builder $query + * @return int + */ + protected function count($query) { + return $query->count(); + } + + /** + * Get the unpaginated count of items (after filtering) in this query. + * + * @param Builder $query + * @return int + */ + protected function countFiltered($query) { + return $query->count(); + } + + /** + * Executes the sprunje query, applying all sorts, filters, and pagination. + * + * Returns an array containing `count` (the total number of rows, before filtering), `count_filtered` (the total number of rows after filtering), + * and `rows` (the filtered result set). + * @deprecated since 4.1.7 Use getArray() instead. + * @return mixed[] + */ + public function getResults() { + return $this->getArray(); + } +} diff --git a/main/app/sprinkles/core/src/Throttle/ThrottleRule.php b/main/app/sprinkles/core/src/Throttle/ThrottleRule.php index c5e0c82..5840027 100644 --- a/main/app/sprinkles/core/src/Throttle/ThrottleRule.php +++ b/main/app/sprinkles/core/src/Throttle/ThrottleRule.php @@ -1,133 +1,133 @@ -setMethod($method); - $this->setInterval($interval); - $this->setDelays($delays); - } - - /** - * Get the current delay on this rule for a particular number of event counts. - * - * @param Carbon\Carbon $lastEventTime The timestamp for the last countable event. - * @param int $count The total number of events which have occurred in an interval. - */ - public function getDelay($lastEventTime, $count) { - // Zero occurrences always maps to a delay of 0 seconds. - if ($count == 0) { - return 0; - } - - foreach ($this->delays as $observations => $delay) { - // Skip any delay rules for which we haven't met the requisite number of observations - if ($count < $observations) { - continue; - } - - // If this rule meets the observed number of events, and violates the required delay, then return the remaining time left - if ($lastEventTime->diffInSeconds() < $delay) { - return $lastEventTime->addSeconds($delay)->diffInSeconds(); - } - } - - return 0; - } - - /** - * Gets the current mapping of attempts (int) to delays (seconds). - * - * @return int[] - */ - public function getDelays() { - return $this->delays; - } - - /** - * Gets the current throttling interval (seconds). - * - * @return int - */ - public function getInterval() { - return $this->interval; - } - - /** - * Gets the current throttling method ('ip' or 'data'). - * - * @return string - */ - public function getMethod() { - return $this->method; - } - - /** - * Sets the current mapping of attempts (int) to delays (seconds). - * - * @param int[] A mapping of minimum observation counts (x) to delays (y), in seconds. - */ - public function setDelays($delays) { - // Sort the array by key, from highest to lowest value - $this->delays = $delays; - krsort($this->delays); - - return $this; - } - - /** - * Sets the current throttling interval (seconds). - * - * @param int The amount of time, in seconds, to look back in determining attempts to consider. - */ - public function setInterval($interval) { - $this->interval = $interval; - - return $this; - } - - /** - * Sets the current throttling method ('ip' or 'data'). - * - * @param string Set to 'ip' for ip-based throttling, 'data' for request-data-based throttling. - */ - public function setMethod($method) { - $this->method = $method; - - return $this; - } -} +setMethod($method); + $this->setInterval($interval); + $this->setDelays($delays); + } + + /** + * Get the current delay on this rule for a particular number of event counts. + * + * @param Carbon\Carbon $lastEventTime The timestamp for the last countable event. + * @param int $count The total number of events which have occurred in an interval. + */ + public function getDelay($lastEventTime, $count) { + // Zero occurrences always maps to a delay of 0 seconds. + if ($count == 0) { + return 0; + } + + foreach ($this->delays as $observations => $delay) { + // Skip any delay rules for which we haven't met the requisite number of observations + if ($count < $observations) { + continue; + } + + // If this rule meets the observed number of events, and violates the required delay, then return the remaining time left + if ($lastEventTime->diffInSeconds() < $delay) { + return $lastEventTime->addSeconds($delay)->diffInSeconds(); + } + } + + return 0; + } + + /** + * Gets the current mapping of attempts (int) to delays (seconds). + * + * @return int[] + */ + public function getDelays() { + return $this->delays; + } + + /** + * Gets the current throttling interval (seconds). + * + * @return int + */ + public function getInterval() { + return $this->interval; + } + + /** + * Gets the current throttling method ('ip' or 'data'). + * + * @return string + */ + public function getMethod() { + return $this->method; + } + + /** + * Sets the current mapping of attempts (int) to delays (seconds). + * + * @param int[] A mapping of minimum observation counts (x) to delays (y), in seconds. + */ + public function setDelays($delays) { + // Sort the array by key, from highest to lowest value + $this->delays = $delays; + krsort($this->delays); + + return $this; + } + + /** + * Sets the current throttling interval (seconds). + * + * @param int The amount of time, in seconds, to look back in determining attempts to consider. + */ + public function setInterval($interval) { + $this->interval = $interval; + + return $this; + } + + /** + * Sets the current throttling method ('ip' or 'data'). + * + * @param string Set to 'ip' for ip-based throttling, 'data' for request-data-based throttling. + */ + public function setMethod($method) { + $this->method = $method; + + return $this; + } +} diff --git a/main/app/sprinkles/core/src/Throttle/Throttler.php b/main/app/sprinkles/core/src/Throttle/Throttler.php index 4ab9dd6..f7d1cc7 100644 --- a/main/app/sprinkles/core/src/Throttle/Throttler.php +++ b/main/app/sprinkles/core/src/Throttle/Throttler.php @@ -1,172 +1,172 @@ -classMapper = $classMapper; - $this->throttleRules = []; - } - - /** - * Add a throttling rule for a particular throttle event type. - * - * @param string $type The type of throttle event to check against. - * @param ThrottleRule $rule The rule to use when throttling this type of event. - */ - public function addThrottleRule($type, $rule) { - if (!($rule instanceof ThrottleRule || ($rule === NULL))) { - throw new ThrottlerException('$rule must be of type ThrottleRule (or null).'); - } - - $this->throttleRules[$type] = $rule; - - return $this; - } - - /** - * Check the current request against a specified throttle rule. - * - * @param string $type The type of throttle event to check against. - * @param mixed[] $requestData Any additional request parameters to use in checking the throttle. - * @return bool - */ - public function getDelay($type, $requestData = []) { - $throttleRule = $this->getRule($type); - - if (is_null($throttleRule)) { - return 0; - } - - // Get earliest time to start looking for throttleable events - $startTime = Carbon::now() - ->subSeconds($throttleRule->getInterval()); - - // Fetch all throttle events of the specified type, that match the specified rule - if ($throttleRule->getMethod() == 'ip') { - $events = $this->classMapper->staticMethod('throttle', 'where', 'type', $type) - ->where('created_at', '>', $startTime) - ->where('ip', $_SERVER['REMOTE_ADDR']) - ->get(); - } else { - $events = $this->classMapper->staticMethod('throttle', 'where', 'type', $type) - ->where('created_at', '>', $startTime) - ->get(); - - // Filter out only events that match the required JSON data - $events = $events->filter(function ($item, $key) use ($requestData) { - $data = json_decode($item->request_data); - - // If a field is not specified in the logged data, or it doesn't match the value we're searching for, - // then filter out this event from the collection. - foreach ($requestData as $name => $value) { - if (!isset($data->$name) || ($data->$name != $value)) { - return FALSE; - } - } - - return TRUE; - }); - } - - // Check the collection of events against the specified throttle rule. - return $this->computeDelay($events, $throttleRule); - } - - /** - * Get a registered rule of a particular type. - * - * @param string $type - * @throws ThrottlerException - * @return ThrottleRule[] - */ - public function getRule($type) { - if (!array_key_exists($type, $this->throttleRules)) { - throw new ThrottlerException("The throttling rule for '$type' could not be found."); - } - - return $this->throttleRules[$type]; - } - - /** - * Get the current throttling rules. - * - * @return ThrottleRule[] - */ - public function getThrottleRules() { - return $this->throttleRules; - } - - /** - * Log a throttleable event to the database. - * - * @param string $type the type of event - * @param string[] $requestData an array of field names => values that are relevant to throttling for this event (e.g. username, email, etc). - */ - public function logEvent($type, $requestData = []) { - // Just a check to make sure the rule exists - $throttleRule = $this->getRule($type); - - if (is_null($throttleRule)) { - return $this; - } - - $event = $this->classMapper->createInstance('throttle', [ - 'type' => $type, - 'ip' => $_SERVER['REMOTE_ADDR'], - 'request_data' => json_encode($requestData) - ]); - - $event->save(); - - return $this; - } - - /** - * Returns the current delay for a specified throttle rule. - * - * @param Throttle[] $events a Collection of throttle events. - * @param ThrottleRule $throttleRule a rule representing the strategy to use for throttling a particular type of event. - * @return int seconds remaining until a particular event is permitted to be attempted again. - */ - protected function computeDelay($events, $throttleRule) { - // If no matching events found, then there is no delay - if (!$events->count()) { - return 0; - } - - // Great, now we compare our delay against the most recent attempt - $lastEvent = $events->last(); - return $throttleRule->getDelay($lastEvent->created_at, $events->count()); - } -} +classMapper = $classMapper; + $this->throttleRules = []; + } + + /** + * Add a throttling rule for a particular throttle event type. + * + * @param string $type The type of throttle event to check against. + * @param ThrottleRule $rule The rule to use when throttling this type of event. + */ + public function addThrottleRule($type, $rule) { + if (!($rule instanceof ThrottleRule || ($rule === NULL))) { + throw new ThrottlerException('$rule must be of type ThrottleRule (or null).'); + } + + $this->throttleRules[$type] = $rule; + + return $this; + } + + /** + * Check the current request against a specified throttle rule. + * + * @param string $type The type of throttle event to check against. + * @param mixed[] $requestData Any additional request parameters to use in checking the throttle. + * @return bool + */ + public function getDelay($type, $requestData = []) { + $throttleRule = $this->getRule($type); + + if (is_null($throttleRule)) { + return 0; + } + + // Get earliest time to start looking for throttleable events + $startTime = Carbon::now() + ->subSeconds($throttleRule->getInterval()); + + // Fetch all throttle events of the specified type, that match the specified rule + if ($throttleRule->getMethod() == 'ip') { + $events = $this->classMapper->staticMethod('throttle', 'where', 'type', $type) + ->where('created_at', '>', $startTime) + ->where('ip', $_SERVER['REMOTE_ADDR']) + ->get(); + } else { + $events = $this->classMapper->staticMethod('throttle', 'where', 'type', $type) + ->where('created_at', '>', $startTime) + ->get(); + + // Filter out only events that match the required JSON data + $events = $events->filter(function ($item, $key) use ($requestData) { + $data = json_decode($item->request_data); + + // If a field is not specified in the logged data, or it doesn't match the value we're searching for, + // then filter out this event from the collection. + foreach ($requestData as $name => $value) { + if (!isset($data->$name) || ($data->$name != $value)) { + return FALSE; + } + } + + return TRUE; + }); + } + + // Check the collection of events against the specified throttle rule. + return $this->computeDelay($events, $throttleRule); + } + + /** + * Get a registered rule of a particular type. + * + * @param string $type + * @throws ThrottlerException + * @return ThrottleRule[] + */ + public function getRule($type) { + if (!array_key_exists($type, $this->throttleRules)) { + throw new ThrottlerException("The throttling rule for '$type' could not be found."); + } + + return $this->throttleRules[$type]; + } + + /** + * Get the current throttling rules. + * + * @return ThrottleRule[] + */ + public function getThrottleRules() { + return $this->throttleRules; + } + + /** + * Log a throttleable event to the database. + * + * @param string $type the type of event + * @param string[] $requestData an array of field names => values that are relevant to throttling for this event (e.g. username, email, etc). + */ + public function logEvent($type, $requestData = []) { + // Just a check to make sure the rule exists + $throttleRule = $this->getRule($type); + + if (is_null($throttleRule)) { + return $this; + } + + $event = $this->classMapper->createInstance('throttle', [ + 'type' => $type, + 'ip' => $_SERVER['REMOTE_ADDR'], + 'request_data' => json_encode($requestData) + ]); + + $event->save(); + + return $this; + } + + /** + * Returns the current delay for a specified throttle rule. + * + * @param Throttle[] $events a Collection of throttle events. + * @param ThrottleRule $throttleRule a rule representing the strategy to use for throttling a particular type of event. + * @return int seconds remaining until a particular event is permitted to be attempted again. + */ + protected function computeDelay($events, $throttleRule) { + // If no matching events found, then there is no delay + if (!$events->count()) { + return 0; + } + + // Great, now we compare our delay against the most recent attempt + $lastEvent = $events->last(); + return $throttleRule->getDelay($lastEvent->created_at, $events->count()); + } +} diff --git a/main/app/sprinkles/core/src/Throttle/ThrottlerException.php b/main/app/sprinkles/core/src/Throttle/ThrottlerException.php index 08f2919..af29bc8 100644 --- a/main/app/sprinkles/core/src/Throttle/ThrottlerException.php +++ b/main/app/sprinkles/core/src/Throttle/ThrottlerException.php @@ -1,19 +1,19 @@ -ci = $ci; - } - - /** - * Function that delete the Twig cache directory content - * - * @access public - * @return bool true/false if operation is successfull - */ - public function clearCache() { - // Get location - $path = $this->ci->locator->findResource('cache://twig', TRUE, TRUE); - - // Get Filesystem instance - $fs = new FileSystem; - - // Make sure directory exist and delete it - if ($fs->exists($path)) { - return $fs->deleteDirectory($path, TRUE); - } - - // It's still considered a success if directory doesn't exist yet - return TRUE; - } -} +ci = $ci; + } + + /** + * Function that delete the Twig cache directory content + * + * @access public + * @return bool true/false if operation is successfull + */ + public function clearCache() { + // Get location + $path = $this->ci->locator->findResource('cache://twig', TRUE, TRUE); + + // Get Filesystem instance + $fs = new FileSystem; + + // Make sure directory exist and delete it + if ($fs->exists($path)) { + return $fs->deleteDirectory($path, TRUE); + } + + // It's still considered a success if directory doesn't exist yet + return TRUE; + } +} diff --git a/main/app/sprinkles/core/src/Twig/CoreExtension.php b/main/app/sprinkles/core/src/Twig/CoreExtension.php index 2837e84..fccd542 100644 --- a/main/app/sprinkles/core/src/Twig/CoreExtension.php +++ b/main/app/sprinkles/core/src/Twig/CoreExtension.php @@ -1,120 +1,120 @@ -services = $services; - } - - /** - * Get the name of this extension. - * - * @return string - */ - public function getName() { - return 'userfrosting/core'; - } - - /** - * Adds Twig functions `getAlerts` and `translate`. - * - * @return array[\Twig_SimpleFunction] - */ - public function getFunctions() { - return array( - // Add Twig function for fetching alerts - new \Twig_SimpleFunction('getAlerts', function ($clear = TRUE) { - if ($clear) { - return $this->services['alerts']->getAndClearMessages(); - } else { - return $this->services['alerts']->messages(); - } - }), - new \Twig_SimpleFunction('translate', function ($hook, $params = array()) { - return $this->services['translator']->translate($hook, $params); - }, [ - 'is_safe' => ['html'] - ]) - ); - } - - /** - * Adds Twig filters `unescape`. - * - * @return array[\Twig_SimpleFilter] - */ - public function getFilters() { - return array( - /** - * Converts phone numbers to a standard format. - * - * @param String $num A unformatted phone number - * @return String Returns the formatted phone number - */ - new \Twig_SimpleFilter('phone', function ($num) { - return Util::formatPhoneNumber($num); - }), - new \Twig_SimpleFilter('unescape', function ($string) { - return html_entity_decode($string); - }) - ); - } - - /** - * Adds Twig global variables `site` and `assets`. - * - * @return array[mixed] - */ - public function getGlobals() { - // CSRF token name and value - $csrfNameKey = $this->services->csrf->getTokenNameKey(); - $csrfValueKey = $this->services->csrf->getTokenValueKey(); - $csrfName = $this->services->csrf->getTokenName(); - $csrfValue = $this->services->csrf->getTokenValue(); - - $csrf = [ - 'csrf' => [ - 'keys' => [ - 'name' => $csrfNameKey, - 'value' => $csrfValueKey - ], - 'name' => $csrfName, - 'value' => $csrfValue - ] - ]; - - $site = array_replace_recursive($this->services->config['site'], $csrf); - - return [ - 'site' => $site, - 'assets' => $this->services->assets - ]; - } -} +services = $services; + } + + /** + * Get the name of this extension. + * + * @return string + */ + public function getName() { + return 'userfrosting/core'; + } + + /** + * Adds Twig functions `getAlerts` and `translate`. + * + * @return array[\Twig_SimpleFunction] + */ + public function getFunctions() { + return array( + // Add Twig function for fetching alerts + new \Twig_SimpleFunction('getAlerts', function ($clear = TRUE) { + if ($clear) { + return $this->services['alerts']->getAndClearMessages(); + } else { + return $this->services['alerts']->messages(); + } + }), + new \Twig_SimpleFunction('translate', function ($hook, $params = array()) { + return $this->services['translator']->translate($hook, $params); + }, [ + 'is_safe' => ['html'] + ]) + ); + } + + /** + * Adds Twig filters `unescape`. + * + * @return array[\Twig_SimpleFilter] + */ + public function getFilters() { + return array( + /** + * Converts phone numbers to a standard format. + * + * @param String $num A unformatted phone number + * @return String Returns the formatted phone number + */ + new \Twig_SimpleFilter('phone', function ($num) { + return Util::formatPhoneNumber($num); + }), + new \Twig_SimpleFilter('unescape', function ($string) { + return html_entity_decode($string); + }) + ); + } + + /** + * Adds Twig global variables `site` and `assets`. + * + * @return array[mixed] + */ + public function getGlobals() { + // CSRF token name and value + $csrfNameKey = $this->services->csrf->getTokenNameKey(); + $csrfValueKey = $this->services->csrf->getTokenValueKey(); + $csrfName = $this->services->csrf->getTokenName(); + $csrfValue = $this->services->csrf->getTokenValue(); + + $csrf = [ + 'csrf' => [ + 'keys' => [ + 'name' => $csrfNameKey, + 'value' => $csrfValueKey + ], + 'name' => $csrfName, + 'value' => $csrfValue + ] + ]; + + $site = array_replace_recursive($this->services->config['site'], $csrf); + + return [ + 'site' => $site, + 'assets' => $this->services->assets + ]; + } +} diff --git a/main/app/sprinkles/core/src/Util/BadClassNameException.php b/main/app/sprinkles/core/src/Util/BadClassNameException.php index 1cd6f4e..1271c44 100644 --- a/main/app/sprinkles/core/src/Util/BadClassNameException.php +++ b/main/app/sprinkles/core/src/Util/BadClassNameException.php @@ -1,19 +1,19 @@ -session = $session; - $this->key = $key; - - if (!$this->session->has($key)) { - $this->session[$key] = array(); - } - } - - /** - * Generates a new captcha for the user registration form. - * - * This generates a random 5-character captcha and stores it in the session with an md5 hash. - * Also, generates the corresponding captcha image. - */ - public function generateRandomCode() { - $md5_hash = md5(rand(0, 99999)); - $this->code = substr($md5_hash, 25, 5); - $enc = md5($this->code); - - // Store the generated captcha value to the session - $this->session[$this->key] = $enc; - - $this->generateImage(); - } - - /** - * Returns the captcha code. - */ - public function getCaptcha() { - return $this->code; - } - - /** - * Returns the captcha image. - */ - public function getImage() { - return $this->image; - } - - /** - * Check that the specified code, when hashed, matches the code in the session. - * - * Also, stores the specified code in the session with an md5 hash. - * @param string - * @return bool - */ - public function verifyCode($code) { - return (md5($code) == $this->session[$this->key]); - } - - /** - * Generate the image for the current captcha. - * - * This generates an image as a binary string. - */ - protected function generateImage() { - $width = 150; - $height = 30; - - $image = imagecreatetruecolor(150, 30); - - //color pallette - $white = imagecolorallocate($image, 255, 255, 255); - $black = imagecolorallocate($image, 0, 0, 0); - $red = imagecolorallocate($image, 255, 0, 0); - $yellow = imagecolorallocate($image, 255, 255, 0); - $dark_grey = imagecolorallocate($image, 64, 64, 64); - $blue = imagecolorallocate($image, 0, 0, 255); - - //create white rectangle - imagefilledrectangle($image, 0, 0, 150, 30, $white); - - //add some lines - for ($i = 0; $i < 2; $i++) { - imageline($image, 0, rand() % 10, 10, rand() % 30, $dark_grey); - imageline($image, 0, rand() % 30, 150, rand() % 30, $red); - imageline($image, 0, rand() % 30, 150, rand() % 30, $yellow); - } - - // RandTab color pallette - $randc[0] = imagecolorallocate($image, 0, 0, 0); - $randc[1] = imagecolorallocate($image, 255, 0, 0); - $randc[2] = imagecolorallocate($image, 255, 255, 0); - $randc[3] = imagecolorallocate($image, 64, 64, 64); - $randc[4] = imagecolorallocate($image, 0, 0, 255); - - //add some dots - for ($i = 0; $i < 1000; $i++) { - imagesetpixel($image, rand() % 200, rand() % 50, $randc[rand() % 5]); - } - - //calculate center of text - $x = (150 - 0 - imagefontwidth(5) * strlen($this->code)) / 2 + 0 + 5; - - //write string twice - imagestring($image, 5, $x, 7, $this->code, $black); - imagestring($image, 5, $x, 7, $this->code, $black); - //start ob - ob_start(); - imagepng($image); - - //get binary image data - $this->image = ob_get_clean(); - - return $this->image; - } -} +session = $session; + $this->key = $key; + + if (!$this->session->has($key)) { + $this->session[$key] = array(); + } + } + + /** + * Generates a new captcha for the user registration form. + * + * This generates a random 5-character captcha and stores it in the session with an md5 hash. + * Also, generates the corresponding captcha image. + */ + public function generateRandomCode() { + $md5_hash = md5(rand(0, 99999)); + $this->code = substr($md5_hash, 25, 5); + $enc = md5($this->code); + + // Store the generated captcha value to the session + $this->session[$this->key] = $enc; + + $this->generateImage(); + } + + /** + * Returns the captcha code. + */ + public function getCaptcha() { + return $this->code; + } + + /** + * Returns the captcha image. + */ + public function getImage() { + return $this->image; + } + + /** + * Check that the specified code, when hashed, matches the code in the session. + * + * Also, stores the specified code in the session with an md5 hash. + * @param string + * @return bool + */ + public function verifyCode($code) { + return (md5($code) == $this->session[$this->key]); + } + + /** + * Generate the image for the current captcha. + * + * This generates an image as a binary string. + */ + protected function generateImage() { + $width = 150; + $height = 30; + + $image = imagecreatetruecolor(150, 30); + + //color pallette + $white = imagecolorallocate($image, 255, 255, 255); + $black = imagecolorallocate($image, 0, 0, 0); + $red = imagecolorallocate($image, 255, 0, 0); + $yellow = imagecolorallocate($image, 255, 255, 0); + $dark_grey = imagecolorallocate($image, 64, 64, 64); + $blue = imagecolorallocate($image, 0, 0, 255); + + //create white rectangle + imagefilledrectangle($image, 0, 0, 150, 30, $white); + + //add some lines + for ($i = 0; $i < 2; $i++) { + imageline($image, 0, rand() % 10, 10, rand() % 30, $dark_grey); + imageline($image, 0, rand() % 30, 150, rand() % 30, $red); + imageline($image, 0, rand() % 30, 150, rand() % 30, $yellow); + } + + // RandTab color pallette + $randc[0] = imagecolorallocate($image, 0, 0, 0); + $randc[1] = imagecolorallocate($image, 255, 0, 0); + $randc[2] = imagecolorallocate($image, 255, 255, 0); + $randc[3] = imagecolorallocate($image, 64, 64, 64); + $randc[4] = imagecolorallocate($image, 0, 0, 255); + + //add some dots + for ($i = 0; $i < 1000; $i++) { + imagesetpixel($image, rand() % 200, rand() % 50, $randc[rand() % 5]); + } + + //calculate center of text + $x = (150 - 0 - imagefontwidth(5) * strlen($this->code)) / 2 + 0 + 5; + + //write string twice + imagestring($image, 5, $x, 7, $this->code, $black); + imagestring($image, 5, $x, 7, $this->code, $black); + //start ob + ob_start(); + imagepng($image); + + //get binary image data + $this->image = ob_get_clean(); + + return $this->image; + } +} diff --git a/main/app/sprinkles/core/src/Util/CheckEnvironment.php b/main/app/sprinkles/core/src/Util/CheckEnvironment.php index 05b555f..b8e5ec8 100644 --- a/main/app/sprinkles/core/src/Util/CheckEnvironment.php +++ b/main/app/sprinkles/core/src/Util/CheckEnvironment.php @@ -1,331 +1,331 @@ -view = $view; - $this->locator = $locator; - $this->cache = $cache; - } - - /** - * Invoke the CheckEnvironment middleware, performing all pre-flight checks and returning an error page if problems were found. - * - * @param \Psr\Http\Message\ServerRequestInterface $request PSR7 request - * @param \Psr\Http\Message\ResponseInterface $response PSR7 response - * @param callable $next Next middleware - * - * @return \Psr\Http\Message\ResponseInterface - */ - public function __invoke($request, $response, $next) { - $problemsFound = FALSE; - - // If production environment and no cached checks, perform environment checks - if ($this->isProduction() && $this->cache->get('checkEnvironment') != 'pass') { - $problemsFound = $this->checkAll(); - - // Cache if checks passed - if (!$problemsFound) { - $this->cache->forever('checkEnvironment', 'pass'); - } - } else if (!$this->isProduction()) { - $problemsFound = $this->checkAll(); - } - - if ($problemsFound) { - $results = array_merge($this->resultsFailed, $this->resultsSuccess); - - $response = $this->view->render($response, 'pages/error/config-errors.html.twig', [ - "messages" => $results - ]); - } else { - $response = $next($request, $response); - } - - return $response; - } - - /** - * Run through all pre-flight checks. - */ - public function checkAll() { - $problemsFound = FALSE; - - if ($this->checkApache()) $problemsFound = TRUE; - - if ($this->checkPhp()) $problemsFound = TRUE; - - if ($this->checkPdo()) $problemsFound = TRUE; - - if ($this->checkGd()) $problemsFound = TRUE; - - if ($this->checkImageFunctions()) $problemsFound = TRUE; - - if ($this->checkPermissions()) $problemsFound = TRUE; - - return $problemsFound; - } - - /** - * For Apache environments, check that required Apache modules are installed. - */ - public function checkApache() { - $problemsFound = FALSE; - - // Perform some Apache checks. We may also need to do this before any routing takes place. - if (strpos(php_sapi_name(), 'apache') !== FALSE) { - - $require_apache_modules = ['mod_rewrite']; - $apache_modules = apache_get_modules(); - - $apache_status = []; - - foreach ($require_apache_modules as $module) { - if (!in_array($module, $apache_modules)) { - $problemsFound = TRUE; - $this->resultsFailed['apache-' . $module] = [ - "title" => " Missing Apache module $module.", - "message" => "Please make sure that the $module Apache module is installed and enabled. If you use shared hosting, you will need to ask your web host to do this for you.", - "success" => FALSE - ]; - } else { - $this->resultsSuccess['apache-' . $module] = [ - "title" => " Apache module $module is installed and enabled.", - "message" => "Great, we found the $module Apache module!", - "success" => TRUE - ]; - } - } - } - - return $problemsFound; - } - - /** - * Check for GD library (required for Captcha). - */ - public function checkGd() { - $problemsFound = FALSE; - - if (!(extension_loaded('gd') && function_exists('gd_info'))) { - $problemsFound = TRUE; - $this->resultsFailed['gd'] = [ - "title" => " GD library not installed", - "message" => "We could not confirm that the GD library is installed and enabled. GD is an image processing library that UserFrosting uses to generate captcha codes for user account registration.", - "success" => FALSE - ]; - } else { - $this->resultsSuccess['gd'] = [ - "title" => " GD library installed!", - "message" => "Great, you have GD installed and enabled.", - "success" => TRUE - ]; - } - - return $problemsFound; - } - - /** - * Check that all image* functions used by Captcha exist. - * - * Some versions of GD are missing one or more of these functions, thus why we check for them explicitly. - */ - public function checkImageFunctions() { - $problemsFound = FALSE; - - $funcs = [ - 'imagepng', - 'imagecreatetruecolor', - 'imagecolorallocate', - 'imagefilledrectangle', - 'imageline', - 'imagesetpixel', - 'imagefontwidth', - 'imagestring' - ]; - - foreach ($funcs as $func) { - if (!function_exists($func)) { - $problemsFound = TRUE; - $this->resultsFailed['function-' . $func] = [ - "title" => " Missing image manipulation function.", - "message" => "It appears that function $func is not available. UserFrosting needs this to render captchas.", - "success" => FALSE - ]; - } else { - $this->resultsSuccess['function-' . $func] = [ - "title" => " Function $func is available!", - "message" => "Sweet!", - "success" => TRUE - ]; - } - } - - return $problemsFound; - } - - /** - * Check that PDO is installed and enabled. - */ - public function checkPdo() { - $problemsFound = FALSE; - - if (!class_exists('PDO')) { - $problemsFound = TRUE; - $this->resultsFailed['pdo'] = [ - "title" => " PDO is not installed.", - "message" => "I'm sorry, you must have PDO installed and enabled in order for UserFrosting to access the database. If you don't know what PDO is, please see http://php.net/manual/en/book.pdo.php.", - "success" => FALSE - ]; - } else { - $this->resultsSuccess['pdo'] = [ - "title" => " PDO is installed!", - "message" => "You've got PDO installed. Good job!", - "success" => TRUE - ]; - } - - return $problemsFound; - } - - /** - * Check that log, cache, and session directories are writable, and that other directories are set appropriately for the environment. - */ - function checkPermissions() { - $problemsFound = FALSE; - - $shouldBeWriteable = [ - $this->locator->findResource('log://') => TRUE, - $this->locator->findResource('cache://') => TRUE, - $this->locator->findResource('session://') => TRUE - ]; - - if ($this->isProduction()) { - // Should be write-protected in production! - $shouldBeWriteable = array_merge($shouldBeWriteable, [ - \UserFrosting\SPRINKLES_DIR => FALSE, - \UserFrosting\VENDOR_DIR => FALSE - ]); - } - - // Check for essential files & perms - foreach ($shouldBeWriteable as $file => $assertWriteable) { - $is_dir = FALSE; - if (!file_exists($file)) { - $problemsFound = TRUE; - $this->resultsFailed['file-' . $file] = [ - "title" => " File or directory does not exist.", - "message" => "We could not find the file or directory $file.", - "success" => FALSE - ]; - } else { - $writeable = is_writable($file); - if ($assertWriteable !== $writeable) { - $problemsFound = TRUE; - $this->resultsFailed['file-' . $file] = [ - "title" => " Incorrect permissions for file or directory.", - "message" => "$file is " - . ($writeable ? "writeable" : "not writeable") - . ", but it should " - . ($assertWriteable ? "be writeable" : "not be writeable") - . ". Please modify the OS user or group permissions so that user " - . exec('whoami') . " " - . ($assertWriteable ? "has" : "does not have") . " write permissions for this directory.", - "success" => FALSE - ]; - } else { - $this->resultsSuccess['file-' . $file] = [ - "title" => " File/directory check passed!", - "message" => "$file exists and is correctly set as " - . ($writeable ? "writeable" : "not writeable") - . ".", - "success" => TRUE - ]; - } - } - } - return $problemsFound; - } - - /** - * Check that PHP meets the minimum required version. - */ - public function checkPhp() { - $problemsFound = FALSE; - - // Check PHP version - if (version_compare(phpversion(), \UserFrosting\PHP_MIN_VERSION, '<')) { - $problemsFound = TRUE; - $this->resultsFailed['phpVersion'] = [ - "title" => " You need to upgrade your PHP installation.", - "message" => "I'm sorry, UserFrosting requires version " . \UserFrosting\PHP_MIN_VERSION . " or greater. Please upgrade your version of PHP, or contact your web hosting service and ask them to upgrade it for you.", - "success" => FALSE - ]; - } else { - $this->resultsSuccess['phpVersion'] = [ - "title" => " PHP version checks out!", - "message" => "You're using PHP " . \UserFrosting\PHP_MIN_VERSION . "or higher. Great!", - "success" => TRUE - ]; - } - - return $problemsFound; - } - - /** - * Determine whether or not we are running in production mode. - * - * @return bool - */ - public function isProduction() { - return (getenv('UF_MODE') == 'production'); - } -} +view = $view; + $this->locator = $locator; + $this->cache = $cache; + } + + /** + * Invoke the CheckEnvironment middleware, performing all pre-flight checks and returning an error page if problems were found. + * + * @param \Psr\Http\Message\ServerRequestInterface $request PSR7 request + * @param \Psr\Http\Message\ResponseInterface $response PSR7 response + * @param callable $next Next middleware + * + * @return \Psr\Http\Message\ResponseInterface + */ + public function __invoke($request, $response, $next) { + $problemsFound = FALSE; + + // If production environment and no cached checks, perform environment checks + if ($this->isProduction() && $this->cache->get('checkEnvironment') != 'pass') { + $problemsFound = $this->checkAll(); + + // Cache if checks passed + if (!$problemsFound) { + $this->cache->forever('checkEnvironment', 'pass'); + } + } else if (!$this->isProduction()) { + $problemsFound = $this->checkAll(); + } + + if ($problemsFound) { + $results = array_merge($this->resultsFailed, $this->resultsSuccess); + + $response = $this->view->render($response, 'pages/error/config-errors.html.twig', [ + "messages" => $results + ]); + } else { + $response = $next($request, $response); + } + + return $response; + } + + /** + * Run through all pre-flight checks. + */ + public function checkAll() { + $problemsFound = FALSE; + + if ($this->checkApache()) $problemsFound = TRUE; + + if ($this->checkPhp()) $problemsFound = TRUE; + + if ($this->checkPdo()) $problemsFound = TRUE; + + if ($this->checkGd()) $problemsFound = TRUE; + + if ($this->checkImageFunctions()) $problemsFound = TRUE; + + if ($this->checkPermissions()) $problemsFound = TRUE; + + return $problemsFound; + } + + /** + * For Apache environments, check that required Apache modules are installed. + */ + public function checkApache() { + $problemsFound = FALSE; + + // Perform some Apache checks. We may also need to do this before any routing takes place. + if (strpos(php_sapi_name(), 'apache') !== FALSE) { + + $require_apache_modules = ['mod_rewrite']; + $apache_modules = apache_get_modules(); + + $apache_status = []; + + foreach ($require_apache_modules as $module) { + if (!in_array($module, $apache_modules)) { + $problemsFound = TRUE; + $this->resultsFailed['apache-' . $module] = [ + "title" => " Missing Apache module $module.", + "message" => "Please make sure that the $module Apache module is installed and enabled. If you use shared hosting, you will need to ask your web host to do this for you.", + "success" => FALSE + ]; + } else { + $this->resultsSuccess['apache-' . $module] = [ + "title" => " Apache module $module is installed and enabled.", + "message" => "Great, we found the $module Apache module!", + "success" => TRUE + ]; + } + } + } + + return $problemsFound; + } + + /** + * Check for GD library (required for Captcha). + */ + public function checkGd() { + $problemsFound = FALSE; + + if (!(extension_loaded('gd') && function_exists('gd_info'))) { + $problemsFound = TRUE; + $this->resultsFailed['gd'] = [ + "title" => " GD library not installed", + "message" => "We could not confirm that the GD library is installed and enabled. GD is an image processing library that UserFrosting uses to generate captcha codes for user account registration.", + "success" => FALSE + ]; + } else { + $this->resultsSuccess['gd'] = [ + "title" => " GD library installed!", + "message" => "Great, you have GD installed and enabled.", + "success" => TRUE + ]; + } + + return $problemsFound; + } + + /** + * Check that all image* functions used by Captcha exist. + * + * Some versions of GD are missing one or more of these functions, thus why we check for them explicitly. + */ + public function checkImageFunctions() { + $problemsFound = FALSE; + + $funcs = [ + 'imagepng', + 'imagecreatetruecolor', + 'imagecolorallocate', + 'imagefilledrectangle', + 'imageline', + 'imagesetpixel', + 'imagefontwidth', + 'imagestring' + ]; + + foreach ($funcs as $func) { + if (!function_exists($func)) { + $problemsFound = TRUE; + $this->resultsFailed['function-' . $func] = [ + "title" => " Missing image manipulation function.", + "message" => "It appears that function $func is not available. UserFrosting needs this to render captchas.", + "success" => FALSE + ]; + } else { + $this->resultsSuccess['function-' . $func] = [ + "title" => " Function $func is available!", + "message" => "Sweet!", + "success" => TRUE + ]; + } + } + + return $problemsFound; + } + + /** + * Check that PDO is installed and enabled. + */ + public function checkPdo() { + $problemsFound = FALSE; + + if (!class_exists('PDO')) { + $problemsFound = TRUE; + $this->resultsFailed['pdo'] = [ + "title" => " PDO is not installed.", + "message" => "I'm sorry, you must have PDO installed and enabled in order for UserFrosting to access the database. If you don't know what PDO is, please see http://php.net/manual/en/book.pdo.php.", + "success" => FALSE + ]; + } else { + $this->resultsSuccess['pdo'] = [ + "title" => " PDO is installed!", + "message" => "You've got PDO installed. Good job!", + "success" => TRUE + ]; + } + + return $problemsFound; + } + + /** + * Check that log, cache, and session directories are writable, and that other directories are set appropriately for the environment. + */ + function checkPermissions() { + $problemsFound = FALSE; + + $shouldBeWriteable = [ + $this->locator->findResource('log://') => TRUE, + $this->locator->findResource('cache://') => TRUE, + $this->locator->findResource('session://') => TRUE + ]; + + if ($this->isProduction()) { + // Should be write-protected in production! + $shouldBeWriteable = array_merge($shouldBeWriteable, [ + \UserFrosting\SPRINKLES_DIR => FALSE, + \UserFrosting\VENDOR_DIR => FALSE + ]); + } + + // Check for essential files & perms + foreach ($shouldBeWriteable as $file => $assertWriteable) { + $is_dir = FALSE; + if (!file_exists($file)) { + $problemsFound = TRUE; + $this->resultsFailed['file-' . $file] = [ + "title" => " File or directory does not exist.", + "message" => "We could not find the file or directory $file.", + "success" => FALSE + ]; + } else { + $writeable = is_writable($file); + if ($assertWriteable !== $writeable) { + $problemsFound = TRUE; + $this->resultsFailed['file-' . $file] = [ + "title" => " Incorrect permissions for file or directory.", + "message" => "$file is " + . ($writeable ? "writeable" : "not writeable") + . ", but it should " + . ($assertWriteable ? "be writeable" : "not be writeable") + . ". Please modify the OS user or group permissions so that user " + . exec('whoami') . " " + . ($assertWriteable ? "has" : "does not have") . " write permissions for this directory.", + "success" => FALSE + ]; + } else { + $this->resultsSuccess['file-' . $file] = [ + "title" => " File/directory check passed!", + "message" => "$file exists and is correctly set as " + . ($writeable ? "writeable" : "not writeable") + . ".", + "success" => TRUE + ]; + } + } + } + return $problemsFound; + } + + /** + * Check that PHP meets the minimum required version. + */ + public function checkPhp() { + $problemsFound = FALSE; + + // Check PHP version + if (version_compare(phpversion(), \UserFrosting\PHP_MIN_VERSION, '<')) { + $problemsFound = TRUE; + $this->resultsFailed['phpVersion'] = [ + "title" => " You need to upgrade your PHP installation.", + "message" => "I'm sorry, UserFrosting requires version " . \UserFrosting\PHP_MIN_VERSION . " or greater. Please upgrade your version of PHP, or contact your web hosting service and ask them to upgrade it for you.", + "success" => FALSE + ]; + } else { + $this->resultsSuccess['phpVersion'] = [ + "title" => " PHP version checks out!", + "message" => "You're using PHP " . \UserFrosting\PHP_MIN_VERSION . "or higher. Great!", + "success" => TRUE + ]; + } + + return $problemsFound; + } + + /** + * Determine whether or not we are running in production mode. + * + * @return bool + */ + public function isProduction() { + return (getenv('UF_MODE') == 'production'); + } +} diff --git a/main/app/sprinkles/core/src/Util/ClassMapper.php b/main/app/sprinkles/core/src/Util/ClassMapper.php index 11720f6..e29c524 100644 --- a/main/app/sprinkles/core/src/Util/ClassMapper.php +++ b/main/app/sprinkles/core/src/Util/ClassMapper.php @@ -1,90 +1,90 @@ -getClassMapping($identifier); - - $params = array_slice(func_get_args(), 1); - - // We must use reflection in PHP < 5.6. See http://stackoverflow.com/questions/8734522/dynamically-call-class-with-variable-number-of-parameters-in-the-constructor - $reflection = new \ReflectionClass($className); - - return $reflection->newInstanceArgs($params); - } - - /** - * Gets the fully qualified class name for a specified class identifier. - * - * @param string $identifier - * @return string - */ - public function getClassMapping($identifier) { - if (isset($this->classMappings[$identifier])) { - return $this->classMappings[$identifier]; - } else { - throw new \OutOfBoundsException("There is no class mapped to the identifier '$identifier'."); - } - } - - /** - * Assigns a fully qualified class name to a specified class identifier. - * - * @param string $identifier - * @param string $className - * @return ClassMapper - */ - public function setClassMapping($identifier, $className) { - // Check that class exists - if (!class_exists($className)) { - throw new BadClassNameException("Unable to find the class '$className'."); - } - - $this->classMappings[$identifier] = $className; - - return $this; - } - - /** - * Call a static method for a specified class. - * - * @param string $identifier The identifier for the class, e.g. 'user' - * @param string $methodName The method to be invoked. - * @param mixed ...$arg Whatever needs to be passed to the method. - */ - public function staticMethod($identifier, $methodName) { - $className = $this->getClassMapping($identifier); - - $params = array_slice(func_get_args(), 2); - - return call_user_func_array("$className::$methodName", $params); - } -} +getClassMapping($identifier); + + $params = array_slice(func_get_args(), 1); + + // We must use reflection in PHP < 5.6. See http://stackoverflow.com/questions/8734522/dynamically-call-class-with-variable-number-of-parameters-in-the-constructor + $reflection = new \ReflectionClass($className); + + return $reflection->newInstanceArgs($params); + } + + /** + * Gets the fully qualified class name for a specified class identifier. + * + * @param string $identifier + * @return string + */ + public function getClassMapping($identifier) { + if (isset($this->classMappings[$identifier])) { + return $this->classMappings[$identifier]; + } else { + throw new \OutOfBoundsException("There is no class mapped to the identifier '$identifier'."); + } + } + + /** + * Assigns a fully qualified class name to a specified class identifier. + * + * @param string $identifier + * @param string $className + * @return ClassMapper + */ + public function setClassMapping($identifier, $className) { + // Check that class exists + if (!class_exists($className)) { + throw new BadClassNameException("Unable to find the class '$className'."); + } + + $this->classMappings[$identifier] = $className; + + return $this; + } + + /** + * Call a static method for a specified class. + * + * @param string $identifier The identifier for the class, e.g. 'user' + * @param string $methodName The method to be invoked. + * @param mixed ...$arg Whatever needs to be passed to the method. + */ + public function staticMethod($identifier, $methodName) { + $className = $this->getClassMapping($identifier); + + $params = array_slice(func_get_args(), 2); + + return call_user_func_array("$className::$methodName", $params); + } +} diff --git a/main/app/sprinkles/core/src/Util/EnvironmentInfo.php b/main/app/sprinkles/core/src/Util/EnvironmentInfo.php index 116a59e..e0e9d49 100644 --- a/main/app/sprinkles/core/src/Util/EnvironmentInfo.php +++ b/main/app/sprinkles/core/src/Util/EnvironmentInfo.php @@ -1,67 +1,67 @@ -getPdo(); - $results = []; - - try { - $results['type'] = $pdo->getAttribute(\PDO::ATTR_DRIVER_NAME); - } catch (Exception $e) { - $results['type'] = "Unknown"; - } - - try { - $results['version'] = $pdo->getAttribute(\PDO::ATTR_SERVER_VERSION); - } catch (Exception $e) { - $results['version'] = ""; - } - - return $results; - } - - /** - * Test whether a DB connection can be established. - * - * @return bool true if the connection can be established, false otherwise. - */ - public static function canConnectToDatabase() { - try { - Capsule::connection()->getPdo(); - } catch (\PDOException $e) { - return FALSE; - } - - return TRUE; - } -} +getPdo(); + $results = []; + + try { + $results['type'] = $pdo->getAttribute(\PDO::ATTR_DRIVER_NAME); + } catch (Exception $e) { + $results['type'] = "Unknown"; + } + + try { + $results['version'] = $pdo->getAttribute(\PDO::ATTR_SERVER_VERSION); + } catch (Exception $e) { + $results['version'] = ""; + } + + return $results; + } + + /** + * Test whether a DB connection can be established. + * + * @return bool true if the connection can be established, false otherwise. + */ + public static function canConnectToDatabase() { + try { + Capsule::connection()->getPdo(); + } catch (\PDOException $e) { + return FALSE; + } + + return TRUE; + } +} diff --git a/main/app/sprinkles/core/src/Util/ShutdownHandler.php b/main/app/sprinkles/core/src/Util/ShutdownHandler.php index 5447c8f..18e60ec 100644 --- a/main/app/sprinkles/core/src/Util/ShutdownHandler.php +++ b/main/app/sprinkles/core/src/Util/ShutdownHandler.php @@ -1,162 +1,162 @@ -ci = $ci; - $this->displayErrorInfo = $displayErrorInfo; - } - - /** - * Register this class with the shutdown handler. - * - * @return void - */ - public function register() { - register_shutdown_function([$this, 'fatalHandler']); - } - - /** - * Set up the fatal error handler, so that we get a clean error message and alert instead of a WSOD. - */ - public function fatalHandler() { - $error = error_get_last(); - $fatalErrorTypes = [ - E_ERROR, - E_PARSE, - E_CORE_ERROR, - E_COMPILE_ERROR, - E_RECOVERABLE_ERROR - ]; - - // Handle fatal errors and parse errors - if ($error !== NULL && in_array($error['type'], $fatalErrorTypes)) { - - // Build the appropriate error message (debug or client) - if ($this->displayErrorInfo) { - $errorMessage = $this->buildErrorInfoMessage($error); - } else { - $errorMessage = "Oops, looks like our server might have goofed. If you're an admin, please ensure that php.log_errors is enabled, and then check the PHP error log."; - } - - // For CLI, just print the message and exit. - if (php_sapi_name() === 'cli') { - exit($errorMessage . PHP_EOL); - } - - // For all other environments, print a debug response for the requested data type - echo $this->buildErrorPage($errorMessage); - - // If this is an AJAX request and AJAX debugging is turned off, write message to the alert stream - if ($this->ci->request->isXhr() && !$this->ci->config['site.debug.ajax']) { - if ($this->ci->alerts && is_object($this->ci->alerts)) { - $this->ci->alerts->addMessageTranslated('danger', $errorMessage); - } - } - - header('HTTP/1.1 500 Internal Server Error'); - exit(); - } - } - - /** - * Build the error message string. - * - * @param array $error - * @return string - */ - protected function buildErrorInfoMessage(array $error) { - $errfile = $error['file']; - $errline = (string)$error['line']; - $errstr = $error['message']; - - $errorTypes = [ - E_ERROR => 'Fatal error', - E_PARSE => 'Parse error', - E_CORE_ERROR => 'PHP core error', - E_COMPILE_ERROR => 'Zend compile error', - E_RECOVERABLE_ERROR => 'Catchable fatal error' - ]; - - return "" . $errorTypes[$error['type']] . ": $errstr in $errfile on line $errline"; - } - - /** - * Build an error response of the appropriate type as determined by the request's Accept header. - * - * @param string $message - * @return string - */ - protected function buildErrorPage($message) { - $contentType = $this->determineContentType($this->ci->request, $this->ci->config['site.debug.ajax']); - - switch ($contentType) { - case 'application/json': - $error = ['message' => $message]; - return json_encode($error, JSON_PRETTY_PRINT); - - case 'text/html': - return $this->buildHtmlErrorPage($message); - - default: - case 'text/plain': - return $message; - } - } - - /** - * Build an HTML error page from an error string. - * - * @param string $errorMessage - * @return string - */ - protected function buildHtmlErrorPage($message) { - $title = 'UserFrosting Application Error'; - $html = "

$message

"; - - return sprintf( - "" . - "%s

%s

%s", - $title, - $title, - $html - ); - } -} +ci = $ci; + $this->displayErrorInfo = $displayErrorInfo; + } + + /** + * Register this class with the shutdown handler. + * + * @return void + */ + public function register() { + register_shutdown_function([$this, 'fatalHandler']); + } + + /** + * Set up the fatal error handler, so that we get a clean error message and alert instead of a WSOD. + */ + public function fatalHandler() { + $error = error_get_last(); + $fatalErrorTypes = [ + E_ERROR, + E_PARSE, + E_CORE_ERROR, + E_COMPILE_ERROR, + E_RECOVERABLE_ERROR + ]; + + // Handle fatal errors and parse errors + if ($error !== NULL && in_array($error['type'], $fatalErrorTypes)) { + + // Build the appropriate error message (debug or client) + if ($this->displayErrorInfo) { + $errorMessage = $this->buildErrorInfoMessage($error); + } else { + $errorMessage = "Oops, looks like our server might have goofed. If you're an admin, please ensure that php.log_errors is enabled, and then check the PHP error log."; + } + + // For CLI, just print the message and exit. + if (php_sapi_name() === 'cli') { + exit($errorMessage . PHP_EOL); + } + + // For all other environments, print a debug response for the requested data type + echo $this->buildErrorPage($errorMessage); + + // If this is an AJAX request and AJAX debugging is turned off, write message to the alert stream + if ($this->ci->request->isXhr() && !$this->ci->config['site.debug.ajax']) { + if ($this->ci->alerts && is_object($this->ci->alerts)) { + $this->ci->alerts->addMessageTranslated('danger', $errorMessage); + } + } + + header('HTTP/1.1 500 Internal Server Error'); + exit(); + } + } + + /** + * Build the error message string. + * + * @param array $error + * @return string + */ + protected function buildErrorInfoMessage(array $error) { + $errfile = $error['file']; + $errline = (string)$error['line']; + $errstr = $error['message']; + + $errorTypes = [ + E_ERROR => 'Fatal error', + E_PARSE => 'Parse error', + E_CORE_ERROR => 'PHP core error', + E_COMPILE_ERROR => 'Zend compile error', + E_RECOVERABLE_ERROR => 'Catchable fatal error' + ]; + + return "" . $errorTypes[$error['type']] . ": $errstr in $errfile on line $errline"; + } + + /** + * Build an error response of the appropriate type as determined by the request's Accept header. + * + * @param string $message + * @return string + */ + protected function buildErrorPage($message) { + $contentType = $this->determineContentType($this->ci->request, $this->ci->config['site.debug.ajax']); + + switch ($contentType) { + case 'application/json': + $error = ['message' => $message]; + return json_encode($error, JSON_PRETTY_PRINT); + + case 'text/html': + return $this->buildHtmlErrorPage($message); + + default: + case 'text/plain': + return $message; + } + } + + /** + * Build an HTML error page from an error string. + * + * @param string $errorMessage + * @return string + */ + protected function buildHtmlErrorPage($message) { + $title = 'UserFrosting Application Error'; + $html = "

$message

"; + + return sprintf( + "" . + "%s

%s

%s", + $title, + $title, + $html + ); + } +} diff --git a/main/app/sprinkles/core/src/Util/Util.php b/main/app/sprinkles/core/src/Util/Util.php index 0db3b72..0cf3a56 100644 --- a/main/app/sprinkles/core/src/Util/Util.php +++ b/main/app/sprinkles/core/src/Util/Util.php @@ -1,174 +1,174 @@ -' . str_repeat('  ', $newLineLevel); - } - - $result .= $char . $post; - } - - return $result; - } - - /** - * Generate a random phrase, consisting of a specified number of adjectives, followed by a noun. - * - * @param int $numAdjectives - * @param int $maxLength - * @param int $maxTries - * @param string $separator - * @return string - */ - static public function randomPhrase($numAdjectives, $maxLength = 9999999, $maxTries = 10, $separator = '-') { - $adjectives = include('extra://adjectives.php'); - $nouns = include('extra://nouns.php'); - - for ($n = 0; $n < $maxTries; $n++) { - $keys = array_rand($adjectives, $numAdjectives); - $matches = array_only($adjectives, $keys); - - $result = implode($separator, $matches); - $result .= $separator . $nouns[array_rand($nouns)]; - $result = str_slug($result, $separator); - if (strlen($result) < $maxLength) { - return $result; - } - } - - return ''; - } -} +' . str_repeat('  ', $newLineLevel); + } + + $result .= $char . $post; + } + + return $result; + } + + /** + * Generate a random phrase, consisting of a specified number of adjectives, followed by a noun. + * + * @param int $numAdjectives + * @param int $maxLength + * @param int $maxTries + * @param string $separator + * @return string + */ + static public function randomPhrase($numAdjectives, $maxLength = 9999999, $maxTries = 10, $separator = '-') { + $adjectives = include('extra://adjectives.php'); + $nouns = include('extra://nouns.php'); + + for ($n = 0; $n < $maxTries; $n++) { + $keys = array_rand($adjectives, $numAdjectives); + $matches = array_only($adjectives, $keys); + + $result = implode($separator, $matches); + $result .= $separator . $nouns[array_rand($nouns)]; + $result = str_slug($result, $separator); + if (strlen($result) < $maxLength) { + return $result; + } + } + + return ''; + } +} diff --git a/main/app/sprinkles/core/templates/forms/csrf.html.twig b/main/app/sprinkles/core/templates/forms/csrf.html.twig index 806382b..acd87aa 100644 --- a/main/app/sprinkles/core/templates/forms/csrf.html.twig +++ b/main/app/sprinkles/core/templates/forms/csrf.html.twig @@ -1,2 +1,2 @@ - - + + diff --git a/main/app/sprinkles/core/templates/navigation/breadcrumb.html.twig b/main/app/sprinkles/core/templates/navigation/breadcrumb.html.twig index b905013..ea5a3b3 100644 --- a/main/app/sprinkles/core/templates/navigation/breadcrumb.html.twig +++ b/main/app/sprinkles/core/templates/navigation/breadcrumb.html.twig @@ -1,4 +1,4 @@ -