From 2a4ce876b65f7d156d5c2b81f6736919f9293011 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Wed, 12 Aug 2020 23:41:20 +0300 Subject: [PATCH] add the stale release --- .fossa.yml | 11 - .github/ISSUE_TEMPLATE.md | 2 +- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .travis.yml | 24 - CODE_OF_CONDUCT.md | 74 - CONTRIBUTING.md | 33 - FAQ.md | 56 - HISTORY.md | 829 -- HISTORY_ES.md | 141 - README.md | 237 +- README_ES.md | 76 - README_FA.md | 102 - README_FR.md | 87 - README_GR.md | 80 - README_KO.md | 76 - README_RU.md | 81 - README_ZH.md | 216 - VERSION | 1 - _examples/README.md | 219 - _examples/apidoc/swagger/README.md | 3 - _examples/apidoc/yaag/go.mod | 8 - _examples/apidoc/yaag/main.go | 55 - _examples/auth/basicauth/main.go | 57 - _examples/auth/basicauth/main_test.go | 29 - _examples/auth/cors/main.go | 63 - _examples/auth/cors/public/index.html | 18 - _examples/auth/cors/public/main.js | 43 - _examples/auth/goth/main.go | 407 - _examples/auth/goth/templates/index.html | 3 - _examples/auth/goth/templates/user.html | 11 - _examples/auth/hcaptcha/hosts | 3 - _examples/auth/hcaptcha/main.go | 46 - .../hcaptcha/templates/register_form.html | 18 - _examples/auth/jwt/README.md | 29 - _examples/auth/jwt/main.go | 155 - _examples/auth/jwt/rsa_password_protected.key | 30 - _examples/auth/permissions/main.go | 118 - _examples/auth/recaptcha/custom_form/main.go | 44 - _examples/auth/recaptcha/main.go | 40 - .../bootstrapper/bootstrap/bootstrapper.go | 123 - _examples/bootstrapper/folder_structure.png | Bin 30487 -> 0 bytes _examples/bootstrapper/main.go | 19 - _examples/bootstrapper/main_test.go | 32 - .../middleware/identity/identity.go | 33 - _examples/bootstrapper/public/favicon.ico | Bin 15086 -> 0 bytes _examples/bootstrapper/routes/follower.go | 11 - _examples/bootstrapper/routes/following.go | 11 - _examples/bootstrapper/routes/index.go | 11 - _examples/bootstrapper/routes/like.go | 11 - _examples/bootstrapper/routes/routes.go | 13 - _examples/bootstrapper/views/index.html | 1 - .../bootstrapper/views/shared/error.html | 5 - .../bootstrapper/views/shared/layout.html | 23 - _examples/caddy/Caddyfile | 9 - _examples/caddy/README.md | 24 - _examples/caddy/server1/main.go | 49 - _examples/caddy/server1/views/index.html | 3 - .../caddy/server1/views/shared/layout.html | 11 - _examples/caddy/server2/main.go | 68 - .../compression/client-using-iris/main.go | 112 - _examples/compression/client/main.go | 102 - _examples/compression/main.go | 64 - _examples/compression/main_test.go | 84 - .../from-configuration-structure/main.go | 29 - .../from-toml-file/configs/iris.tml | 9 - .../configuration/from-toml-file/main.go | 21 - .../from-yaml-file/configs/iris.yml | 16 - .../configuration/from-yaml-file/main.go | 24 - .../shared-configuration/main.go | 21 - _examples/configuration/functional/main.go | 23 - .../convert-handlers/negroni-like/main.go | 41 - _examples/convert-handlers/nethttp/main.go | 31 - .../wrapping-the-router/main.go | 45 - .../writing-middleware/main.go | 57 - _examples/cookies/basic/main.go | 64 - _examples/cookies/basic/main_test.go | 32 - _examples/cookies/options/main.go | 76 - _examples/cookies/options/main_test.go | 32 - _examples/cookies/securecookie/main.go | 72 - _examples/cookies/securecookie/main_test.go | 34 - _examples/database/mongodb/.env | 2 - _examples/database/mongodb/0_create_movie.png | Bin 93838 -> 0 bytes _examples/database/mongodb/1_update_movie.png | Bin 70592 -> 0 bytes .../database/mongodb/2_get_all_movies.png | Bin 104362 -> 0 bytes _examples/database/mongodb/3_get_movie.png | Bin 85269 -> 0 bytes _examples/database/mongodb/4_delete_movie.png | Bin 49580 -> 0 bytes _examples/database/mongodb/Dockerfile | 17 - _examples/database/mongodb/README.md | 64 - _examples/database/mongodb/api/store/movie.go | 101 - _examples/database/mongodb/docker-compose.yml | 18 - _examples/database/mongodb/env/env.go | 85 - _examples/database/mongodb/go.mod | 9 - _examples/database/mongodb/httputil/error.go | 130 - _examples/database/mongodb/main.go | 83 - _examples/database/mongodb/store/movie.go | 180 - _examples/database/mysql/Dockerfile | 17 - _examples/database/mysql/README.md | 146 - _examples/database/mysql/api/api.go | 97 - .../database/mysql/api/category_handler.go | 251 - _examples/database/mysql/api/helper.go | 25 - _examples/database/mysql/api/httperror.go | 60 - .../database/mysql/api/middleware/.gitkeep | 0 .../database/mysql/api/product_handler.go | 173 - _examples/database/mysql/cache/groupcache.go | 120 - _examples/database/mysql/docker-compose.yml | 32 - _examples/database/mysql/entity/category.go | 89 - _examples/database/mysql/entity/product.go | 95 - _examples/database/mysql/go.mod | 9 - _examples/database/mysql/main.go | 44 - .../api_category/create_category.json | 5 - .../insert_products_category.json | 31 - .../api_category/update_category.json | 6 - .../api_category/update_partial_category.json | 3 - .../database/mysql/migration/api_postman.json | 484 -- .../migration/api_product/create_product.json | 7 - .../api_product/update_partial_product.json | 3 - .../migration/api_product/update_product.json | 8 - _examples/database/mysql/migration/db.sql | 33 - .../mysql/service/category_service.go | 74 - .../mysql/service/category_service_test.go | 42 - .../database/mysql/service/product_service.go | 110 - _examples/database/mysql/sql/mysql.go | 123 - _examples/database/mysql/sql/service.go | 243 - _examples/database/mysql/sql/sql.go | 40 - _examples/database/orm/gorm/REAMDE.md | 5 - _examples/database/orm/gorm/main.go | 177 - .../reform/controllers/person_controller.go | 47 - _examples/database/orm/reform/go.mod | 11 - _examples/database/orm/reform/main.go | 50 - .../database/orm/reform/models/person.go | 13 - .../orm/reform/models/person_reform.go | 136 - .../orm/reform/postman_collection.json | 58 - _examples/database/orm/xorm/main.go | 74 - _examples/dependency-injection/basic/main.go | 47 - .../basic/middleware/main.go | 64 - .../basic/middleware/main_test.go | 25 - .../context-register-dependency/main.go | 95 - .../dependency-injection/jwt/contrib/go.mod | 5 - .../dependency-injection/jwt/contrib/main.go | 66 - _examples/dependency-injection/jwt/main.go | 50 - .../overview/datamodels/movie.go | 18 - .../overview/datasource/movies.go | 44 - .../dependency-injection/overview/main.go | 55 - .../overview/repositories/movie_repository.go | 176 - .../overview/services/movie_service.go | 65 - .../overview/web/middleware/basicauth.go | 12 - .../overview/web/routes/hello.go | 50 - .../overview/web/routes/movies.go | 59 - .../overview/web/views/hello/index.html | 12 - .../overview/web/views/hello/name.html | 12 - .../dependency-injection/sessions/main.go | 34 - .../sessions/routes/index.go | 17 - .../smart-contract/main.go | 156 - _examples/desktop/blink/main.go | 42 - _examples/desktop/lorca/main.go | 40 - _examples/desktop/webview/main.go | 44 - _examples/dropzonejs/README.md | 168 - _examples/dropzonejs/README_PART2.md | 310 - _examples/dropzonejs/folder_structure.png | Bin 10628 -> 0 bytes _examples/dropzonejs/meta.yml | 8 - _examples/dropzonejs/no_files.png | Bin 31987 -> 0 bytes _examples/dropzonejs/src/main.go | 168 - .../dropzonejs/src/public/css/dropzone.css | 388 - .../dropzonejs/src/public/js/dropzone.js | 2052 ----- _examples/dropzonejs/src/views/upload.html | 53 - _examples/dropzonejs/with_files.png | Bin 42036 -> 0 bytes .../basic/assets.system/css/main.css | 3 - .../file-server/basic/assets.system/test.txt | 1 - .../app2/app22/just_a_text_no_index.txt | 1 - .../basic/assets/app2/app2app3/index.html | 1 - .../file-server/basic/assets/app2/index.html | 1 - .../file-server/basic/assets/css/main.css | 3 - .../file-server/basic/assets/favicon.ico | Bin 15086 -> 0 bytes _examples/file-server/basic/assets/index.html | 1 - _examples/file-server/basic/assets/js/main.js | 1 - _examples/file-server/basic/main.go | 66 - _examples/file-server/basic/main_test.go | 114 - .../assets/css/bootstrap.min.css | 7225 ----------------- .../assets/favicon.ico | Bin 15086 -> 0 bytes .../assets/js/jquery-2.1.1.js | 1 - .../embedding-files-into-app/bindata.go | 382 - .../embedding-files-into-app/main.go | 43 - .../embedding-files-into-app/main_test.go | 96 - .../bindata.go | 382 - .../embedding-gzipped-files-into-app/main.go | 50 - .../main_test.go | 125 - _examples/file-server/favicon/main.go | 24 - .../favicon/static/favicons/favicon.ico | Bin 15086 -> 0 bytes _examples/file-server/file-server/main.go | 135 - .../file-server/views/dirlist.html | 125 - .../file-server/file-server/views/upload.html | 38 - .../http2push-embedded-gzipped/bindata.go | 580 -- .../http2push-embedded-gzipped/main.go | 41 - .../file-server/http2push-embedded/bindata.go | 580 -- .../file-server/http2push-embedded/main.go | 37 - .../assets/app2/app2app3/css/main.css | 3 - .../assets/app2/app2app3/dirs/dir1/text.txt | 1 - .../assets/app2/app2app3/dirs/dir2/text.txt | 1 - .../assets/app2/app2app3/dirs/text.txt | 1 - .../http2push/assets/app2/app2app3/index.html | 15 - .../http2push/assets/app2/index.html | 1 - .../http2push/assets/app2/mydir/text.txt | 1 - .../file-server/http2push/assets/css/main.css | 3 - .../file-server/http2push/assets/favicon.ico | Bin 15086 -> 0 bytes .../file-server/http2push/assets/index.html | 18 - .../file-server/http2push/assets/js/main.js | 5 - _examples/file-server/http2push/main.go | 52 - _examples/file-server/http2push/mycert.crt | 31 - _examples/file-server/http2push/mykey.key | 52 - .../file-server/send-files/files/first.zip | Bin 2901 -> 0 bytes _examples/file-server/send-files/main.go | 31 - .../single-page-application/basic/main.go | 36 - .../basic/main_test.go | 62 - .../basic/public/app.js | 1 - .../basic/public/css/main.css | 3 - .../basic/public/index.html | 14 - .../bindata.go | 380 - .../main.go | 54 - .../public/app.js | 1 - .../public/css/main.css | 3 - .../public/index.html | 14 - .../bindata.go | 407 - .../embedded-single-page-application/main.go | 42 - .../main_test.go | 79 - .../public/app.js | 1 - .../public/app2/index.html | 11 - .../public/css/main.css | 3 - .../public/index.html | 14 - .../app2/app22/just_a_text_no_index.txt | 1 - .../subdomain/assets/app2/app2app3/index.html | 1 - .../subdomain/assets/app2/index.html | 1 - .../file-server/subdomain/assets/css/main.css | 3 - .../file-server/subdomain/assets/favicon.ico | Bin 15086 -> 0 bytes .../file-server/subdomain/assets/index.html | 1 - .../subdomain/assets/js/jquery-2.1.1.js | 1 - _examples/file-server/subdomain/hosts | 2 - _examples/file-server/subdomain/main.go | 29 - _examples/file-server/subdomain/main_test.go | 81 - _examples/file-server/upload-file/main.go | 128 - .../upload-file/templates/upload_form.html | 15 - .../file-server/upload-file/uploads/.gitkeep | 0 _examples/file-server/upload-files/main.go | 116 - .../file-server/upload-files/main_test.go | 31 - .../upload-files/templates/upload_form.html | 12 - .../file-server/upload-files/uploads/.gitkeep | 0 _examples/http-server/README.md | 205 - .../custom-httpserver/easy-way/main.go | 32 - .../custom-httpserver/multi/main.go | 47 - .../custom-httpserver/std-way/main.go | 40 - _examples/http-server/custom-listener/main.go | 28 - .../graceful-shutdown/custom-notifier/main.go | 46 - .../default-notifier/main.go | 34 - _examples/http-server/http3-quic/go.mod | 7 - .../http-server/http3-quic/localhost.cert | 18 - .../http-server/http3-quic/localhost.key | 27 - _examples/http-server/http3-quic/main.go | 29 - .../main.go | 28 - .../http-server/listen-addr-public/main.go | 36 - _examples/http-server/listen-addr/main.go | 17 - .../listen-addr/omit-server-errors/main.go | 24 - .../omit-server-errors/main_test.go | 73 - .../http-server/listen-letsencrypt/main.go | 42 - _examples/http-server/listen-tls/main.go | 27 - _examples/http-server/listen-tls/mycert.crt | 31 - _examples/http-server/listen-tls/mykey.key | 52 - _examples/http-server/listen-unix/main.go | 17 - .../http-server/notify-on-shutdown/main.go | 59 - _examples/http-server/socket-sharding/main.go | 21 - _examples/i18n/hosts | 26 - _examples/i18n/locales/el-GR/locale_el-GR.ini | 1 - .../el-GR/locale_multi_first_el-GR.ini | 1 - .../el-GR/locale_multi_second_el-GR.ini | 1 - _examples/i18n/locales/en-US/locale_en-US.ini | 1 - .../en-US/locale_multi_first_en-US.ini | 1 - .../en-US/locale_multi_second_en-US.ini | 1 - _examples/i18n/locales/zh-CN/locale_zh-CN.ini | 1 - _examples/i18n/main.go | 95 - _examples/i18n/main_test.go | 86 - _examples/i18n/views/index.html | 9 - _examples/kafka-api/0_docs.png | Bin 29953 -> 0 bytes _examples/kafka-api/1_create_topic.png | Bin 26684 -> 0 bytes _examples/kafka-api/2_list_topics.png | Bin 45669 -> 0 bytes _examples/kafka-api/3_store_to_topic.png | Bin 38028 -> 0 bytes .../4_retrieve_from_topic_real_time.png | Bin 48712 -> 0 bytes _examples/kafka-api/Dockerfile | 17 - _examples/kafka-api/README.md | 33 - _examples/kafka-api/docker-compose.yml | 29 - _examples/kafka-api/go.mod | 8 - _examples/kafka-api/main.go | 394 - _examples/logging/file-logger/main.go | 48 - _examples/logging/json-logger/main.go | 87 - _examples/logging/json-logger/main_test.go | 59 - _examples/logging/request-logger/main.go | 65 - .../request-logger-file-json/main.go | 110 - .../request-logger-file/main.go | 107 - _examples/logging/rollbar/go.mod | 8 - _examples/logging/rollbar/main.go | 107 - .../mvc/authenticated-controller/main.go | 110 - .../mvc/authenticated-controller/main_test.go | 24 - _examples/mvc/basic/main.go | 105 - _examples/mvc/basic/wildcard/main.go | 41 - _examples/mvc/error-handler/main.go | 39 - _examples/mvc/grpc-compatible/README.md | 20 - .../mvc/grpc-compatible/grpc-client/main.go | 47 - .../mvc/grpc-compatible/helloworld/README.md | 3 - .../helloworld/helloworld.pb.go | 315 - .../helloworld/helloworld.proto | 33 - .../mvc/grpc-compatible/http-client/main.go | 50 - _examples/mvc/grpc-compatible/main.go | 74 - _examples/mvc/grpc-compatible/main_test.go | 16 - _examples/mvc/grpc-compatible/server.crt | 22 - _examples/mvc/grpc-compatible/server.key | 27 - _examples/mvc/hello-world/main.go | 154 - _examples/mvc/hello-world/main_test.go | 23 - .../folder_structure.png | Bin 28423 -> 0 bytes .../login-mvc-single-responsibility/main.go | 56 - .../public/css/site.css | 61 - .../user/auth.go | 110 - .../user/controller.go | 189 - .../user/datasource.go | 114 - .../user/model.go | 36 - .../views/shared/error.html | 4 - .../views/shared/layout.html | 12 - .../views/user/login.html | 11 - .../views/user/me.html | 3 - .../views/user/notfound.html | 3 - .../views/user/register.html | 14 - _examples/mvc/login/datamodels/user.go | 41 - _examples/mvc/login/datasource/users.go | 31 - _examples/mvc/login/folder_structure.png | Bin 33014 -> 0 bytes _examples/mvc/login/main.go | 83 - .../mvc/login/repositories/user_repository.go | 174 - _examples/mvc/login/services/user_service.go | 125 - .../login/web/controllers/user_controller.go | 170 - .../login/web/controllers/users_controller.go | 88 - .../mvc/login/web/middleware/basicauth.go | 12 - _examples/mvc/login/web/public/css/site.css | 61 - _examples/mvc/login/web/viewmodels/README.md | 56 - .../mvc/login/web/views/shared/error.html | 15 - .../mvc/login/web/views/shared/layout.html | 12 - _examples/mvc/login/web/views/user/login.html | 11 - _examples/mvc/login/web/views/user/me.html | 3 - .../mvc/login/web/views/user/register.html | 14 - _examples/mvc/middleware/main.go | 47 - _examples/mvc/middleware/per-method/main.go | 105 - .../mvc/middleware/without-ctx-next/main.go | 48 - _examples/mvc/overview/Dockerfile | 17 - _examples/mvc/overview/README.md | 378 - .../overview/controller/greet_controller.go | 23 - _examples/mvc/overview/database/database.go | 20 - _examples/mvc/overview/database/mysql.go | 10 - _examples/mvc/overview/database/sqlite.go | 5 - _examples/mvc/overview/docker-compose.yml | 16 - .../mvc/overview/environment/environment.go | 50 - _examples/mvc/overview/go.mod | 5 - _examples/mvc/overview/main.go | 85 - _examples/mvc/overview/model/request.go | 6 - _examples/mvc/overview/model/response.go | 6 - .../mvc/overview/service/greet_service.go | 51 - _examples/mvc/regexp/main.go | 49 - _examples/mvc/repository/datamodels/README.md | 1 - _examples/mvc/repository/datamodels/movie.go | 18 - _examples/mvc/repository/datasource/README.md | 1 - _examples/mvc/repository/datasource/movies.go | 44 - _examples/mvc/repository/folder_structure.png | Bin 30336 -> 0 bytes _examples/mvc/repository/main.go | 53 - _examples/mvc/repository/models/README.md | 20 - .../mvc/repository/repositories/README.md | 3 - .../repositories/movie_repository.go | 176 - _examples/mvc/repository/services/README.md | 3 - .../mvc/repository/services/movie_service.go | 65 - .../web/controllers/hello_controller.go | 58 - .../web/controllers/movie_controller.go | 77 - .../repository/web/middleware/basicauth.go | 12 - .../mvc/repository/web/viewmodels/README.md | 56 - .../mvc/repository/web/views/hello/index.html | 12 - .../mvc/repository/web/views/hello/name.html | 12 - _examples/mvc/session-controller/main.go | 58 - _examples/mvc/session-controller/main_test.go | 21 - _examples/mvc/singleton/main.go | 36 - _examples/mvc/versioned-controller/main.go | 62 - .../mvc/versioned-controller/main_test.go | 34 - _examples/mvc/vuejs-todo-mvc/README.md | 593 -- _examples/mvc/vuejs-todo-mvc/screen.png | Bin 103259 -> 0 bytes _examples/mvc/vuejs-todo-mvc/src/todo/item.go | 8 - .../mvc/vuejs-todo-mvc/src/todo/service.go | 46 - .../src/web/controllers/todo_controller.go | 66 - _examples/mvc/vuejs-todo-mvc/src/web/main.go | 63 - .../vuejs-todo-mvc/src/web/public/css/index | 2 - .../vuejs-todo-mvc/src/web/public/index.html | 73 - .../vuejs-todo-mvc/src/web/public/js/app.js | 214 - .../vuejs-todo-mvc/src/web/public/js/lib/vue | 2 - _examples/mvc/websocket/browser/index.html | 106 - _examples/mvc/websocket/main.go | 118 - _examples/pprof/main.go | 21 - _examples/recover/main.go | 28 - _examples/request-body/read-body/main.go | 58 - _examples/request-body/read-body/main_test.go | 53 - .../request-body/read-custom-per-type/main.go | 64 - .../read-custom-per-type/main_test.go | 17 - .../read-custom-via-unmarshaler/main.go | 72 - .../read-custom-via-unmarshaler/main_test.go | 17 - _examples/request-body/read-form/main.go | 47 - .../read-form/templates/form.html | 22 - .../read-json-struct-validation/main.go | 146 - _examples/request-body/read-json/main.go | 62 - _examples/request-body/read-many/main.go | 60 - _examples/request-body/read-msgpack/main.go | 37 - _examples/request-body/read-query/main.go | 30 - _examples/request-body/read-xml/main.go | 49 - _examples/request-body/read-xml/main_test.go | 18 - _examples/request-body/read-yaml/main.go | 35 - _examples/request-body/read-yaml/main_test.go | 24 - _examples/request-ratelimit/main.go | 90 - _examples/request-referrer/main.go | 28 - .../response-writer/cache/client-side/main.go | 39 - .../response-writer/cache/simple/main.go | 80 - .../content-negotiation/main.go | 114 - .../content-negotiation/main_test.go | 80 - _examples/response-writer/http2push/main.go | 47 - .../response-writer/http2push/mycert.crt | 31 - _examples/response-writer/http2push/mykey.key | 52 - .../response-writer/http2push/public/main.js | 1 - _examples/response-writer/protobuf/README.md | 18 - _examples/response-writer/protobuf/go.mod | 3 - _examples/response-writer/protobuf/main.go | 60 - .../protobuf/protos/hello.pb.go | 209 - .../protobuf/protos/hello.proto | 13 - .../response-writer/sse-third-party/main.go | 50 - _examples/response-writer/sse/main.go | 191 - .../sse/optional.sse.mini.js.html | 17 - .../response-writer/stream-writer/main.go | 79 - .../response-writer/transactions/main.go | 54 - _examples/response-writer/write-rest/main.go | 125 - _examples/routing/README.md | 1 - _examples/routing/basic/.dockerignore | 3 - _examples/routing/basic/Dockerfile | 17 - _examples/routing/basic/README.md | 27 - _examples/routing/basic/docker-compose.yml | 8 - _examples/routing/basic/main.go | 206 - _examples/routing/basic/main_test.go | 88 - _examples/routing/conditional-chain/main.go | 56 - .../routing/conditional-chain/main_test.go | 17 - _examples/routing/custom-router/main.go | 108 - _examples/routing/custom-wrapper/main.go | 69 - _examples/routing/custom-wrapper/main_test.go | 61 - .../routing/custom-wrapper/public/app.js | 1 - .../custom-wrapper/public/css/main.css | 3 - .../routing/custom-wrapper/public/index.html | 14 - _examples/routing/dynamic-path/main.go | 293 - .../dynamic-path/root-wildcard/main.go | 70 - .../same-pattern-different-func/main.go | 33 - .../same-pattern-different-func/main_test.go | 41 - .../use-global/main.go | 42 - .../use-global/main_test.go | 25 - _examples/routing/hello-world/main.go | 42 - _examples/routing/http-errors/main.go | 116 - .../routing/http-errors/reset-body/main.go | 42 - .../http-errors/reset-body/main_test.go | 14 - _examples/routing/intelligence/main.go | 24 - _examples/routing/intelligence/manual/main.go | 37 - _examples/routing/macros/main.go | 76 - _examples/routing/main.go | 182 - _examples/routing/main_test.go | 141 - _examples/routing/overview-2/main.go | 126 - .../views/user/create_verification.html | 22 - .../overview-2/views/user/profile.html | 7 - _examples/routing/overview/main.go | 192 - .../overview/public/assets/css/main.css | 3 - .../overview/public/images/favicon.ico | Bin 15086 -> 0 bytes _examples/routing/reverse/main.go | 39 - .../route-handlers-execution-rules/main.go | 61 - _examples/routing/route-register-rule/main.go | 45 - .../routing/route-register-rule/main_test.go | 22 - _examples/routing/route-state/main.go | 45 - _examples/routing/sitemap/main.go | 38 - _examples/routing/sitemap/main_test.go | 18 - _examples/routing/subdomains/multi/hosts | 28 - _examples/routing/subdomains/multi/main.go | 40 - .../multi/public/assets/images/test.ico | Bin 1150 -> 0 bytes .../multi/public/upload_resources/favicon.ico | Bin 15086 -> 0 bytes _examples/routing/subdomains/redirect/hosts | 4 - _examples/routing/subdomains/redirect/main.go | 73 - .../routing/subdomains/redirect/main_test.go | 29 - _examples/routing/subdomains/single/hosts | 27 - _examples/routing/subdomains/single/main.go | 44 - _examples/routing/subdomains/wildcard/hosts | 30 - _examples/routing/subdomains/wildcard/main.go | 71 - _examples/routing/subdomains/www/hosts | 25 - _examples/routing/subdomains/www/main.go | 79 - _examples/routing/subdomains/www/main_test.go | 57 - _examples/routing/versioning/main.go | 78 - .../writing-a-middleware/globally/main.go | 69 - .../writing-a-middleware/per-route/main.go | 69 - _examples/sessions/basic/main.go | 51 - _examples/sessions/database/badger/main.go | 56 - _examples/sessions/database/boltdb/main.go | 63 - _examples/sessions/database/redis/Dockerfile | 16 - .../database/redis/docker-compose.yml | 24 - _examples/sessions/database/redis/go.mod | 6 - _examples/sessions/database/redis/main.go | 77 - _examples/sessions/flash-messages/main.go | 44 - .../sessions/overview/example/example.go | 187 - _examples/sessions/overview/main.go | 42 - _examples/sessions/securecookie/main.go | 40 - _examples/sessions/securecookie/main_test.go | 27 - _examples/testing/httptest/main.go | 46 - _examples/testing/httptest/main_test.go | 46 - _examples/url-shortener/README.md | 3 - _examples/url-shortener/factory.go | 52 - _examples/url-shortener/main.go | 114 - _examples/url-shortener/main_test.go | 76 - .../url-shortener/resources/css/style.css | 3 - _examples/url-shortener/store.go | 181 - _examples/url-shortener/templates/index.html | 25 - _examples/view/context-view-data/main.go | 55 - .../context-view-data/templates/index.html | 8 - .../templates/layouts/layout.html | 10 - _examples/view/context-view-engine/main.go | 65 - .../views/admin/index.html | 3 - .../views/admin/layouts/main.html | 14 - .../views/on-fly/index.html | 2 - .../context-view-engine/views/public/500.html | 12 - .../views/public/index.html | 1 - .../views/public/layouts/error.html | 13 - .../views/public/layouts/main.html | 13 - .../views/public/partials/footer.html | 1 - .../embedding-templates-into-app/bindata.go | 319 - .../view/embedding-templates-into-app/main.go | 61 - .../templates/layouts/layout.html | 12 - .../templates/layouts/mylayout.html | 12 - .../templates/page1.html | 7 - .../templates/partials/page1_partial1.html | 3 - _examples/view/herotemplate/README.md | 26 - _examples/view/herotemplate/app.go | 52 - .../view/herotemplate/template/index.html | 11 - .../view/herotemplate/template/index.html.go | 3 - .../view/herotemplate/template/user.html | 3 - .../view/herotemplate/template/user.html.go | 3 - .../view/herotemplate/template/userlist.html | 11 - .../herotemplate/template/userlist.html.go | 40 - .../herotemplate/template/userlistwriter.html | 11 - .../template/userlistwriter.html.go | 43 - _examples/view/overview/main.go | 37 - _examples/view/overview/templates/hi.html | 11 - _examples/view/quicktemplate/README.md | 19 - .../controllers/execute_template.go | 14 - .../view/quicktemplate/controllers/hello.go | 30 - .../view/quicktemplate/controllers/index.go | 15 - _examples/view/quicktemplate/main.go | 22 - _examples/view/quicktemplate/main_test.go | 47 - _examples/view/quicktemplate/models/.gitkeep | 0 .../view/quicktemplate/templates/base.qtpl | 36 - .../view/quicktemplate/templates/base.qtpl.go | 147 - .../view/quicktemplate/templates/hello.qtpl | 14 - .../quicktemplate/templates/hello.qtpl.go | 82 - .../view/quicktemplate/templates/index.qtpl | 12 - .../quicktemplate/templates/index.qtpl.go | 72 - _examples/view/template_ace_0/main.go | 31 - _examples/view/template_ace_0/views/index.ace | 5 - .../template_ace_0/views/layouts/main.ace | 6 - .../template_ace_0/views/partials/footer.ace | 1 - .../template_ace_0/views/partials/header.ace | 1 - _examples/view/template_blocks_0/main.go | 35 - .../view/template_blocks_0/views/500.html | 12 - .../view/template_blocks_0/views/index.html | 1 - .../views/layouts/error.html | 13 - .../template_blocks_0/views/layouts/main.html | 13 - .../views/partials/footer.html | 1 - .../template_blocks_1_embedded/bindata.go | 343 - .../view/template_blocks_1_embedded/main.go | 40 - _examples/view/template_django_0/main.go | 44 - .../view/template_django_0/templates/hi.html | 12 - _examples/view/template_html_0/main.go | 48 - .../view/template_html_0/templates/hi.html | 8 - _examples/view/template_html_1/main.go | 29 - .../template_html_1/templates/layout.html | 11 - .../template_html_1/templates/mypage.html | 4 - _examples/view/template_html_2/README.md | 3 - _examples/view/template_html_2/main.go | 50 - .../templates/layouts/layout.html | 12 - .../templates/layouts/mylayout.html | 12 - .../view/template_html_2/templates/page1.html | 7 - .../templates/partials/page1_partial1.html | 3 - _examples/view/template_html_3/main.go | 66 - .../view/template_html_3/templates/page.html | 55 - _examples/view/template_html_4/hosts | 32 - _examples/view/template_html_4/main.go | 76 - .../view/template_html_4/templates/page.html | 43 - _examples/view/template_html_5/main.go | 31 - .../view/template_html_5/views/about.html | 15 - .../view/template_html_5/views/home.html | 11 - .../view/template_html_5/views/layout.html | 11 - .../template_html_5/views/user/index.html | 10 - _examples/view/template_jet_0/README.md | 10 - _examples/view/template_jet_0/main.go | 146 - .../views/layouts/application.jet | 10 - .../view/template_jet_0/views/todos/index.jet | 30 - .../view/template_jet_0/views/todos/show.jet | 9 - .../view/template_jet_1_embedded/README.md | 25 - .../view/template_jet_1_embedded/bindata.go | 308 - .../view/template_jet_1_embedded/main.go | 34 - .../views/includes/_partial.jet | 1 - .../views/includes/blocks.jet | 3 - .../template_jet_1_embedded/views/index.jet | 16 - .../views/layouts/application.jet | 10 - _examples/view/template_jet_2/main.go | 70 - _examples/view/template_jet_2/views/page.jet | 24 - _examples/view/template_jet_3/main.go | 55 - _examples/view/template_jet_3/views/index.jet | 5 - _examples/view/template_pug_0/main.go | 28 - .../view/template_pug_0/templates/index.pug | 25 - _examples/view/template_pug_1/main.go | 42 - .../view/template_pug_1/templates/index.pug | 20 - _examples/view/template_pug_2/main.go | 28 - .../view/template_pug_2/templates/footer.pug | 2 - .../view/template_pug_2/templates/header.pug | 4 - .../view/template_pug_2/templates/index.pug | 7 - _examples/view/template_pug_3/bindata.go | 269 - _examples/view/template_pug_3/main.go | 23 - .../view/template_pug_3/templates/index.pug | 7 - .../view/template_pug_3/templates/layout.pug | 7 - _examples/view/write-to/main.go | 42 - .../view/write-to/views/email/simple.html | 1 - .../view/write-to/views/shared/email.html | 6 - .../webassembly/client/go-wasm-runtime.js | 412 - _examples/webassembly/client/hello.html | 10 - _examples/webassembly/client/hello_go114.go | 16 - _examples/webassembly/client/main.js | 13 - _examples/webassembly/main.go | 28 - _examples/websocket/README.md | 14 - _examples/websocket/basic/README.md | 62 - _examples/websocket/basic/browser/index.html | 112 - _examples/websocket/basic/browserify/app.js | 75 - .../websocket/basic/browserify/bundle.js | 1 - .../websocket/basic/browserify/client.html | 10 - .../websocket/basic/browserify/package.json | 16 - _examples/websocket/basic/go-client/client.go | 85 - _examples/websocket/basic/go.mod | 5 - .../websocket/basic/nodejs-client/client.js | 35 - .../basic/nodejs-client/package.json | 8 - _examples/websocket/basic/overview.png | Bin 206747 -> 0 bytes _examples/websocket/basic/server.go | 120 - _examples/websocket/gorilla-filewatch/go.mod | 10 - _examples/websocket/gorilla-filewatch/main.go | 168 - .../websocket/gorilla-filewatch/testfile.txt | 4 - .../gorilla-filewatch/views/home.html | 22 - _examples/websocket/native-messages/main.go | 59 - .../native-messages/static/js/chat.js | 35 - .../native-messages/templates/client.html | 19 - _examples/websocket/online-visitors/main.go | 173 - .../static/assets/js/visitors.js | 24 - .../online-visitors/templates/index.html | 43 - .../online-visitors/templates/other.html | 29 - _examples/websocket/secure/README.md | 6 - _examples/websocket/socketio/asset/index.html | 80 - _examples/websocket/socketio/go.mod | 8 - _examples/websocket/socketio/main.go | 57 - aliases.go | 16 +- cache/browser.go | 6 +- cache/browser_test.go | 102 - cache/cache.go | 8 +- cache/cache_test.go | 215 - cache/client/client.go | 8 +- cache/client/handler.go | 6 +- cache/client/rule/chained.go | 2 +- cache/client/rule/conditional.go | 2 +- cache/client/rule/header.go | 4 +- cache/client/rule/not_satisfied.go | 2 +- cache/client/rule/rule.go | 2 +- cache/client/rule/satisfied.go | 2 +- cache/client/rule/validator.go | 2 +- cache/client/ruleset.go | 8 +- cache/entry/entry.go | 2 +- cache/uri/uribuilder.go | 2 +- cli.go | 4 +- configuration.go | 4 +- configuration_test.go | 360 - context/configuration.go | 2 +- context/context.go | 4 +- context/handler.go | 2 +- context/request_params.go | 2 +- context/route.go | 2 +- core/errgroup/errgroup_test.go | 173 - core/handlerconv/from_std.go | 2 +- core/handlerconv/from_std_test.go | 71 - core/host/proxy.go | 2 +- core/host/proxy_test.go | 69 - core/host/supervisor.go | 2 +- core/host/supervisor_task_example_test.go | 112 - core/host/supervisor_test.go | 119 - core/host/task.go | 2 +- core/memstore/memstore_test.go | 167 - core/netutil/addr_test.go | 43 - core/netutil/ip_test.go | 62 - core/router/api_builder.go | 10 +- core/router/api_builder_benchmark_test.go | 103 - core/router/api_container.go | 6 +- core/router/fs.go | 2 +- core/router/handler.go | 8 +- core/router/handler_execution_rules.go | 2 +- core/router/handler_execution_rules_test.go | 91 - core/router/mime.go | 2 +- core/router/party.go | 6 +- core/router/path.go | 8 +- core/router/path_test.go | 136 - core/router/route.go | 6 +- core/router/route_register_rule_test.go | 111 - core/router/route_test.go | 56 - core/router/router.go | 2 +- core/router/router_handlers_order_test.go | 287 - .../router_subdomain_redirect_wrapper.go | 4 +- core/router/router_test.go | 74 - core/router/router_wildcard_root_test.go | 198 - core/router/router_wrapper_test.go | 51 - core/router/status_test.go | 160 - core/router/trie.go | 2 +- doc.go | 67 - go.mod | 2 +- hero/binding.go | 2 +- hero/binding_test.go | 548 -- hero/container.go | 4 +- hero/container_test.go | 131 - hero/dependency.go | 2 +- hero/dependency_test.go | 206 - hero/func_result.go | 2 +- hero/func_result_test.go | 281 - hero/handler.go | 2 +- hero/handler_test.go | 287 - hero/param_test.go | 47 - hero/reflect.go | 2 +- hero/reflect_test.go | 39 - hero/struct.go | 2 +- hero/struct_test.go | 121 - httptest/httptest.go | 6 +- i18n/i18n.go | 4 +- i18n/loader.go | 2 +- iris.go | 37 +- macro/handler/handler.go | 6 +- macro/handler/handler_test.go | 41 - macro/interpreter/lexer/lexer.go | 2 +- macro/interpreter/lexer/lexer_test.go | 54 - macro/interpreter/parser/parser.go | 6 +- macro/interpreter/parser/parser_test.go | 399 - macro/macro_test.go | 471 -- macro/macros.go | 2 +- macro/template.go | 4 +- middleware/basicauth/basicauth.go | 4 +- middleware/basicauth/config.go | 2 +- middleware/grpc/grpc.go | 4 +- middleware/hcaptcha/hcaptcha.go | 2 +- middleware/jwt/jwt.go | 2 +- middleware/jwt/jwt_test.go | 139 - middleware/logger/config.go | 2 +- middleware/logger/logger.go | 2 +- middleware/methodoverride/methodoverride.go | 4 +- .../methodoverride/methodoverride_test.go | 76 - middleware/pprof/pprof.go | 4 +- middleware/rate/rate.go | 2 +- middleware/recaptcha/recaptcha.go | 4 +- middleware/recover/recover.go | 2 +- middleware/requestid/requestid.go | 2 +- middleware/requestid/requestid_test.go | 63 - mvc/aliases.go | 4 +- mvc/controller.go | 8 +- mvc/controller_handle_test.go | 201 - mvc/controller_method_parser.go | 4 +- mvc/controller_method_result_test.go | 271 - mvc/controller_test.go | 758 -- mvc/grpc.go | 2 +- mvc/mvc.go | 8 +- mvc/versioning.go | 6 +- sessions/config.go | 2 +- sessions/database.go | 2 +- sessions/lifetime.go | 2 +- sessions/session.go | 2 +- sessions/sessiondb/badger/database.go | 2 +- sessions/sessiondb/boltdb/database.go | 2 +- sessions/sessiondb/redis/database.go | 2 +- sessions/sessions.go | 2 +- sessions/sessions_test.go | 326 - versioning/deprecation.go | 2 +- versioning/deprecation_test.go | 33 - versioning/group.go | 4 +- versioning/version.go | 2 +- versioning/version_test.go | 48 - versioning/versioning.go | 2 +- versioning/versioning_test.go | 135 - view/README.md | 6 +- view/django.go | 2 +- view/jet.go | 2 +- view/view.go | 2 +- websocket/websocket.go | 2 +- 793 files changed, 188 insertions(+), 52415 deletions(-) delete mode 100644 .fossa.yml delete mode 100644 .travis.yml delete mode 100644 CODE_OF_CONDUCT.md delete mode 100644 CONTRIBUTING.md delete mode 100644 FAQ.md delete mode 100644 HISTORY.md delete mode 100644 HISTORY_ES.md delete mode 100644 README_ES.md delete mode 100644 README_FA.md delete mode 100644 README_FR.md delete mode 100644 README_GR.md delete mode 100644 README_KO.md delete mode 100644 README_RU.md delete mode 100644 README_ZH.md delete mode 100644 VERSION delete mode 100644 _examples/README.md delete mode 100644 _examples/apidoc/swagger/README.md delete mode 100644 _examples/apidoc/yaag/go.mod delete mode 100644 _examples/apidoc/yaag/main.go delete mode 100644 _examples/auth/basicauth/main.go delete mode 100644 _examples/auth/basicauth/main_test.go delete mode 100644 _examples/auth/cors/main.go delete mode 100644 _examples/auth/cors/public/index.html delete mode 100644 _examples/auth/cors/public/main.js delete mode 100644 _examples/auth/goth/main.go delete mode 100644 _examples/auth/goth/templates/index.html delete mode 100644 _examples/auth/goth/templates/user.html delete mode 100644 _examples/auth/hcaptcha/hosts delete mode 100644 _examples/auth/hcaptcha/main.go delete mode 100644 _examples/auth/hcaptcha/templates/register_form.html delete mode 100644 _examples/auth/jwt/README.md delete mode 100644 _examples/auth/jwt/main.go delete mode 100644 _examples/auth/jwt/rsa_password_protected.key delete mode 100644 _examples/auth/permissions/main.go delete mode 100644 _examples/auth/recaptcha/custom_form/main.go delete mode 100644 _examples/auth/recaptcha/main.go delete mode 100644 _examples/bootstrapper/bootstrap/bootstrapper.go delete mode 100644 _examples/bootstrapper/folder_structure.png delete mode 100644 _examples/bootstrapper/main.go delete mode 100644 _examples/bootstrapper/main_test.go delete mode 100644 _examples/bootstrapper/middleware/identity/identity.go delete mode 100644 _examples/bootstrapper/public/favicon.ico delete mode 100644 _examples/bootstrapper/routes/follower.go delete mode 100644 _examples/bootstrapper/routes/following.go delete mode 100644 _examples/bootstrapper/routes/index.go delete mode 100644 _examples/bootstrapper/routes/like.go delete mode 100644 _examples/bootstrapper/routes/routes.go delete mode 100644 _examples/bootstrapper/views/index.html delete mode 100644 _examples/bootstrapper/views/shared/error.html delete mode 100644 _examples/bootstrapper/views/shared/layout.html delete mode 100644 _examples/caddy/Caddyfile delete mode 100644 _examples/caddy/README.md delete mode 100644 _examples/caddy/server1/main.go delete mode 100644 _examples/caddy/server1/views/index.html delete mode 100644 _examples/caddy/server1/views/shared/layout.html delete mode 100644 _examples/caddy/server2/main.go delete mode 100644 _examples/compression/client-using-iris/main.go delete mode 100644 _examples/compression/client/main.go delete mode 100644 _examples/compression/main.go delete mode 100644 _examples/compression/main_test.go delete mode 100644 _examples/configuration/from-configuration-structure/main.go delete mode 100644 _examples/configuration/from-toml-file/configs/iris.tml delete mode 100644 _examples/configuration/from-toml-file/main.go delete mode 100644 _examples/configuration/from-yaml-file/configs/iris.yml delete mode 100644 _examples/configuration/from-yaml-file/main.go delete mode 100644 _examples/configuration/from-yaml-file/shared-configuration/main.go delete mode 100644 _examples/configuration/functional/main.go delete mode 100644 _examples/convert-handlers/negroni-like/main.go delete mode 100644 _examples/convert-handlers/nethttp/main.go delete mode 100644 _examples/convert-handlers/real-usecase-raven/wrapping-the-router/main.go delete mode 100644 _examples/convert-handlers/real-usecase-raven/writing-middleware/main.go delete mode 100644 _examples/cookies/basic/main.go delete mode 100644 _examples/cookies/basic/main_test.go delete mode 100644 _examples/cookies/options/main.go delete mode 100644 _examples/cookies/options/main_test.go delete mode 100644 _examples/cookies/securecookie/main.go delete mode 100644 _examples/cookies/securecookie/main_test.go delete mode 100644 _examples/database/mongodb/.env delete mode 100644 _examples/database/mongodb/0_create_movie.png delete mode 100644 _examples/database/mongodb/1_update_movie.png delete mode 100644 _examples/database/mongodb/2_get_all_movies.png delete mode 100644 _examples/database/mongodb/3_get_movie.png delete mode 100644 _examples/database/mongodb/4_delete_movie.png delete mode 100644 _examples/database/mongodb/Dockerfile delete mode 100644 _examples/database/mongodb/README.md delete mode 100644 _examples/database/mongodb/api/store/movie.go delete mode 100644 _examples/database/mongodb/docker-compose.yml delete mode 100644 _examples/database/mongodb/env/env.go delete mode 100644 _examples/database/mongodb/go.mod delete mode 100644 _examples/database/mongodb/httputil/error.go delete mode 100644 _examples/database/mongodb/main.go delete mode 100644 _examples/database/mongodb/store/movie.go delete mode 100644 _examples/database/mysql/Dockerfile delete mode 100644 _examples/database/mysql/README.md delete mode 100644 _examples/database/mysql/api/api.go delete mode 100644 _examples/database/mysql/api/category_handler.go delete mode 100644 _examples/database/mysql/api/helper.go delete mode 100644 _examples/database/mysql/api/httperror.go delete mode 100644 _examples/database/mysql/api/middleware/.gitkeep delete mode 100644 _examples/database/mysql/api/product_handler.go delete mode 100644 _examples/database/mysql/cache/groupcache.go delete mode 100644 _examples/database/mysql/docker-compose.yml delete mode 100644 _examples/database/mysql/entity/category.go delete mode 100644 _examples/database/mysql/entity/product.go delete mode 100644 _examples/database/mysql/go.mod delete mode 100644 _examples/database/mysql/main.go delete mode 100644 _examples/database/mysql/migration/api_category/create_category.json delete mode 100644 _examples/database/mysql/migration/api_category/insert_products_category.json delete mode 100644 _examples/database/mysql/migration/api_category/update_category.json delete mode 100644 _examples/database/mysql/migration/api_category/update_partial_category.json delete mode 100644 _examples/database/mysql/migration/api_postman.json delete mode 100644 _examples/database/mysql/migration/api_product/create_product.json delete mode 100644 _examples/database/mysql/migration/api_product/update_partial_product.json delete mode 100644 _examples/database/mysql/migration/api_product/update_product.json delete mode 100644 _examples/database/mysql/migration/db.sql delete mode 100644 _examples/database/mysql/service/category_service.go delete mode 100644 _examples/database/mysql/service/category_service_test.go delete mode 100644 _examples/database/mysql/service/product_service.go delete mode 100644 _examples/database/mysql/sql/mysql.go delete mode 100644 _examples/database/mysql/sql/service.go delete mode 100644 _examples/database/mysql/sql/sql.go delete mode 100644 _examples/database/orm/gorm/REAMDE.md delete mode 100644 _examples/database/orm/gorm/main.go delete mode 100644 _examples/database/orm/reform/controllers/person_controller.go delete mode 100644 _examples/database/orm/reform/go.mod delete mode 100644 _examples/database/orm/reform/main.go delete mode 100644 _examples/database/orm/reform/models/person.go delete mode 100644 _examples/database/orm/reform/models/person_reform.go delete mode 100644 _examples/database/orm/reform/postman_collection.json delete mode 100644 _examples/database/orm/xorm/main.go delete mode 100644 _examples/dependency-injection/basic/main.go delete mode 100644 _examples/dependency-injection/basic/middleware/main.go delete mode 100644 _examples/dependency-injection/basic/middleware/main_test.go delete mode 100644 _examples/dependency-injection/context-register-dependency/main.go delete mode 100644 _examples/dependency-injection/jwt/contrib/go.mod delete mode 100644 _examples/dependency-injection/jwt/contrib/main.go delete mode 100644 _examples/dependency-injection/jwt/main.go delete mode 100644 _examples/dependency-injection/overview/datamodels/movie.go delete mode 100644 _examples/dependency-injection/overview/datasource/movies.go delete mode 100644 _examples/dependency-injection/overview/main.go delete mode 100644 _examples/dependency-injection/overview/repositories/movie_repository.go delete mode 100644 _examples/dependency-injection/overview/services/movie_service.go delete mode 100644 _examples/dependency-injection/overview/web/middleware/basicauth.go delete mode 100644 _examples/dependency-injection/overview/web/routes/hello.go delete mode 100644 _examples/dependency-injection/overview/web/routes/movies.go delete mode 100644 _examples/dependency-injection/overview/web/views/hello/index.html delete mode 100644 _examples/dependency-injection/overview/web/views/hello/name.html delete mode 100644 _examples/dependency-injection/sessions/main.go delete mode 100644 _examples/dependency-injection/sessions/routes/index.go delete mode 100644 _examples/dependency-injection/smart-contract/main.go delete mode 100644 _examples/desktop/blink/main.go delete mode 100644 _examples/desktop/lorca/main.go delete mode 100644 _examples/desktop/webview/main.go delete mode 100644 _examples/dropzonejs/README.md delete mode 100644 _examples/dropzonejs/README_PART2.md delete mode 100644 _examples/dropzonejs/folder_structure.png delete mode 100644 _examples/dropzonejs/meta.yml delete mode 100644 _examples/dropzonejs/no_files.png delete mode 100644 _examples/dropzonejs/src/main.go delete mode 100644 _examples/dropzonejs/src/public/css/dropzone.css delete mode 100644 _examples/dropzonejs/src/public/js/dropzone.js delete mode 100644 _examples/dropzonejs/src/views/upload.html delete mode 100644 _examples/dropzonejs/with_files.png delete mode 100644 _examples/file-server/basic/assets.system/css/main.css delete mode 100644 _examples/file-server/basic/assets.system/test.txt delete mode 100644 _examples/file-server/basic/assets/app2/app22/just_a_text_no_index.txt delete mode 100644 _examples/file-server/basic/assets/app2/app2app3/index.html delete mode 100644 _examples/file-server/basic/assets/app2/index.html delete mode 100644 _examples/file-server/basic/assets/css/main.css delete mode 100644 _examples/file-server/basic/assets/favicon.ico delete mode 100644 _examples/file-server/basic/assets/index.html delete mode 100644 _examples/file-server/basic/assets/js/main.js delete mode 100644 _examples/file-server/basic/main.go delete mode 100644 _examples/file-server/basic/main_test.go delete mode 100644 _examples/file-server/embedding-files-into-app/assets/css/bootstrap.min.css delete mode 100644 _examples/file-server/embedding-files-into-app/assets/favicon.ico delete mode 100644 _examples/file-server/embedding-files-into-app/assets/js/jquery-2.1.1.js delete mode 100644 _examples/file-server/embedding-files-into-app/bindata.go delete mode 100644 _examples/file-server/embedding-files-into-app/main.go delete mode 100644 _examples/file-server/embedding-files-into-app/main_test.go delete mode 100644 _examples/file-server/embedding-gzipped-files-into-app/bindata.go delete mode 100644 _examples/file-server/embedding-gzipped-files-into-app/main.go delete mode 100644 _examples/file-server/embedding-gzipped-files-into-app/main_test.go delete mode 100644 _examples/file-server/favicon/main.go delete mode 100644 _examples/file-server/favicon/static/favicons/favicon.ico delete mode 100644 _examples/file-server/file-server/main.go delete mode 100644 _examples/file-server/file-server/views/dirlist.html delete mode 100644 _examples/file-server/file-server/views/upload.html delete mode 100644 _examples/file-server/http2push-embedded-gzipped/bindata.go delete mode 100644 _examples/file-server/http2push-embedded-gzipped/main.go delete mode 100644 _examples/file-server/http2push-embedded/bindata.go delete mode 100644 _examples/file-server/http2push-embedded/main.go delete mode 100644 _examples/file-server/http2push/assets/app2/app2app3/css/main.css delete mode 100644 _examples/file-server/http2push/assets/app2/app2app3/dirs/dir1/text.txt delete mode 100644 _examples/file-server/http2push/assets/app2/app2app3/dirs/dir2/text.txt delete mode 100644 _examples/file-server/http2push/assets/app2/app2app3/dirs/text.txt delete mode 100644 _examples/file-server/http2push/assets/app2/app2app3/index.html delete mode 100644 _examples/file-server/http2push/assets/app2/index.html delete mode 100644 _examples/file-server/http2push/assets/app2/mydir/text.txt delete mode 100644 _examples/file-server/http2push/assets/css/main.css delete mode 100644 _examples/file-server/http2push/assets/favicon.ico delete mode 100644 _examples/file-server/http2push/assets/index.html delete mode 100644 _examples/file-server/http2push/assets/js/main.js delete mode 100644 _examples/file-server/http2push/main.go delete mode 100644 _examples/file-server/http2push/mycert.crt delete mode 100644 _examples/file-server/http2push/mykey.key delete mode 100644 _examples/file-server/send-files/files/first.zip delete mode 100644 _examples/file-server/send-files/main.go delete mode 100644 _examples/file-server/single-page-application/basic/main.go delete mode 100644 _examples/file-server/single-page-application/basic/main_test.go delete mode 100644 _examples/file-server/single-page-application/basic/public/app.js delete mode 100644 _examples/file-server/single-page-application/basic/public/css/main.css delete mode 100644 _examples/file-server/single-page-application/basic/public/index.html delete mode 100644 _examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/bindata.go delete mode 100644 _examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/main.go delete mode 100644 _examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/public/app.js delete mode 100644 _examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/public/css/main.css delete mode 100644 _examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/public/index.html delete mode 100644 _examples/file-server/single-page-application/embedded-single-page-application/bindata.go delete mode 100644 _examples/file-server/single-page-application/embedded-single-page-application/main.go delete mode 100644 _examples/file-server/single-page-application/embedded-single-page-application/main_test.go delete mode 100644 _examples/file-server/single-page-application/embedded-single-page-application/public/app.js delete mode 100644 _examples/file-server/single-page-application/embedded-single-page-application/public/app2/index.html delete mode 100644 _examples/file-server/single-page-application/embedded-single-page-application/public/css/main.css delete mode 100644 _examples/file-server/single-page-application/embedded-single-page-application/public/index.html delete mode 100644 _examples/file-server/subdomain/assets/app2/app22/just_a_text_no_index.txt delete mode 100644 _examples/file-server/subdomain/assets/app2/app2app3/index.html delete mode 100644 _examples/file-server/subdomain/assets/app2/index.html delete mode 100644 _examples/file-server/subdomain/assets/css/main.css delete mode 100644 _examples/file-server/subdomain/assets/favicon.ico delete mode 100644 _examples/file-server/subdomain/assets/index.html delete mode 100644 _examples/file-server/subdomain/assets/js/jquery-2.1.1.js delete mode 100644 _examples/file-server/subdomain/hosts delete mode 100644 _examples/file-server/subdomain/main.go delete mode 100644 _examples/file-server/subdomain/main_test.go delete mode 100644 _examples/file-server/upload-file/main.go delete mode 100644 _examples/file-server/upload-file/templates/upload_form.html delete mode 100644 _examples/file-server/upload-file/uploads/.gitkeep delete mode 100644 _examples/file-server/upload-files/main.go delete mode 100644 _examples/file-server/upload-files/main_test.go delete mode 100644 _examples/file-server/upload-files/templates/upload_form.html delete mode 100644 _examples/file-server/upload-files/uploads/.gitkeep delete mode 100644 _examples/http-server/README.md delete mode 100644 _examples/http-server/custom-httpserver/easy-way/main.go delete mode 100644 _examples/http-server/custom-httpserver/multi/main.go delete mode 100644 _examples/http-server/custom-httpserver/std-way/main.go delete mode 100644 _examples/http-server/custom-listener/main.go delete mode 100644 _examples/http-server/graceful-shutdown/custom-notifier/main.go delete mode 100644 _examples/http-server/graceful-shutdown/default-notifier/main.go delete mode 100644 _examples/http-server/http3-quic/go.mod delete mode 100644 _examples/http-server/http3-quic/localhost.cert delete mode 100644 _examples/http-server/http3-quic/localhost.key delete mode 100644 _examples/http-server/http3-quic/main.go delete mode 100644 _examples/http-server/iris-configurator-and-host-configurator/main.go delete mode 100644 _examples/http-server/listen-addr-public/main.go delete mode 100644 _examples/http-server/listen-addr/main.go delete mode 100644 _examples/http-server/listen-addr/omit-server-errors/main.go delete mode 100644 _examples/http-server/listen-addr/omit-server-errors/main_test.go delete mode 100644 _examples/http-server/listen-letsencrypt/main.go delete mode 100644 _examples/http-server/listen-tls/main.go delete mode 100644 _examples/http-server/listen-tls/mycert.crt delete mode 100644 _examples/http-server/listen-tls/mykey.key delete mode 100644 _examples/http-server/listen-unix/main.go delete mode 100644 _examples/http-server/notify-on-shutdown/main.go delete mode 100644 _examples/http-server/socket-sharding/main.go delete mode 100644 _examples/i18n/hosts delete mode 100644 _examples/i18n/locales/el-GR/locale_el-GR.ini delete mode 100644 _examples/i18n/locales/el-GR/locale_multi_first_el-GR.ini delete mode 100644 _examples/i18n/locales/el-GR/locale_multi_second_el-GR.ini delete mode 100644 _examples/i18n/locales/en-US/locale_en-US.ini delete mode 100644 _examples/i18n/locales/en-US/locale_multi_first_en-US.ini delete mode 100644 _examples/i18n/locales/en-US/locale_multi_second_en-US.ini delete mode 100644 _examples/i18n/locales/zh-CN/locale_zh-CN.ini delete mode 100644 _examples/i18n/main.go delete mode 100644 _examples/i18n/main_test.go delete mode 100644 _examples/i18n/views/index.html delete mode 100644 _examples/kafka-api/0_docs.png delete mode 100644 _examples/kafka-api/1_create_topic.png delete mode 100644 _examples/kafka-api/2_list_topics.png delete mode 100644 _examples/kafka-api/3_store_to_topic.png delete mode 100644 _examples/kafka-api/4_retrieve_from_topic_real_time.png delete mode 100644 _examples/kafka-api/Dockerfile delete mode 100644 _examples/kafka-api/README.md delete mode 100644 _examples/kafka-api/docker-compose.yml delete mode 100644 _examples/kafka-api/go.mod delete mode 100644 _examples/kafka-api/main.go delete mode 100644 _examples/logging/file-logger/main.go delete mode 100644 _examples/logging/json-logger/main.go delete mode 100644 _examples/logging/json-logger/main_test.go delete mode 100644 _examples/logging/request-logger/main.go delete mode 100644 _examples/logging/request-logger/request-logger-file-json/main.go delete mode 100644 _examples/logging/request-logger/request-logger-file/main.go delete mode 100644 _examples/logging/rollbar/go.mod delete mode 100644 _examples/logging/rollbar/main.go delete mode 100644 _examples/mvc/authenticated-controller/main.go delete mode 100644 _examples/mvc/authenticated-controller/main_test.go delete mode 100644 _examples/mvc/basic/main.go delete mode 100644 _examples/mvc/basic/wildcard/main.go delete mode 100644 _examples/mvc/error-handler/main.go delete mode 100644 _examples/mvc/grpc-compatible/README.md delete mode 100644 _examples/mvc/grpc-compatible/grpc-client/main.go delete mode 100644 _examples/mvc/grpc-compatible/helloworld/README.md delete mode 100644 _examples/mvc/grpc-compatible/helloworld/helloworld.pb.go delete mode 100644 _examples/mvc/grpc-compatible/helloworld/helloworld.proto delete mode 100644 _examples/mvc/grpc-compatible/http-client/main.go delete mode 100644 _examples/mvc/grpc-compatible/main.go delete mode 100644 _examples/mvc/grpc-compatible/main_test.go delete mode 100644 _examples/mvc/grpc-compatible/server.crt delete mode 100644 _examples/mvc/grpc-compatible/server.key delete mode 100644 _examples/mvc/hello-world/main.go delete mode 100644 _examples/mvc/hello-world/main_test.go delete mode 100644 _examples/mvc/login-mvc-single-responsibility/folder_structure.png delete mode 100644 _examples/mvc/login-mvc-single-responsibility/main.go delete mode 100644 _examples/mvc/login-mvc-single-responsibility/public/css/site.css delete mode 100644 _examples/mvc/login-mvc-single-responsibility/user/auth.go delete mode 100644 _examples/mvc/login-mvc-single-responsibility/user/controller.go delete mode 100644 _examples/mvc/login-mvc-single-responsibility/user/datasource.go delete mode 100644 _examples/mvc/login-mvc-single-responsibility/user/model.go delete mode 100644 _examples/mvc/login-mvc-single-responsibility/views/shared/error.html delete mode 100644 _examples/mvc/login-mvc-single-responsibility/views/shared/layout.html delete mode 100644 _examples/mvc/login-mvc-single-responsibility/views/user/login.html delete mode 100644 _examples/mvc/login-mvc-single-responsibility/views/user/me.html delete mode 100644 _examples/mvc/login-mvc-single-responsibility/views/user/notfound.html delete mode 100644 _examples/mvc/login-mvc-single-responsibility/views/user/register.html delete mode 100644 _examples/mvc/login/datamodels/user.go delete mode 100644 _examples/mvc/login/datasource/users.go delete mode 100644 _examples/mvc/login/folder_structure.png delete mode 100644 _examples/mvc/login/main.go delete mode 100644 _examples/mvc/login/repositories/user_repository.go delete mode 100644 _examples/mvc/login/services/user_service.go delete mode 100644 _examples/mvc/login/web/controllers/user_controller.go delete mode 100644 _examples/mvc/login/web/controllers/users_controller.go delete mode 100644 _examples/mvc/login/web/middleware/basicauth.go delete mode 100644 _examples/mvc/login/web/public/css/site.css delete mode 100644 _examples/mvc/login/web/viewmodels/README.md delete mode 100644 _examples/mvc/login/web/views/shared/error.html delete mode 100644 _examples/mvc/login/web/views/shared/layout.html delete mode 100644 _examples/mvc/login/web/views/user/login.html delete mode 100644 _examples/mvc/login/web/views/user/me.html delete mode 100644 _examples/mvc/login/web/views/user/register.html delete mode 100644 _examples/mvc/middleware/main.go delete mode 100644 _examples/mvc/middleware/per-method/main.go delete mode 100644 _examples/mvc/middleware/without-ctx-next/main.go delete mode 100644 _examples/mvc/overview/Dockerfile delete mode 100644 _examples/mvc/overview/README.md delete mode 100644 _examples/mvc/overview/controller/greet_controller.go delete mode 100644 _examples/mvc/overview/database/database.go delete mode 100644 _examples/mvc/overview/database/mysql.go delete mode 100644 _examples/mvc/overview/database/sqlite.go delete mode 100644 _examples/mvc/overview/docker-compose.yml delete mode 100644 _examples/mvc/overview/environment/environment.go delete mode 100644 _examples/mvc/overview/go.mod delete mode 100644 _examples/mvc/overview/main.go delete mode 100644 _examples/mvc/overview/model/request.go delete mode 100644 _examples/mvc/overview/model/response.go delete mode 100644 _examples/mvc/overview/service/greet_service.go delete mode 100644 _examples/mvc/regexp/main.go delete mode 100644 _examples/mvc/repository/datamodels/README.md delete mode 100644 _examples/mvc/repository/datamodels/movie.go delete mode 100644 _examples/mvc/repository/datasource/README.md delete mode 100644 _examples/mvc/repository/datasource/movies.go delete mode 100644 _examples/mvc/repository/folder_structure.png delete mode 100644 _examples/mvc/repository/main.go delete mode 100644 _examples/mvc/repository/models/README.md delete mode 100644 _examples/mvc/repository/repositories/README.md delete mode 100644 _examples/mvc/repository/repositories/movie_repository.go delete mode 100644 _examples/mvc/repository/services/README.md delete mode 100644 _examples/mvc/repository/services/movie_service.go delete mode 100644 _examples/mvc/repository/web/controllers/hello_controller.go delete mode 100644 _examples/mvc/repository/web/controllers/movie_controller.go delete mode 100644 _examples/mvc/repository/web/middleware/basicauth.go delete mode 100644 _examples/mvc/repository/web/viewmodels/README.md delete mode 100644 _examples/mvc/repository/web/views/hello/index.html delete mode 100644 _examples/mvc/repository/web/views/hello/name.html delete mode 100644 _examples/mvc/session-controller/main.go delete mode 100644 _examples/mvc/session-controller/main_test.go delete mode 100644 _examples/mvc/singleton/main.go delete mode 100644 _examples/mvc/versioned-controller/main.go delete mode 100644 _examples/mvc/versioned-controller/main_test.go delete mode 100644 _examples/mvc/vuejs-todo-mvc/README.md delete mode 100644 _examples/mvc/vuejs-todo-mvc/screen.png delete mode 100644 _examples/mvc/vuejs-todo-mvc/src/todo/item.go delete mode 100644 _examples/mvc/vuejs-todo-mvc/src/todo/service.go delete mode 100644 _examples/mvc/vuejs-todo-mvc/src/web/controllers/todo_controller.go delete mode 100644 _examples/mvc/vuejs-todo-mvc/src/web/main.go delete mode 100644 _examples/mvc/vuejs-todo-mvc/src/web/public/css/index delete mode 100644 _examples/mvc/vuejs-todo-mvc/src/web/public/index.html delete mode 100644 _examples/mvc/vuejs-todo-mvc/src/web/public/js/app.js delete mode 100644 _examples/mvc/vuejs-todo-mvc/src/web/public/js/lib/vue delete mode 100644 _examples/mvc/websocket/browser/index.html delete mode 100644 _examples/mvc/websocket/main.go delete mode 100644 _examples/pprof/main.go delete mode 100644 _examples/recover/main.go delete mode 100644 _examples/request-body/read-body/main.go delete mode 100644 _examples/request-body/read-body/main_test.go delete mode 100644 _examples/request-body/read-custom-per-type/main.go delete mode 100644 _examples/request-body/read-custom-per-type/main_test.go delete mode 100644 _examples/request-body/read-custom-via-unmarshaler/main.go delete mode 100644 _examples/request-body/read-custom-via-unmarshaler/main_test.go delete mode 100644 _examples/request-body/read-form/main.go delete mode 100644 _examples/request-body/read-form/templates/form.html delete mode 100644 _examples/request-body/read-json-struct-validation/main.go delete mode 100644 _examples/request-body/read-json/main.go delete mode 100644 _examples/request-body/read-many/main.go delete mode 100644 _examples/request-body/read-msgpack/main.go delete mode 100644 _examples/request-body/read-query/main.go delete mode 100644 _examples/request-body/read-xml/main.go delete mode 100644 _examples/request-body/read-xml/main_test.go delete mode 100644 _examples/request-body/read-yaml/main.go delete mode 100644 _examples/request-body/read-yaml/main_test.go delete mode 100644 _examples/request-ratelimit/main.go delete mode 100644 _examples/request-referrer/main.go delete mode 100644 _examples/response-writer/cache/client-side/main.go delete mode 100644 _examples/response-writer/cache/simple/main.go delete mode 100644 _examples/response-writer/content-negotiation/main.go delete mode 100644 _examples/response-writer/content-negotiation/main_test.go delete mode 100644 _examples/response-writer/http2push/main.go delete mode 100644 _examples/response-writer/http2push/mycert.crt delete mode 100644 _examples/response-writer/http2push/mykey.key delete mode 100644 _examples/response-writer/http2push/public/main.js delete mode 100644 _examples/response-writer/protobuf/README.md delete mode 100644 _examples/response-writer/protobuf/go.mod delete mode 100644 _examples/response-writer/protobuf/main.go delete mode 100644 _examples/response-writer/protobuf/protos/hello.pb.go delete mode 100644 _examples/response-writer/protobuf/protos/hello.proto delete mode 100644 _examples/response-writer/sse-third-party/main.go delete mode 100644 _examples/response-writer/sse/main.go delete mode 100644 _examples/response-writer/sse/optional.sse.mini.js.html delete mode 100644 _examples/response-writer/stream-writer/main.go delete mode 100644 _examples/response-writer/transactions/main.go delete mode 100644 _examples/response-writer/write-rest/main.go delete mode 100644 _examples/routing/README.md delete mode 100644 _examples/routing/basic/.dockerignore delete mode 100644 _examples/routing/basic/Dockerfile delete mode 100644 _examples/routing/basic/README.md delete mode 100644 _examples/routing/basic/docker-compose.yml delete mode 100644 _examples/routing/basic/main.go delete mode 100644 _examples/routing/basic/main_test.go delete mode 100644 _examples/routing/conditional-chain/main.go delete mode 100644 _examples/routing/conditional-chain/main_test.go delete mode 100644 _examples/routing/custom-router/main.go delete mode 100644 _examples/routing/custom-wrapper/main.go delete mode 100644 _examples/routing/custom-wrapper/main_test.go delete mode 100644 _examples/routing/custom-wrapper/public/app.js delete mode 100644 _examples/routing/custom-wrapper/public/css/main.css delete mode 100644 _examples/routing/custom-wrapper/public/index.html delete mode 100644 _examples/routing/dynamic-path/main.go delete mode 100644 _examples/routing/dynamic-path/root-wildcard/main.go delete mode 100644 _examples/routing/dynamic-path/same-pattern-different-func/main.go delete mode 100644 _examples/routing/dynamic-path/same-pattern-different-func/main_test.go delete mode 100644 _examples/routing/dynamic-path/same-pattern-different-func/use-global/main.go delete mode 100644 _examples/routing/dynamic-path/same-pattern-different-func/use-global/main_test.go delete mode 100644 _examples/routing/hello-world/main.go delete mode 100644 _examples/routing/http-errors/main.go delete mode 100644 _examples/routing/http-errors/reset-body/main.go delete mode 100644 _examples/routing/http-errors/reset-body/main_test.go delete mode 100644 _examples/routing/intelligence/main.go delete mode 100644 _examples/routing/intelligence/manual/main.go delete mode 100644 _examples/routing/macros/main.go delete mode 100644 _examples/routing/main.go delete mode 100644 _examples/routing/main_test.go delete mode 100644 _examples/routing/overview-2/main.go delete mode 100644 _examples/routing/overview-2/views/user/create_verification.html delete mode 100644 _examples/routing/overview-2/views/user/profile.html delete mode 100644 _examples/routing/overview/main.go delete mode 100644 _examples/routing/overview/public/assets/css/main.css delete mode 100644 _examples/routing/overview/public/images/favicon.ico delete mode 100644 _examples/routing/reverse/main.go delete mode 100644 _examples/routing/route-handlers-execution-rules/main.go delete mode 100644 _examples/routing/route-register-rule/main.go delete mode 100644 _examples/routing/route-register-rule/main_test.go delete mode 100644 _examples/routing/route-state/main.go delete mode 100644 _examples/routing/sitemap/main.go delete mode 100644 _examples/routing/sitemap/main_test.go delete mode 100644 _examples/routing/subdomains/multi/hosts delete mode 100644 _examples/routing/subdomains/multi/main.go delete mode 100644 _examples/routing/subdomains/multi/public/assets/images/test.ico delete mode 100644 _examples/routing/subdomains/multi/public/upload_resources/favicon.ico delete mode 100644 _examples/routing/subdomains/redirect/hosts delete mode 100644 _examples/routing/subdomains/redirect/main.go delete mode 100644 _examples/routing/subdomains/redirect/main_test.go delete mode 100644 _examples/routing/subdomains/single/hosts delete mode 100644 _examples/routing/subdomains/single/main.go delete mode 100644 _examples/routing/subdomains/wildcard/hosts delete mode 100644 _examples/routing/subdomains/wildcard/main.go delete mode 100644 _examples/routing/subdomains/www/hosts delete mode 100644 _examples/routing/subdomains/www/main.go delete mode 100644 _examples/routing/subdomains/www/main_test.go delete mode 100644 _examples/routing/versioning/main.go delete mode 100644 _examples/routing/writing-a-middleware/globally/main.go delete mode 100644 _examples/routing/writing-a-middleware/per-route/main.go delete mode 100644 _examples/sessions/basic/main.go delete mode 100644 _examples/sessions/database/badger/main.go delete mode 100644 _examples/sessions/database/boltdb/main.go delete mode 100644 _examples/sessions/database/redis/Dockerfile delete mode 100644 _examples/sessions/database/redis/docker-compose.yml delete mode 100644 _examples/sessions/database/redis/go.mod delete mode 100644 _examples/sessions/database/redis/main.go delete mode 100644 _examples/sessions/flash-messages/main.go delete mode 100644 _examples/sessions/overview/example/example.go delete mode 100644 _examples/sessions/overview/main.go delete mode 100644 _examples/sessions/securecookie/main.go delete mode 100644 _examples/sessions/securecookie/main_test.go delete mode 100644 _examples/testing/httptest/main.go delete mode 100644 _examples/testing/httptest/main_test.go delete mode 100644 _examples/url-shortener/README.md delete mode 100644 _examples/url-shortener/factory.go delete mode 100644 _examples/url-shortener/main.go delete mode 100644 _examples/url-shortener/main_test.go delete mode 100644 _examples/url-shortener/resources/css/style.css delete mode 100644 _examples/url-shortener/store.go delete mode 100644 _examples/url-shortener/templates/index.html delete mode 100644 _examples/view/context-view-data/main.go delete mode 100644 _examples/view/context-view-data/templates/index.html delete mode 100644 _examples/view/context-view-data/templates/layouts/layout.html delete mode 100644 _examples/view/context-view-engine/main.go delete mode 100644 _examples/view/context-view-engine/views/admin/index.html delete mode 100644 _examples/view/context-view-engine/views/admin/layouts/main.html delete mode 100644 _examples/view/context-view-engine/views/on-fly/index.html delete mode 100644 _examples/view/context-view-engine/views/public/500.html delete mode 100644 _examples/view/context-view-engine/views/public/index.html delete mode 100644 _examples/view/context-view-engine/views/public/layouts/error.html delete mode 100644 _examples/view/context-view-engine/views/public/layouts/main.html delete mode 100644 _examples/view/context-view-engine/views/public/partials/footer.html delete mode 100644 _examples/view/embedding-templates-into-app/bindata.go delete mode 100644 _examples/view/embedding-templates-into-app/main.go delete mode 100644 _examples/view/embedding-templates-into-app/templates/layouts/layout.html delete mode 100644 _examples/view/embedding-templates-into-app/templates/layouts/mylayout.html delete mode 100644 _examples/view/embedding-templates-into-app/templates/page1.html delete mode 100644 _examples/view/embedding-templates-into-app/templates/partials/page1_partial1.html delete mode 100644 _examples/view/herotemplate/README.md delete mode 100644 _examples/view/herotemplate/app.go delete mode 100644 _examples/view/herotemplate/template/index.html delete mode 100644 _examples/view/herotemplate/template/index.html.go delete mode 100644 _examples/view/herotemplate/template/user.html delete mode 100644 _examples/view/herotemplate/template/user.html.go delete mode 100644 _examples/view/herotemplate/template/userlist.html delete mode 100644 _examples/view/herotemplate/template/userlist.html.go delete mode 100644 _examples/view/herotemplate/template/userlistwriter.html delete mode 100644 _examples/view/herotemplate/template/userlistwriter.html.go delete mode 100644 _examples/view/overview/main.go delete mode 100644 _examples/view/overview/templates/hi.html delete mode 100644 _examples/view/quicktemplate/README.md delete mode 100644 _examples/view/quicktemplate/controllers/execute_template.go delete mode 100644 _examples/view/quicktemplate/controllers/hello.go delete mode 100644 _examples/view/quicktemplate/controllers/index.go delete mode 100644 _examples/view/quicktemplate/main.go delete mode 100644 _examples/view/quicktemplate/main_test.go delete mode 100644 _examples/view/quicktemplate/models/.gitkeep delete mode 100644 _examples/view/quicktemplate/templates/base.qtpl delete mode 100644 _examples/view/quicktemplate/templates/base.qtpl.go delete mode 100644 _examples/view/quicktemplate/templates/hello.qtpl delete mode 100644 _examples/view/quicktemplate/templates/hello.qtpl.go delete mode 100644 _examples/view/quicktemplate/templates/index.qtpl delete mode 100644 _examples/view/quicktemplate/templates/index.qtpl.go delete mode 100644 _examples/view/template_ace_0/main.go delete mode 100644 _examples/view/template_ace_0/views/index.ace delete mode 100644 _examples/view/template_ace_0/views/layouts/main.ace delete mode 100644 _examples/view/template_ace_0/views/partials/footer.ace delete mode 100644 _examples/view/template_ace_0/views/partials/header.ace delete mode 100644 _examples/view/template_blocks_0/main.go delete mode 100644 _examples/view/template_blocks_0/views/500.html delete mode 100644 _examples/view/template_blocks_0/views/index.html delete mode 100644 _examples/view/template_blocks_0/views/layouts/error.html delete mode 100644 _examples/view/template_blocks_0/views/layouts/main.html delete mode 100644 _examples/view/template_blocks_0/views/partials/footer.html delete mode 100644 _examples/view/template_blocks_1_embedded/bindata.go delete mode 100644 _examples/view/template_blocks_1_embedded/main.go delete mode 100644 _examples/view/template_django_0/main.go delete mode 100644 _examples/view/template_django_0/templates/hi.html delete mode 100644 _examples/view/template_html_0/main.go delete mode 100644 _examples/view/template_html_0/templates/hi.html delete mode 100644 _examples/view/template_html_1/main.go delete mode 100644 _examples/view/template_html_1/templates/layout.html delete mode 100644 _examples/view/template_html_1/templates/mypage.html delete mode 100644 _examples/view/template_html_2/README.md delete mode 100644 _examples/view/template_html_2/main.go delete mode 100644 _examples/view/template_html_2/templates/layouts/layout.html delete mode 100644 _examples/view/template_html_2/templates/layouts/mylayout.html delete mode 100644 _examples/view/template_html_2/templates/page1.html delete mode 100644 _examples/view/template_html_2/templates/partials/page1_partial1.html delete mode 100644 _examples/view/template_html_3/main.go delete mode 100644 _examples/view/template_html_3/templates/page.html delete mode 100644 _examples/view/template_html_4/hosts delete mode 100644 _examples/view/template_html_4/main.go delete mode 100644 _examples/view/template_html_4/templates/page.html delete mode 100644 _examples/view/template_html_5/main.go delete mode 100644 _examples/view/template_html_5/views/about.html delete mode 100644 _examples/view/template_html_5/views/home.html delete mode 100644 _examples/view/template_html_5/views/layout.html delete mode 100644 _examples/view/template_html_5/views/user/index.html delete mode 100644 _examples/view/template_jet_0/README.md delete mode 100644 _examples/view/template_jet_0/main.go delete mode 100644 _examples/view/template_jet_0/views/layouts/application.jet delete mode 100644 _examples/view/template_jet_0/views/todos/index.jet delete mode 100644 _examples/view/template_jet_0/views/todos/show.jet delete mode 100644 _examples/view/template_jet_1_embedded/README.md delete mode 100644 _examples/view/template_jet_1_embedded/bindata.go delete mode 100644 _examples/view/template_jet_1_embedded/main.go delete mode 100644 _examples/view/template_jet_1_embedded/views/includes/_partial.jet delete mode 100644 _examples/view/template_jet_1_embedded/views/includes/blocks.jet delete mode 100644 _examples/view/template_jet_1_embedded/views/index.jet delete mode 100644 _examples/view/template_jet_1_embedded/views/layouts/application.jet delete mode 100644 _examples/view/template_jet_2/main.go delete mode 100644 _examples/view/template_jet_2/views/page.jet delete mode 100644 _examples/view/template_jet_3/main.go delete mode 100644 _examples/view/template_jet_3/views/index.jet delete mode 100644 _examples/view/template_pug_0/main.go delete mode 100644 _examples/view/template_pug_0/templates/index.pug delete mode 100644 _examples/view/template_pug_1/main.go delete mode 100644 _examples/view/template_pug_1/templates/index.pug delete mode 100644 _examples/view/template_pug_2/main.go delete mode 100644 _examples/view/template_pug_2/templates/footer.pug delete mode 100644 _examples/view/template_pug_2/templates/header.pug delete mode 100644 _examples/view/template_pug_2/templates/index.pug delete mode 100644 _examples/view/template_pug_3/bindata.go delete mode 100644 _examples/view/template_pug_3/main.go delete mode 100644 _examples/view/template_pug_3/templates/index.pug delete mode 100644 _examples/view/template_pug_3/templates/layout.pug delete mode 100644 _examples/view/write-to/main.go delete mode 100644 _examples/view/write-to/views/email/simple.html delete mode 100644 _examples/view/write-to/views/shared/email.html delete mode 100644 _examples/webassembly/client/go-wasm-runtime.js delete mode 100644 _examples/webassembly/client/hello.html delete mode 100644 _examples/webassembly/client/hello_go114.go delete mode 100644 _examples/webassembly/client/main.js delete mode 100644 _examples/webassembly/main.go delete mode 100644 _examples/websocket/README.md delete mode 100644 _examples/websocket/basic/README.md delete mode 100644 _examples/websocket/basic/browser/index.html delete mode 100644 _examples/websocket/basic/browserify/app.js delete mode 100644 _examples/websocket/basic/browserify/bundle.js delete mode 100644 _examples/websocket/basic/browserify/client.html delete mode 100644 _examples/websocket/basic/browserify/package.json delete mode 100644 _examples/websocket/basic/go-client/client.go delete mode 100644 _examples/websocket/basic/go.mod delete mode 100644 _examples/websocket/basic/nodejs-client/client.js delete mode 100644 _examples/websocket/basic/nodejs-client/package.json delete mode 100644 _examples/websocket/basic/overview.png delete mode 100644 _examples/websocket/basic/server.go delete mode 100644 _examples/websocket/gorilla-filewatch/go.mod delete mode 100644 _examples/websocket/gorilla-filewatch/main.go delete mode 100644 _examples/websocket/gorilla-filewatch/testfile.txt delete mode 100644 _examples/websocket/gorilla-filewatch/views/home.html delete mode 100644 _examples/websocket/native-messages/main.go delete mode 100644 _examples/websocket/native-messages/static/js/chat.js delete mode 100644 _examples/websocket/native-messages/templates/client.html delete mode 100644 _examples/websocket/online-visitors/main.go delete mode 100644 _examples/websocket/online-visitors/static/assets/js/visitors.js delete mode 100644 _examples/websocket/online-visitors/templates/index.html delete mode 100644 _examples/websocket/online-visitors/templates/other.html delete mode 100644 _examples/websocket/secure/README.md delete mode 100644 _examples/websocket/socketio/asset/index.html delete mode 100644 _examples/websocket/socketio/go.mod delete mode 100644 _examples/websocket/socketio/main.go delete mode 100644 cache/browser_test.go delete mode 100644 cache/cache_test.go delete mode 100644 configuration_test.go delete mode 100644 core/errgroup/errgroup_test.go delete mode 100644 core/handlerconv/from_std_test.go delete mode 100644 core/host/proxy_test.go delete mode 100644 core/host/supervisor_task_example_test.go delete mode 100644 core/host/supervisor_test.go delete mode 100644 core/memstore/memstore_test.go delete mode 100644 core/netutil/addr_test.go delete mode 100644 core/netutil/ip_test.go delete mode 100644 core/router/api_builder_benchmark_test.go delete mode 100644 core/router/handler_execution_rules_test.go delete mode 100644 core/router/path_test.go delete mode 100644 core/router/route_register_rule_test.go delete mode 100644 core/router/route_test.go delete mode 100644 core/router/router_handlers_order_test.go delete mode 100644 core/router/router_test.go delete mode 100644 core/router/router_wildcard_root_test.go delete mode 100644 core/router/router_wrapper_test.go delete mode 100644 core/router/status_test.go delete mode 100644 doc.go delete mode 100644 hero/binding_test.go delete mode 100644 hero/container_test.go delete mode 100644 hero/dependency_test.go delete mode 100644 hero/func_result_test.go delete mode 100644 hero/handler_test.go delete mode 100644 hero/param_test.go delete mode 100644 hero/reflect_test.go delete mode 100644 hero/struct_test.go delete mode 100644 macro/handler/handler_test.go delete mode 100644 macro/interpreter/lexer/lexer_test.go delete mode 100644 macro/interpreter/parser/parser_test.go delete mode 100644 macro/macro_test.go delete mode 100644 middleware/jwt/jwt_test.go delete mode 100644 middleware/methodoverride/methodoverride_test.go delete mode 100644 middleware/requestid/requestid_test.go delete mode 100644 mvc/controller_handle_test.go delete mode 100644 mvc/controller_method_result_test.go delete mode 100644 mvc/controller_test.go delete mode 100644 sessions/sessions_test.go delete mode 100644 versioning/deprecation_test.go delete mode 100644 versioning/version_test.go delete mode 100644 versioning/versioning_test.go diff --git a/.fossa.yml b/.fossa.yml deleted file mode 100644 index cb3f48ee..00000000 --- a/.fossa.yml +++ /dev/null @@ -1,11 +0,0 @@ -version: 2 -cli: - server: https://app.fossa.com - fetcher: custom - project: https://github.com/kataras/iris.git -analyze: - modules: - - name: iris - type: go - target: . - path: . \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 680144f5..d0118e62 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -2,7 +2,7 @@ Examples for the Iris project can be found at . Documentation for the Iris project can be found at -. +. Love iris? Please consider supporting the project: 👉 https://iris-go.com/donate diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b1ecdfba..e26c40a5 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -30,7 +30,7 @@ Please make sure the bug is reproducible over the `master` branch: ```sh $ cd PROJECT -$ go get -u github.com/kataras/iris/v12@master +$ go get -u github.com/kataras/iris@master $ go run . ``` diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 579e611b..00000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -sudo: false -language: go - -os: - - linux - - osx -go: - - 1.14.x - - 1.15.x - - master -go_import_path: github.com/kataras/iris/v12 -env: - global: - - GO111MODULE=on -install: - - go get ./... -script: - - go test -count=1 -v -cover -race ./... -after_script: - # examples - - cd ./_examples - - go get ./... - - go test -count=1 -v -cover -race ./... - - cd ../ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index d2b9a657..00000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,74 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or -advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at kataras2006@hotmail.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index a2d19c61..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,33 +0,0 @@ -# Contributing - -First of all read our [Code of Conduct](https://github.com/kataras/iris/blob/master/CODE_OF_CONDUCT.md). - -## PR - -1. Open a new [issue](https://github.com/kataras/iris/issues/new) - * Write version of your local Iris. - * Write version of your local Go programming language. - * Describe your problem, what did you expect to see and what you see instead. - * If it's a feature request, describe your idea as better as you can - * optionally, navigate to the [chat](https://chat.iris-go.com) to push other members to participate and share their thoughts about your brilliant idea. -2. Fork the [repository](https://github.com/kataras/iris). -3. Make your changes. -4. Compare & Push the PR from [here](https://github.com/kataras/iris/compare). - -## Translate - -We need your help with translations into your native language. - -Iris needs your help, please think about contributing to the translation of the [README](README.md) and https://iris-go.com, you will be rewarded. - -Instructions can be found at: https://github.com/kataras/iris/issues/796 - -## Share - -### Writing - -Write an article about Iris in https://medium.com , https://dev.to or if you're being a hackathon at https://hackernoon.com, some [examples](https://github.com/kataras/iris/wiki/Publications). - -### Social networks - -If you're part of any social network, do a post(or tweet if twitter) about Iris and what you love about it, many examples can be found, the most recent one is [that](https://twitter.com/DorMoshe/status/1154486477247508480). diff --git a/FAQ.md b/FAQ.md deleted file mode 100644 index 3703c32a..00000000 --- a/FAQ.md +++ /dev/null @@ -1,56 +0,0 @@ -# FAQ - -## [![iris](https://img.shields.io/badge/iris-powered-2196f3.svg?style=for-the-badge)](https://github.com/kataras/iris) - -Add a `badge` to your open-source projects powered by [Iris](https://iris-go.com) by pasting the below code snippet to the project repo's README.md: - -```md -[![iris](https://img.shields.io/badge/iris-powered-2196f3.svg?style=for-the-badge)](https://github.com/kataras/iris) -``` - -## Editors & IDEs Extensions - -### Visual Studio Code - - - -> Please feel free to list your own Iris extension(s) here by [PR](https://github.com/kataras/iris/pulls) - -## How to upgrade - -```sh -go get -u github.com/kataras/iris/v12@master -``` - -Go version 1.13 and above is required. - -## Learning - -More than 180 practical examples, tutorials and articles at: - -- https://iris-go.com/start -- https://bit.ly/iris-req-book -- https://github.com/kataras/iris/wiki/Starter-kits -- https://github.com/kataras/iris/tree/master/_examples -- https://godoc.org/github.com/kataras/iris - -## Active development mode - -Iris may have reached version 12, but we're not stopping there. We have many feature ideas on our board that we're anxious to add and other innovative web development solutions that we're planning to build into Iris. - -## Can I find a job if I learn how to use Iris? - -Yes, not only because you will learn Golang in the same time, but there are some positions -open for Iris-specific developers the time we speak. - -Go to our facebook page, like it and receive notifications about new job offers, we already have couple of them stay at the top of the page: https://www.facebook.com/iris.framework - -## Do we have a Community chat? - -Yes, https://chat.iris-go.com - -## How is the development of Iris economically supported? - -By people like you, who help us by donating small or large amounts of money. - -Help this project deliver awesome and unique features with the highest possible code quality by donating any amount via [PayPal](https://iris-go.com/donate). Your name will be published [here](https://iris-go.com) after your approval via e-mail. diff --git a/HISTORY.md b/HISTORY.md deleted file mode 100644 index d4deb1ac..00000000 --- a/HISTORY.md +++ /dev/null @@ -1,829 +0,0 @@ - - -# Changelog - -### Looking for free and real-time support? - - https://github.com/kataras/iris/issues - https://chat.iris-go.com - -### Looking for previous versions? - - https://github.com/kataras/iris/releases - -### Want to be hired? - - https://facebook.com/iris.framework - -### Should I upgrade my Iris? - -Developers are not forced to upgrade if they don't really need it. Upgrade whenever you feel ready. - -**How to upgrade**: Open your command-line and execute this command: `go get github.com/kataras/iris/v12@latest`. - -# Next - -This release introduces new features and some breaking changes inside the `mvc` and `hero` packages. -The codebase for dependency injection has been simplified a lot (fewer LOCs and easier to read and follow up). - -The new release contains a fresh new and awesome feature....**a function dependency can accept previous registered dependencies and update or return a new value of any type**. - -The new implementation is **faster** on both design and serve-time. - -The most common scenario from a route to handle is to: -- accept one or more path parameters and request data, a payload -- send back a response, a payload (JSON, XML,...) - -The new Iris Dependency Injection feature is about **33.2% faster** than its predecessor on the above case. This drops down even more the performance cost between native handlers and dynamic handlers with dependencies. This reason itself brings us, with safety and performance-wise, to the new `Party.ConfigureContainer(builder ...func(*iris.APIContainer)) *APIContainer` method which returns methods such as `Handle(method, relativePath string, handlersFn ...interface{}) *Route` and `RegisterDependency`. - -Look how clean your codebase can be when using Iris': - -```go -package main - -import "github.com/kataras/iris/v12" - -type ( - testInput struct { - Email string `json:"email"` - } - - testOutput struct { - ID int `json:"id"` - Name string `json:"name"` - } -) - -func handler(id int, in testInput) testOutput { - return testOutput{ - ID: id, - Name: in.Email, - } -} - -func main() { - app := iris.New() - app.ConfigureContainer(func(api *iris.APIContainer) { - api.Post("/{id:int}", handler) - }) - app.Listen(":5000", iris.WithOptimizations) -} -``` - -Your eyes don't lie you. You read well, no `ctx.ReadJSON(&v)` and `ctx.JSON(send)` neither `error` handling are presented. It is a huge relief but if you ever need, you still have the control over those, even errors from dependencies. Here is a quick list of the new Party.ConfigureContainer()'s fields and methods: - -```go -// Container holds the DI Container of this Party featured Dependency Injection. -// Use it to manually convert functions or structs(controllers) to a Handler. -Container *hero.Container -``` - -```go -// OnError adds an error handler for this Party's DI Hero Container and its handlers (or controllers). -// The "errorHandler" handles any error may occurred and returned -// during dependencies injection of the Party's hero handlers or from the handlers themselves. -OnError(errorHandler func(iris.Context, error)) -``` - -```go -// RegisterDependency adds a dependency. -// The value can be a single struct value or a function. -// Follow the rules: -// * {structValue} -// * func(accepts ) returns or (, error) -// * func(accepts iris.Context) returns or (, error) -// -// A Dependency can accept a previous registered dependency and return a new one or the same updated. -// * func(accepts1 , accepts2 ) returns or (, error) or error -// * func(acceptsPathParameter1 string, id uint64) returns or (, error) -// -// Usage: -// -// - RegisterDependency(loggerService{prefix: "dev"}) -// - RegisterDependency(func(ctx iris.Context) User {...}) -// - RegisterDependency(func(User) OtherResponse {...}) -RegisterDependency(dependency interface{}) - -// UseResultHandler adds a result handler to the Container. -// A result handler can be used to inject the returned struct value -// from a request handler or to replace the default renderer. -UseResultHandler(handler func(next iris.ResultHandler) iris.ResultHandler) -``` - -
ResultHandler - -```go -type ResultHandler func(ctx iris.Context, v interface{}) error -``` -
- -```go -// Use same as a common Party's "Use" but it accepts dynamic functions as its "handlersFn" input. -Use(handlersFn ...interface{}) -// Done same as a common Party's but it accepts dynamic functions as its "handlersFn" input. -Done(handlersFn ...interface{}) -``` - -```go -// Handle same as a common Party's `Handle` but it accepts one or more "handlersFn" functions which each one of them -// can accept any input arguments that match with the Party's registered Container's `Dependencies` and -// any output result; like custom structs , string, []byte, int, error, -// a combination of the above, hero.Result(hero.View | hero.Response) and more. -// -// It's common from a hero handler to not even need to accept a `Context`, for that reason, -// the "handlersFn" will call `ctx.Next()` automatically when not called manually. -// To stop the execution and not continue to the next "handlersFn" -// the end-developer should output an error and return `iris.ErrStopExecution`. -Handle(method, relativePath string, handlersFn ...interface{}) *Route - -// Get registers a GET route, same as `Handle("GET", relativePath, handlersFn....)`. -Get(relativePath string, handlersFn ...interface{}) *Route -// and so on... -``` - -Prior to this version the `iris.Context` was the only one dependency that has been automatically binded to the handler's input or a controller's fields and methods, read below to see what types are automatically binded: - -| Type | Maps To | -|------|:---------| -| [*mvc.Application](https://pkg.go.dev/github.com/kataras/iris/v12/mvc?tab=doc#Application) | Current MVC Application | -| [iris.Context](https://pkg.go.dev/github.com/kataras/iris/v12/context?tab=doc#Context) | Current Iris Context | -| [*sessions.Session](https://pkg.go.dev/github.com/kataras/iris/v12/sessions?tab=doc#Session) | Current Iris Session | -| [context.Context](https://golang.org/pkg/context/#Context) | [ctx.Request().Context()](https://golang.org/pkg/net/http/#Request.Context) | -| [*http.Request](https://golang.org/pkg/net/http/#Request) | `ctx.Request()` | -| [http.ResponseWriter](https://golang.org/pkg/net/http/#ResponseWriter) | `ctx.ResponseWriter()` | -| [http.Header](https://golang.org/pkg/net/http/#Header) | `ctx.Request().Header` | -| [time.Time](https://golang.org/pkg/time/#Time) | `time.Now()` | -| [*golog.Logger](https://pkg.go.dev/github.com/kataras/golog) | Iris Logger | -| [net.IP](https://golang.org/pkg/net/#IP) | `net.ParseIP(ctx.RemoteAddr())` | -| `string`, | | -| `int, int8, int16, int32, int64`, | | -| `uint, uint8, uint16, uint32, uint64`, | | -| `float, float32, float64`, | | -| `bool`, | | -| `slice` | [Path Parameter](https://github.com/kataras/iris/wiki/Routing-path-parameter-types) | -| Struct | [Request Body](https://github.com/kataras/iris/tree/master/_examples/request-body) of `JSON`, `XML`, `YAML`, `Form`, `URL Query`, `Protobuf`, `MsgPack` | - -Here is a preview of what the new Hero handlers look like: - -### Request & Response & Path Parameters - -**1.** Declare Go types for client's request body and a server's response. - -```go -type ( - request struct { - Firstname string `json:"firstname"` - Lastname string `json:"lastname"` - } - - response struct { - ID uint64 `json:"id"` - Message string `json:"message"` - } -) -``` - -**2.** Create the route handler. - -Path parameters and request body are binded automatically. -- **id uint64** binds to "id:uint64" -- **input request** binds to client request data such as JSON - -```go -func updateUser(id uint64, input request) response { - return response{ - ID: id, - Message: "User updated successfully", - } -} -``` - -**3.** Configure the container per group and register the route. - -```go -app.Party("/user").ConfigureContainer(container) - -func container(api *iris.APIContainer) { - api.Put("/{id:uint64}", updateUser) -} -``` - -**4.** Simulate a [client](https://curl.haxx.se/download.html) request which sends data to the server and displays the response. - -```sh -curl --request PUT -d '{"firstanme":"John","lastname":"Doe"}' http://localhost:8080/user/42 -``` - -```json -{ - "id": 42, - "message": "User updated successfully" -} -``` - -### Custom Preflight - -Before we continue to the next section, register dependencies, you may want to learn how a response can be customized through the `iris.Context` right before sent to the client. - -The server will automatically execute the `Preflight(iris.Context) error` method of a function's output struct value right before send the response to the client. - -Take for example that you want to fire different HTTP status codes depending on the custom logic inside your handler and also modify the value(response body) itself before sent to the client. Your response type should contain a `Preflight` method like below. - -```go -type response struct { - ID uint64 `json:"id,omitempty"` - Message string `json:"message"` - Code int `json:"code"` - Timestamp int64 `json:"timestamp,omitempty"` -} - -func (r *response) Preflight(ctx iris.Context) error { - if r.ID > 0 { - r.Timestamp = time.Now().Unix() - } - - ctx.StatusCode(r.Code) - return nil -} -``` - -Now, each handler that returns a `*response` value will call the `response.Preflight` method automatically. - -```go -func deleteUser(db *sql.DB, id uint64) *response { - // [...custom logic] - - return &response{ - Message: "User has been marked for deletion", - Code: iris.StatusAccepted, - } -} -``` - -If you register the route and fire a request you should see an output like this, the timestamp is filled and the HTTP status code of the response that the client will receive is 202 (Status Accepted). - -```json -{ - "message": "User has been marked for deletion", - "code": 202, - "timestamp": 1583313026 -} -``` - -### Register Dependencies - -**1.** Import packages to interact with a database. -The go-sqlite3 package is a database driver for [SQLite](https://www.sqlite.org/index.html). - -```go -import "database/sql" -import _ "github.com/mattn/go-sqlite3" -``` - -**2.** Configure the container ([see above](#request--response--path-parameters)), register your dependencies. Handler expects an *sql.DB instance. - -```go -localDB, _ := sql.Open("sqlite3", "./foo.db") -api.RegisterDependency(localDB) -``` - -**3.** Register a route to create a user. - -```go -api.Post("/{id:uint64}", createUser) -``` - -**4.** The create user Handler. - -The handler accepts a database and some client request data such as JSON, Protobuf, Form, URL Query and e.t.c. It Returns a response. - -```go -func createUser(db *sql.DB, user request) *response { - // [custom logic using the db] - userID, err := db.CreateUser(user) - if err != nil { - return &response{ - Message: err.Error(), - Code: iris.StatusInternalServerError, - } - } - - return &response{ - ID: userID, - Message: "User created", - Code: iris.StatusCreated, - } -} -``` - -**5.** Simulate a [client](https://curl.haxx.se/download.html) to create a user. - -```sh -# JSON -curl --request POST -d '{"firstname":"John","lastname":"Doe"}' \ ---header 'Content-Type: application/json' \ -http://localhost:8080/user -``` - -```sh -# Form (multipart) -curl --request POST 'http://localhost:8080/users' \ ---header 'Content-Type: multipart/form-data' \ ---form 'firstname=John' \ ---form 'lastname=Doe' -``` - -```sh -# Form (URL-encoded) -curl --request POST 'http://localhost:8080/users' \ ---header 'Content-Type: application/x-www-form-urlencoded' \ ---data-urlencode 'firstname=John' \ ---data-urlencode 'lastname=Doe' -``` - -```sh -# URL Query -curl --request POST 'http://localhost:8080/users?firstname=John&lastname=Doe' -``` - -Response: - -```json -{ - "id": 42, - "message": "User created", - "code": 201, - "timestamp": 1583313026 -} -``` - -Other Improvements: - -- Fix `AutoTLS` when used with `iris.TLSNoRedirect` [*](https://github.com/kataras/iris/issues/1577). The `AutoTLS` runner can be customized through the new `iris.AutoTLSNoRedirect` instead, read its go documentation. Example of having both TLS and non-TLS versions of the same application without conflicts with letsencrypt `./well-known` path: - -![](https://iris-go.com/images/github/autotls-1.png) - -```go -package main - -import ( - "net/http" - "time" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - app.Logger().SetLevel("debug") - - app.Get("/", func(ctx iris.Context) { - ctx.JSON(iris.Map{ - "time": time.Now().Unix(), - "tls": ctx.Request().TLS != nil, - }) - }) - - var fallbackServer = func(acme func(http.Handler) http.Handler) *http.Server { - srv := &http.Server{Handler: acme(app)} - go srv.ListenAndServe() - return srv - } - - app.Run(iris.AutoTLS(":443", "example.com", "mail@example.com", - iris.AutoTLSNoRedirect(fallbackServer))) -} -``` - -- `Application.UseRouter(...Handler)` - per party to register handlers before the main router, useful on handlers that should control whether the router itself should ran or not. Independently of the incoming request's method and path values. These handlers will be executed ALWAYS against ALL incoming matched requests. Example of use-case: CORS. - -- `*versioning.Group` type is a full `Party` now. - -- `Party.UseOnce` - either inserts a middleware, or on the basis of the middleware already existing, replace that existing middleware instead. - -- Ability to register a view engine per group of routes or for the current chain of handlers through `Party.RegisterView` and `Context.ViewEngine` respectfully. - -- Add [Blocks](_examples/view/template_blocks_0) template engine. - -- Add [Ace](_examples/view/template_ace_0) template parser to the view engine and other minor improvements. - -- Fix huge repo size of 55.7MB, which slows down the overall Iris installation experience. Now, go-get performs ~3 times faster. I 've managed it using the [bfg-repo-cleaner](https://github.com/rtyley/bfg-repo-cleaner) tool - an alternative to git-filter-branch command. Watch the small gif below to learn how: - -[![](https://media.giphy.com/media/U8560aiWTurW4iAOLn/giphy.gif)](https://media.giphy.com/media/U8560aiWTurW4iAOLn/giphy.gif) - -- [gRPC](https://grpc.io/) features: - - New Router [Wrapper](middleware/grpc). - - New MVC `.Handle(ctrl, mvc.GRPC{...})` option which allows to register gRPC services per-party (without the requirement of a full wrapper) and optionally strict access to gRPC clients only, see the [example here](_examples/mvc/grpc-compatible). - -- Improved tracing (with `app.Logger().SetLevel("debug")`) for routes. Example: - -#### DBUG Routes (1) - -![DBUG routes](https://iris-go.com/images/v12.2.0-dbug.png?v=0) - -#### DBUG Routes (2) - -![DBUG routes](https://iris-go.com/images/v12.2.0-dbug2.png?v=0) - -- Add `Configuration.RemoteAddrHeadersForce bool` to force `Context.RemoteAddr() string` to return the first entry of request headers as a fallback instead of the `Request.RemoteAddr` one, as requested at: [1567#issuecomment-663972620](https://github.com/kataras/iris/issues/1567#issuecomment-663972620). - -- Fix [#1569#issuecomment-663739177](https://github.com/kataras/iris/issues/1569#issuecomment-663739177). - -- Fix [#1564](https://github.com/kataras/iris/issues/1564). - -- Fix [#1553](https://github.com/kataras/iris/issues/1553). - -- New `DirOptions.Cache` to cache assets in-memory among with their compressed contents (in order to be ready to served if client ask). Learn more about this feature by reading [all #1556 comments](https://github.com/kataras/iris/issues/1556#issuecomment-661057446). Usage: - -```go -var dirOpts = DirOptions{ - // [...other options] - Cache: DirCacheOptions{ - Enable: true, - // Don't compress files smaller than 300 bytes. - CompressMinSize: 300, - // Ignore compress already compressed file types - // (some images and pdf). - CompressIgnore: iris.MatchImagesAssets, - // Gzip, deflate, br(brotli), snappy. - Encodings: []string{"gzip", "deflate", "br", "snappy"}, - // Log to the stdout the total reduced file size. - Verbose: 1, - }, -} -``` - -- New `DirOptions.PushTargets` and `PushTargetsRegexp` to push index' assets to the client without additional requests. Inspirated by issue [#1562](https://github.com/kataras/iris/issues/1562). Example matching all `.js, .css and .ico` files (recursively): - -```go -var dirOpts = iris.DirOptions{ - // [...other options] - IndexName: "/index.html", - PushTargetsRegexp: map[string]*regexp.Regexp{ - "/": regexp.MustCompile("((.*).js|(.*).css|(.*).ico)$"), - // OR: - // "/": iris.MatchCommonAssets, - }, - Compress: true, -} -``` - -- Update jet parser to v4.0.2, closes [#1551](https://github.com/kataras/iris/issues/1551). It contains two breaking changes by its author: - - Relative paths on `extends, import, include...` tmpl functions, e.g. `{{extends "../layouts/application.jet"}}` instead of `layouts/application.jet` - - the new [jet.Ranger](https://github.com/CloudyKit/jet/pull/165) interface now requires a `ProvidesIndex() bool` method too - - Example has been [updated](https://github.com/kataras/iris/tree/master/_examples/view/template_jet_0) - -- Fix [#1552](https://github.com/kataras/iris/issues/1552). - -- Proper listing of root directories on `Party.HandleDir` when its `DirOptions.ShowList` was set to true. - - Customize the file/directory listing page through views, see [example](https://github.com/kataras/iris/tree/master/_examples/file-server/file-server). - -- Socket Sharding as requested at [#1544](https://github.com/kataras/iris/issues/1544). New `iris.WithSocketSharding` Configurator and `SocketSharding bool` setting. - -- Versioned Controllers feature through the new `mvc.Version` option. See [_examples/mvc/versioned-controller](https://github.com/kataras/iris/blob/master/_examples/mvc/versioned-controller/main.go). - -- Fix [#1539](https://github.com/kataras/iris/issues/1539). - -- New [rollbar example](https://github.com/kataras/iris/blob/master/_examples/logging/rollbar/main.go). - -- New builtin [requestid](https://github.com/kataras/iris/tree/master/middleware/requestid) middleware. - -- New builtin [JWT](https://github.com/kataras/iris/tree/master/middleware/jwt) middleware based on [square/go-jose](https://github.com/square/go-jose) featured with optional encryption to set claims with sensitive data when necessary. - -- New `iris.RouteOverlap` route registration rule. `Party.SetRegisterRule(iris.RouteOverlap)` to allow overlapping across multiple routes for the same request subdomain, method, path. See [1536#issuecomment-643719922](https://github.com/kataras/iris/issues/1536#issuecomment-643719922). This allows two or more **MVC Controllers** to listen on the same path based on one or more registered dependencies (see [_examples/mvc/authenticated-controller](https://github.com/kataras/iris/tree/master/_examples/mvc/authenticated-controller)). - -- `Context.ReadForm` now can return an `iris.ErrEmptyForm` instead of `nil` when the new `Configuration.FireEmptyFormError` is true (when `iris.WithEmptyFormError` is set) on missing form body to read from. - -- `Configuration.EnablePathIntelligence | iris.WithPathIntelligence` to enable path intelligence automatic path redirection on the most closest path (if any), [example]((https://github.com/kataras/iris/blob/master/_examples/routing/intelligence/main.go) - -- Enhanced cookie security and management through new `Context.AddCookieOptions` method and new cookie options (look on New Package-level functions section below), [securecookie](https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie) example has been updated. -- `Context.RemoveCookie` removes also the Request's specific cookie of the same request lifecycle when `iris.CookieAllowReclaim` is set to cookie options, [example](https://github.com/kataras/iris/tree/master/_examples/cookies/options). - -- `iris.TLS` can now accept certificates in form of raw `[]byte` contents too. -- `iris.TLS` registers a secondary http server which redirects "http://" to their "https://" equivalent requests, unless the new `iris.TLSNoRedirect` host Configurator is provided on `iris.TLS`, e.g. `app.Run(iris.TLS("127.0.0.1:443", "mycert.cert", "mykey.key", iris.TLSNoRedirect))`. There is `iris.AutoTLSNoRedirect` option for `AutoTLS` too. - -- Fix an [issue](https://github.com/kataras/i18n/issues/1) about i18n loading from path which contains potential language code. - -- Server will not return neither log the `ErrServerClosed` error if `app.Shutdown` was called manually via interrupt signal(CTRL/CMD+C), note that if the server closed by any other reason the error will be fired as previously (unless `iris.WithoutServerError(iris.ErrServerClosed)`). - -- Finally, Log level's and Route debug information colorization is respected across outputs. Previously if the application used more than one output destination (e.g. a file through `app.Logger().AddOutput`) the color support was automatically disabled from all, including the terminal one, this problem is fixed now. Developers can now see colors in their terminals while log files are kept with clear text. - -- New `iris.WithLowercaseRouting` option which forces all routes' paths to be lowercase and converts request paths to their lowercase for matching. - -- New `app.Validator { Struct(interface{}) error }` field and `app.Validate` method were added. The `app.Validator = ` can be used to integrate a 3rd-party package such as [go-playground/validator](https://github.com/go-playground/validator). If set-ed then Iris `Context`'s `ReadJSON`, `ReadXML`, `ReadMsgPack`, `ReadYAML`, `ReadForm`, `ReadQuery`, `ReadBody` methods will return the validation error on data validation failures. The [read-json-struct-validation](_examples/request-body/read-json-struct-validation) example was updated. - -- A result of can implement the new `hero.PreflightResult` interface which contains a single method of `Preflight(iris.Context) error`. If this method exists on a custom struct value which is returned from a handler then it will fire that `Preflight` first and if not errored then it will cotninue by sending the struct value as JSON(by-default) response body. - -- `ctx.JSON, JSONP, XML`: if `iris.WithOptimizations` is NOT passed on `app.Run/Listen` then the indentation defaults to `" "` (four spaces) and `" "` respectfully otherwise it is empty or the provided value. - -- Hero Handlers (and `app.ConfigureContainer().Handle`) do not have to require `iris.Context` just to call `ctx.Next()` anymore, this is done automatically now. - -- Improve Remote Address parsing as requested at: [#1453](https://github.com/kataras/iris/issues/1453). Add `Configuration.RemoteAddrPrivateSubnets` to exclude those addresses when fetched by `Configuration.RemoteAddrHeaders` through `context.RemoteAddr() string`. - -- Fix [#1487](https://github.com/kataras/iris/issues/1487). - -- Fix [#1473](https://github.com/kataras/iris/issues/1473). - -New Package-level Variables: - -- `iris.DirListRichOptions` to pass on `iris.DirListRich` method. -- `iris.DirListRich` to override the default look and feel if the `DirOptions.ShowList` was set to true, can be passed to `DirOptions.DirList` field. -- `DirOptions.PushTargets` for http/2 push on index [*](https://github.com/kataras/iris/tree/master/_examples/file-server/http2push/main.go). -- `iris.Compression` middleware to compress responses and decode compressed request data respectfully. -- `iris.B, KB, MB, GB, TB, PB, EB` for byte units. -- `TLSNoRedirect` to disable automatic "http://" to "https://" redirections (see below) -- `CookieAllowReclaim`, `CookieAllowSubdomains`, `CookieSameSite`, `CookieSecure` and `CookieEncoding` to bring previously sessions-only features to all cookies in the request. - -New Context Methods: - -- `Context.ViewEngine(ViewEngine)` to set a view engine on-fly for the current chain of handlers, responsible to render templates through `ctx.View`. [Example](_examples/view/context-view-engine). -- `Context.SetErr(error)` and `Context.GetErr() error` helpers. -- `Context.CompressWriter(bool) error` and `Context.CompressReader(bool) error`. -- `Context.Clone() Context` returns a copy of the Context. -- `Context.IsCanceled() bool` reports whether the request has been canceled by the client. -- `Context.IsSSL() bool` reports whether the request is under HTTPS SSL (New `Configuration.SSLProxyHeaders` and `HostProxyHeaders` fields too). -- `Context.CompressReader(enable bool)` method and `iris.CompressReader` middleware to enable future request read body calls to decompress data, [example](_examples/compression/main.go). -- `Context.RegisterDependency(v interface{})` and `Context.UnregisterDependency(typ reflect.Type)` to register/remove struct dependencies on serve-time through a middleware. -- `Context.SetID(id interface{})` and `Context.GetID() interface{}` added to register a custom unique indetifier to the Context, if necessary. -- `Context.GetDomain() string` returns the domain. -- `Context.AddCookieOptions(...CookieOption)` adds options for `SetCookie`, `SetCookieKV, UpsertCookie` and `RemoveCookie` methods for the current request. -- `Context.ClearCookieOptions()` clears any cookie options registered through `AddCookieOptions`. -- `Context.SetLanguage(langCode string)` force-sets a language code from inside a middleare, similar to the `app.I18n.ExtractFunc` -- `Context.ServeContentWithRate`, `ServeFileWithRate` and `SendFileWithRate` methods to throttle the "download" speed of the client -- `Context.IsHTTP2() bool` reports whether the protocol version for incoming request was HTTP/2 -- `Context.IsGRPC() bool` reports whether the request came from a gRPC client -- `Context.UpsertCookie(*http.Cookie, cookieOptions ...context.CookieOption)` upserts a cookie, fixes [#1485](https://github.com/kataras/iris/issues/1485) too -- `Context.StopWithStatus(int)` stops the handlers chain and writes the status code -- `Context.StopWithText(int, string)` stops the handlers chain, writes thre status code and a plain text message -- `Context.StopWithError(int, error)` stops the handlers chain, writes thre status code and the error's message -- `Context.StopWithJSON(int, interface{})` stops the handlers chain, writes the status code and sends a JSON response -- `Context.StopWithProblem(int, iris.Problem)` stops the handlers, writes the status code and sends an `application/problem+json` response -- `Context.Protobuf(proto.Message)` sends protobuf to the client (note that the `Context.JSON` is able to send protobuf as JSON) -- `Context.MsgPack(interface{})` sends msgpack format data to the client -- `Context.ReadProtobuf(ptr)` binds request body to a proto message -- `Context.ReadJSONProtobuf(ptr, ...options)` binds JSON request body to a proto message -- `Context.ReadMsgPack(ptr)` binds request body of a msgpack format to a struct -- `Context.ReadBody(ptr)` binds the request body to the "ptr" depending on the request's Method and Content-Type -- `Context.ReflectValue() []reflect.Value` stores and returns the `[]reflect.ValueOf(ctx)` -- `Context.Controller() reflect.Value` returns the current MVC Controller value. - -Breaking Changes: - -- `versioning.NewGroup(string)` now accepts a `Party` as its first input argument: `NewGroup(Party, string)`. -- `versioning.RegisterGroups` is **removed** as it is no longer necessary. -- `Configuration.RemoteAddrHeaders` from `map[string]bool` to `[]string`. If you used `With(out)RemoteAddrHeader` then you are ready to proceed without any code changes for that one. -- `ctx.Gzip(boolean)` replaced with `ctx.CompressWriter(boolean) error`. -- `ctx.GzipReader(boolean) error` replaced with `ctx.CompressReader(boolean) error`. -- `iris.Gzip` and `iris.GzipReader` replaced with `iris.Compression` (middleware). -- `ctx.ClientSupportsGzip() bool` replaced with `ctx.ClientSupportsEncoding("gzip", "br" ...) bool`. -- `ctx.GzipResponseWriter()` is **removed**. -- `Party.HandleDir/iris.FileServer` now accepts a `http.FileSystem` instead of a string and returns a list of `[]*Route` (GET and HEAD) instead of GET only. Write: `app.HandleDir("/", iris.Dir("./assets"))` instead of `app.HandleDir("/", "./assets")` and `DirOptions.Asset, AssetNames, AssetInfo` removed, use `go-bindata -fs [..]` and `app.HandleDir("/", AssetFile())` instead. -- `Context.OnClose` and `Context.OnCloseConnection` now both accept an `iris.Handler` instead of a simple `func()` as their callback. -- `Context.StreamWriter(writer func(w io.Writer) bool)` changed to `StreamWriter(writer func(w io.Writer) error) error` and it's now the `Context.Request().Context().Done()` channel that is used to receive any close connection/manual cancel signals, instead of the deprecated `ResponseWriter().CloseNotify()` one. Same for the `Context.OnClose` and `Context.OnCloseConnection` methods. -- Fixed handler's error response not be respected when response recorder was used instead of the common writer. Fixes [#1531](https://github.com/kataras/iris/issues/1531). It contains a **BREAKING CHANGE** of: the new `Configuration.ResetOnFireErrorCode` field should be set **to true** in order to behave as it used before this update (to reset the contents on recorder). -- `Context.String()` (rarely used by end-developers) it does not return a unique string anymore, to achieve the old representation you must call the new `Context.SetID` method first. -- `iris.CookieEncode` and `CookieDecode` are replaced with the `iris.CookieEncoding`. -- `sessions#Config.Encode` and `Decode` are removed in favor of (the existing) `Encoding` field. -- `versioning.GetVersion` now returns an empty string if version wasn't found. -- Change the MIME type of `Javascript .js` and `JSONP` as the HTML specification now recommends to `"text/javascript"` instead of the obselete `"application/javascript"`. This change was pushed to the `Go` language itself as well. See . -- Remove the last input argument of `enableGzipCompression` in `Context.ServeContent`, `ServeFile` methods. This was deprecated a few versions ago. A middleware (`app.Use(iris.CompressWriter)`) or a prior call to `Context.CompressWriter(true)` will enable compression. Also these two methods and `Context.SendFile` one now support `Content-Range` and `Accept-Ranges` correctly out of the box (`net/http` had a bug, which is now fixed). -- `Context.ServeContent` no longer returns an error, see `ServeContentWithRate`, `ServeFileWithRate` and `SendFileWithRate` new methods too. -- `route.Trace() string` changed to `route.Trace(w io.Writer)`, to achieve the same result just pass a `bytes.Buffer` -- `var mvc.AutoBinding` removed as the default behavior now resolves such dependencies automatically (see [[FEATURE REQUEST] MVC serving gRPC-compatible controller](https://github.com/kataras/iris/issues/1449)). -- `mvc#Application.SortByNumMethods()` removed as the default behavior now binds the "thinnest" empty `interface{}` automatically (see [MVC: service injecting fails](https://github.com/kataras/iris/issues/1343)). -- `mvc#BeforeActivation.Dependencies().Add` should be replaced with `mvc#BeforeActivation.Dependencies().Register` instead -- **REMOVE** the `kataras/iris/v12/typescript` package in favor of the new [iris-cli](https://github.com/kataras/iris-cli). Also, the alm typescript online editor was removed as it is deprecated by its author, please consider using the [designtsx](https://designtsx.com/) instead. - -There is a breaking change on the type alias of `iris.Context` which now points to the `*context.Context` instead of the `context.Context` interface. The **interface has been removed** and the ability to **override** the Context **is not** available any more. When we added the ability from end-developers to override the Context years ago, we have never imagine that we will ever had such a featured Context with more than 4000 lines of code. As of Iris 2020, it is difficult and un-productive from an end-developer to override the Iris Context, and as far as we know, nobody uses this feature anymore because of that exact reason. Beside the overriding feature support end, if you still use the `context.Context` instead of `iris.Context`, it's the time to do it: please find-and-replace to `iris.Context` as wikis, book and all examples shows for the past 3 years. For the 99.9% of the users there is no a single breaking change, you already using `iris.Context` so you are in the "safe zone". - -# Su, 16 February 2020 | v12.1.8 - -New Features: - -- [[FEATURE REQUEST] MVC serving gRPC-compatible controller](https://github.com/kataras/iris/issues/1449) - -Fixes: - -- [App can't find embedded pug template files by go-bindata](https://github.com/kataras/iris/issues/1450) - -New Examples: - -- [_examples/mvc/grpc-compatible](_examples/mvc/grpc-compatible) - -# Mo, 10 February 2020 | v12.1.7 - -Implement **new** `SetRegisterRule(iris.RouteOverride, RouteSkip, RouteError)` to resolve: https://github.com/kataras/iris/issues/1448 - -New Examples: - -- [_examples/routing/route-register-rule](_examples/routing/route-register-rule) - -# We, 05 February 2020 | v12.1.6 - -Fixes: - -- [jet.View - urlpath error](https://github.com/kataras/iris/issues/1438) -- [Context.ServeFile send 'application/wasm' with a wrong extra field](https://github.com/kataras/iris/issues/1440) - -# Su, 02 February 2020 | v12.1.5 - -Various improvements and linting. - -# Su, 29 December 2019 | v12.1.4 - -Minor fix on serving [embedded files](https://github.com/kataras/iris/wiki/File-server). - -# We, 25 December 2019 | v12.1.3 - -Fix [[BUG] [iris.Default] RegisterView](https://github.com/kataras/iris/issues/1410) - -# Th, 19 December 2019 | v12.1.2 - -Fix [[BUG]Session works incorrectly when meets the multi-level TLDs](https://github.com/kataras/iris/issues/1407). - -# Mo, 16 December 2019 | v12.1.1 - -Add [Context.FindClosest(n int) []string](https://github.com/kataras/iris/blob/master/_examples/routing/intelligence/manual/main.go#L22) - -```go -app := iris.New() -app.OnErrorCode(iris.StatusNotFound, notFound) -``` - -```go -func notFound(ctx iris.Context) { - suggestPaths := ctx.FindClosest(3) - if len(suggestPaths) == 0 { - ctx.WriteString("404 not found") - return - } - - ctx.HTML("Did you mean?
    ") - for _, s := range suggestPaths { - ctx.HTML(`
  • %s
  • `, s, s) - } - ctx.HTML("
") -} -``` - -![](https://iris-go.com/images/iris-not-found-suggests.png) - -# Fr, 13 December 2019 | v12.1.0 - -## Breaking Changes - -Minor as many of you don't even use them but, indeed, they need to be covered here. - -- Old i18n middleware(iris/middleware/i18n) was replaced by the [i18n](i18n) sub-package which lives as field at your application: `app.I18n.Load(globPathPattern string, languages ...string)` (see below) -- Community-driven i18n middleware(iris-contrib/middleware/go-i18n) has a `NewLoader` function which returns a loader which can be passed at `app.I18n.Reset(loader i18n.Loader, languages ...string)` to change the locales parser -- The Configuration's `TranslateFunctionContextKey` was replaced by `LocaleContextKey` which Context store's value (if i18n is used) returns the current Locale which contains the translate function, the language code, the language tag and the index position of it -- The `context.Translate` method was replaced by `context.Tr` as a shortcut for the new `context.GetLocale().GetMessage(format, args...)` method and it matches the view's function `{{tr format args}}` too -- If you used [Iris Django](https://github.com/kataras/iris/tree/master/_examples/view/template_django_0) view engine with `import _ github.com/flosch/pongo2-addons` you **must change** the import path to `_ github.com/iris-contrib/pongo2-addons` or add a [go mod replace](https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive) to your `go.mod` file, e.g. `replace github.com/flosch/pongo2-addons => github.com/iris-contrib/pongo2-addons v0.0.1`. - -## Fixes - -All known issues. - -1. [#1395](https://github.com/kataras/iris/issues/1395) -2. [#1369](https://github.com/kataras/iris/issues/1369) -3. [#1399](https://github.com/kataras/iris/issues/1399) with PR [#1400](https://github.com/kataras/iris/pull/1400) -4. [#1401](https://github.com/kataras/iris/issues/1401) -5. [#1406](https://github.com/kataras/iris/issues/1406) -6. [neffos/#20](https://github.com/kataras/neffos/issues/20) -7. [pio/#5](https://github.com/kataras/pio/issues/5) - -## New Features - -### Internationalization and localization - -Support for i18n is now a **builtin feature** and is being respected across your entire application, per say [sitemap](https://github.com/kataras/iris/wiki/Sitemap) and [views](https://github.com/kataras/iris/blob/master/_examples/i18n/main.go#L50). - -Refer to the wiki section: https://github.com/kataras/iris/wiki/Sitemap for details. - -### Sitemaps - -Iris generates and serves one or more [sitemap.xml](https://www.sitemaps.org/protocol.html) for your static routes. - -Navigate through: https://github.com/kataras/iris/wiki/Sitemap for more. - -## New Examples - -2. [_examples/i18n](_examples/i18n) -1. [_examples/sitemap](_examples/routing/sitemap) -3. [_examples/desktop/blink](_examples/desktop/blink) -4. [_examples/desktop/lorca](_examples/desktop/lorca) -5. [_examples/desktop/webview](_examples/desktop/webview) - -# Sa, 26 October 2019 | v12.0.0 - -- Add version suffix of the **import path**, learn why and see what people voted at [issue #1370](https://github.com/kataras/iris/issues/1370) - -![](https://iris-go.com/images/vote-v12-version-suffix_26_oct_2019.png) - -- All errors are now compatible with go1.13 `errors.Is`, `errors.As` and `fmt.Errorf` and a new `core/errgroup` package created -- Fix [#1383](https://github.com/kataras/iris/issues/1383) -- Report whether system couldn't find the directory of view templates -- Remove the `Party#GetReport` method, keep `Party#GetReporter` which is an `error` and an `errgroup.Group`. -- Remove the router's deprecated methods such as StaticWeb and StaticEmbedded_XXX -- The `Context#CheckIfModifiedSince` now returns an `context.ErrPreconditionFailed` type of error when client conditions are not met. Usage: `if errors.Is(err, context.ErrPreconditionFailed) { ... }` -- Add `SourceFileName` and `SourceLineNumber` to the `Route`, reports the exact position of its registration inside your project's source code. -- Fix a bug about the MVC package route binding, see [PR #1364](https://github.com/kataras/iris/pull/1364) -- Add `mvc/Application#SortByNumMethods` as requested at [#1343](https://github.com/kataras/iris/issues/1343#issuecomment-524868164) -- Add status code `103 Early Hints` -- Fix performance of session.UpdateExpiration on 200 thousands+ keys with new radix as reported at [issue #1328](https://github.com/kataras/iris/issues/1328) -- New redis session database configuration field: `Driver: redis.Redigo()` or `redis.Radix()`, see [updated examples](_examples/sessions/database/redis/) -- Add Clusters support for redis:radix session database (`Driver: redis:Radix()`) as requested at [issue #1339](https://github.com/kataras/iris/issues/1339) -- Create Iranian [README_FA](README_FA.md) translation with [PR #1360](https://github.com/kataras/iris/pull/1360) -- Create Korean [README_KO](README_KO.md) translation with [PR #1356](https://github.com/kataras/iris/pull/1356) -- Create Spanish [README_ES](README_ES.md) and [HISTORY_ES](HISTORY_ES.md) translations with [PR #1344](https://github.com/kataras/iris/pull/1344). - -The iris-contrib/middleare and examples are updated to use the new `github.com/kataras/iris/v12` import path. - -# Fr, 16 August 2019 | v11.2.8 - -- Set `Cookie.SameSite` to `Lax` when subdomains sessions share is enabled[*](https://github.com/kataras/iris/commit/6bbdd3db9139f9038641ce6f00f7b4bab6e62550) -- Add and update all [experimental handlers](https://github.com/iris-contrib/middleware) -- New `XMLMap` function which wraps a `map[string]interface{}` and converts it to a valid xml content to render through `Context.XML` method -- Add new `ProblemOptions.XML` and `RenderXML` fields to render the `Problem` as XML(application/problem+xml) instead of JSON("application/problem+json) and enrich the `Negotiate` to easily accept the `application/problem+xml` mime. - -Commit log: https://github.com/kataras/iris/compare/v11.2.7...v11.2.8 - -# Th, 15 August 2019 | v11.2.7 - -This minor version contains improvements on the Problem Details for HTTP APIs implemented on [v11.2.5](#mo-12-august-2019--v1125). - -- Fix https://github.com/kataras/iris/issues/1335#issuecomment-521319721 -- Add `ProblemOptions` with `RetryAfter` as requested at: https://github.com/kataras/iris/issues/1335#issuecomment-521330994. -- Add `iris.JSON` alias for `context#JSON` options type. - -[Example](https://github.com/kataras/iris/blob/45d7c6fedb5adaef22b9730592255f7bb375e809/_examples/routing/http-errors/main.go#L85) and [wikis](https://github.com/kataras/iris/wiki/Routing-error-handlers#the-problem-type) updated. - -References: - -- https://tools.ietf.org/html/rfc7231#section-7.1.3 -- https://tools.ietf.org/html/rfc7807 - -Commit log: https://github.com/kataras/iris/compare/v11.2.6...v11.2.7 - -# We, 14 August 2019 | v11.2.6 - -Allow [handle more than one route with the same paths and parameter types but different macro validation functions](https://github.com/kataras/iris/issues/1058#issuecomment-521110639). - -```go -app.Get("/{alias:string regexp(^[a-z0-9]{1,10}\\.xml$)}", PanoXML) -app.Get("/{alias:string regexp(^[a-z0-9]{1,10}$)}", Tour) -``` - -Commit log: https://github.com/kataras/iris/compare/v11.2.5...v11.2.6 - -# Mo, 12 August 2019 | v11.2.5 - -- [New Feature: Problem Details for HTTP APIs](https://github.com/kataras/iris/pull/1336) -- [Add Context.AbsoluteURI](https://github.com/kataras/iris/pull/1336/files#diff-15cce7299aae8810bcab9b0bf9a2fdb1R2368) - -Commit log: https://github.com/kataras/iris/compare/v11.2.4...v11.2.5 - -# Fr, 09 August 2019 | v11.2.4 - -- Fixes [iris.Jet: no view engine found for '.jet' or '.html'](https://github.com/kataras/iris/issues/1327) -- Fixes [ctx.ViewData not work with JetEngine](https://github.com/kataras/iris/issues/1330) -- **New Feature**: [HTTP Method Override](https://github.com/kataras/iris/issues/1325) -- Fixes [Poor performance of session.UpdateExpiration on 200 thousands+ keys with new radix lib](https://github.com/kataras/iris/issues/1328) by introducing the `sessions.Config.Driver` configuration field which defaults to `Redigo()` but can be set to `Radix()` too, future additions are welcomed. - -Commit log: https://github.com/kataras/iris/compare/v11.2.3...v11.2.4 - -# Tu, 30 July 2019 | v11.2.3 - -- [New Feature: Handle different parameter types in the same path](https://github.com/kataras/iris/issues/1315) -- [New Feature: Content Negotiation](https://github.com/kataras/iris/issues/1319) -- [Context.ReadYAML](https://github.com/kataras/iris/tree/master/_examples/request-body/read-yaml) -- Fixes https://github.com/kataras/neffos/issues/1#issuecomment-515698536 - -# We, 24 July 2019 | v11.2.2 - -Sessions as middleware: - -```go -import "github.com/kataras/iris/v12/sessions" -// [...] - -app := iris.New() -sess := sessions.New(sessions.Config{...}) - -app.Get("/path", func(ctx iris.Context){ - session := sessions.Get(ctx) - // [work with session...] -}) -``` - -- Add `Session.Len() int` to return the total number of stored values/entries. -- Make `Context.HTML` and `Context.Text` to accept an optional, variadic, `args ...interface{}` input arg(s) too. - -## v11.1.1 - -- https://github.com/kataras/iris/issues/1298 -- https://github.com/kataras/iris/issues/1207 - -# Tu, 23 July 2019 | v11.2.0 - -Read about the new release at: https://www.facebook.com/iris.framework/posts/3276606095684693 diff --git a/HISTORY_ES.md b/HISTORY_ES.md deleted file mode 100644 index 20cc3398..00000000 --- a/HISTORY_ES.md +++ /dev/null @@ -1,141 +0,0 @@ - - -# Registro de cambios - -### ¿Buscando soporte gratuito y en tiempo real? - - https://github.com/kataras/iris/issues - https://chat.iris-go.com - -### ¿Buscando versiones anteriores? - - https://github.com/kataras/iris/releases - -### ¿Quieres ser contratado? - - https://facebook.com/iris.framework - -### ¿Debo actualizar mi versión de Iris? - -Los desarrolladores no están obligados a actualizar si realmente no lo necesitan. Actualice siempre que se sienta listo. - -**Cómo actualizar**: Abra su línea de comandos y ejecute este comando: `go get github.com/kataras/iris/v12@latest`. - -# Su, 16 February 2020 | v12.1.8 - -Not translated yet, please navigate to the [english version](HISTORY.md#su-16-february-2020--v1218) instead. - -# Sábado, 26 de octubre 2019 | v12.0.0 - -- Add version suffix of the **import path**, learn why and see what people voted at [issue #1370](https://github.com/kataras/iris/issues/1370) - -![](https://iris-go.com/images/vote-v12-version-suffix_26_oct_2019.png) - - -- Todos los errores ahora son compatibles con `errors.Is`, `errors.As` y `fmt.Errorf` de go1.13 y ha sido creado un nuevo paquete `core/errgroup` -- Corrección [#1383](https://github.com/kataras/iris/issues/1383) -- Informar en cualquier sistema si no se logró encontrar directorio de plantillas para las vistas. -- Se removió el método `Party#GetReport`, se mantuvo `Party#GetReporter` que es un `error` y `errgroup.Group`. -- Se removieron métodos obsoletos del enrutador como StaticWeb y StaticEmbedded_XXX -- `Context#CheckIfModifiedSince` ahora returna tipo error `context.ErrPreconditionFailed` cuando no se cumplen condiciones del cliente. Uso: `if errors.Is(err, context.ErrPreconditionFailed) { ... }` -- Se agregó `SourceFileName` y `SourceLineNumber` a `Route`, informan la posición exacta de su registro dentro del código fuente de su proyecto. -- Se corrige bug sobre enlace de ruta del paquete MVC, ver [PR #1364](https://github.com/kataras/iris/pull/1364) -- Se agregó `mvc/Application#SortByNumMethods` solicitado en [#1343](https://github.com/kataras/iris/issues/1343#issuecomment-524868164) -- Código de estado `103 Early Hints` agregado. -- Se corrigió rendimiento de `session.UpdateExpiration` en nas de 200 mil registros con nuevo radix reportado en [problema #1328](https://github.com/kataras/iris/issues/1328) -- Nuevo campo de configuración de la base de datos de sesión de redis: `Driver: redis.Redigo()` o `redis.Radix()`, ver [ejemplos actualizados](_examples/sessions/database/redis/) -- Se agregó soporte de Clusters para la base de datos de sesión redis: radix (`Driver: redis: Radix ()`) como se solicitó en [problema #1339](https://github.com/kataras/iris/issues/1339) -- Se creó traducción en iraní [README_FA](README_FA.md) en [PR #1360](https://github.com/kataras/iris/pull/1360) -- Se creó traducción en koreano [README_KO](README_KO.md) en [PR #1356](https://github.com/kataras/iris/pull/1356) -- Se creó traducción en español [README_ES](README_ES.md) y [HISTORY_ES](HISTORY_ES.md) en [PR #1344](https://github.com/kataras/iris/pull/1344). - -iris-contrib/middleare y ejemplos se actualizaron para utilizar la nueva ruta de importación `github.com/kataras/iris/v12`. - -# Viernes, 16 de agosto 2019 | v11.2.8 - -- Establecer `Cookie.SameSite` como `Lax` cuando el uso compartido de sesiones de subdominios esté habilitado[*](https://github.com/kataras/iris/commit/6bbdd3db9139f9038641ce6f00f7b4bab6e62550) -- Agregados y actualizados todos los [Handlers experimentales](https://github.com/kataras/iris/tree/master/_examples/experimental-handlers) -- Nueva función `XMLMap` que envuelve un `map[string]interface{}` y la convierte en un contenido xml válido para representarlo a través del método `Context.XML` -- Se agregaron nuevos campos `ProblemOptions.XML` y ` RenderXML` para renderizar `Problem` como XML(application/problem+xml) en lugar de JSON("application/problem+json) y enriquezca el `Negotiate` para aceptar fácilmente el mime type `application/problem+xml`. - -Registro de commits: https://github.com/kataras/iris/compare/v11.2.7...v11.2.8 - -# Jueves, 15 de agosto 2019 | v11.2.7 - -Esta versión menor contiene mejoras en los Detalles del problema para las API HTTP implementadas en [v11.2.5](#lunes-12-de-agosto-2019--v1125). - -- Ajuste https://github.com/kataras/iris/issues/1335#issuecomment-521319721 -- Agregado `ProblemOptions` con `RetryAfter` como se solicitó en: https://github.com/kataras/iris/issues/1335#issuecomment-521330994. -- Agregado alias `iris.JSON` para el tipo de opciones `context#JSON`. - -[Ejemplos](https://github.com/kataras/iris/blob/45d7c6fedb5adaef22b9730592255f7bb375e809/_examples/routing/http-errors/main.go#L85) y [wikis](https://github.com/kataras/iris/wiki/Routing-error-handlers#the-problem-type) actualizados. - -Referencias: - -- https://tools.ietf.org/html/rfc7231#section-7.1.3 -- https://tools.ietf.org/html/rfc7807 - -Registro de commits: https://github.com/kataras/iris/compare/v11.2.6...v11.2.7 - -# Miércoles, 14 de agosto 2019 | v11.2.6 - -Permitir [manejar más de una ruta con las mismas rutas y tipos de parámetros pero diferentes funciones de validación de macros](https://github.com/kataras/iris/issues/1058#issuecomment-521110639). - -```go -app.Get("/{alias:string regexp(^[a-z0-9]{1,10}\\.xml$)}", PanoXML) -app.Get("/{alias:string regexp(^[a-z0-9]{1,10}$)}", Tour) -``` - -Registro de commits: https://github.com/kataras/iris/compare/v11.2.5...v11.2.6 - -# Lunes, 12 de agosto 2019 | v11.2.5 - -- [Nueva característica: Detalle del problemas para las APIs HTTP](https://github.com/kataras/iris/pull/1336) -- [Agregado Context.AbsoluteURI](https://github.com/kataras/iris/pull/1336/files#diff-15cce7299aae8810bcab9b0bf9a2fdb1R2368) - -Registro de commits: https://github.com/kataras/iris/compare/v11.2.4...v11.2.5 - -# Viernes, 09 de agosto 2019 | v11.2.4 - -- Ajustes [iris.Jet: no view engine found for '.jet' or '.html'](https://github.com/kataras/iris/issues/1327) -- Ajustes [ctx.ViewData no funciona con JetEngine](https://github.com/kataras/iris/issues/1330) -- **Nueva característica**: [Override de métodos HTTP](https://github.com/kataras/iris/issues/1325) -- Ajustes [Bajo rendimiento en session.UpdateExpiration en más de 200 mil keys con nueva librería radix](https://github.com/kataras/iris/issues/1328) al introducir el campo de configuración `sessions.Config.Driver` que se establece de forma predeterminada en `Redigo()` pero también se puede establecer en `Radix()`, futuras adiciones son bienvenidas. - -Registro de commits: https://github.com/kataras/iris/compare/v11.2.3...v11.2.4 - -# Martes, 30 de julio 2019 | v11.2.3 - -- [Nueva característica: Manejar diferentes tipos de parámetros en la misma ruta](https://github.com/kataras/iris/issues/1315) -- [Nueva característica: Negociación de contenido](https://github.com/kataras/iris/issues/1319) -- [Context.ReadYAML](https://github.com/kataras/iris/tree/master/_examples/request-body/read-yaml) -- Ajustes https://github.com/kataras/neffos/issues/1#issuecomment-515698536 - -# Miércoles, 24 de julio 2019 | v11.2.2 - -Sesiones como middleware: - -```go -import "github.com/kataras/iris/v12/sessions" -// [...] - -app := iris.New() -sess := sessions.New(sessions.Config{...}) - -app.Get("/path", func(ctx iris.Context){ - session := sessions.Get(ctx) - // [work with session...] -}) -``` - -- Agregado `Session.Len() int` para devolver el número total de valores/entradas almacenados. -- Permitir que `Context.HTML` y `Context.Text` acepten tambien un argumento `args ...interface{}` opcional y variable. - -## v11.1.1 - -- https://github.com/kataras/iris/issues/1298 -- https://github.com/kataras/iris/issues/1207 - -# Martes, 23 de julio 2019 | v11.2.0 - -Lea sobre la nueva versión liberada en: https://www.facebook.com/iris.framework/posts/3276606095684693 diff --git a/README.md b/README.md index 5a282c62..f9915d92 100644 --- a/README.md +++ b/README.md @@ -1,236 +1,3 @@ -[![Black Lives Matter](https://iris-go.com/images/blacklivesmatter_banner.png)](https://support.eji.org/give/153413/#!/donation/checkout) +# Iris Web Framework - - -> This is the under-**development branch**. Stay tuned for the upcoming release [v12.2.0](HISTORY.md#Next). Looking for a stable release? Head over to the [v12.1.8 branch](https://github.com/kataras/iris/tree/v12.1.8) instead. -> -> ![](https://iris-go.com/images/cli.png) Try the official [Iris Command Line Interface](https://github.com/kataras/iris-cli) today! - - - -# Iris Web Framework - -[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![view examples](https://img.shields.io/badge/examples%20-173-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) - - - -Iris is a fast, simple yet fully featured and very efficient web framework for Go. - -It provides a beautifully expressive and easy to use foundation for your next website or API. - -Learn what [others saying about Iris](https://iris-go.com/testimonials/) and **[star](https://github.com/kataras/iris/stargazers)** this open-source project to support its potentials. - -[![](https://iris-go.com/images/reviews.gif)](https://iris-go.com/testimonials/) - -[![Benchmarks: Jul 18, 2020 at 10:46am (UTC)](https://iris-go.com/images/benchmarks.svg)](https://github.com/kataras/server-benchmarks) - -## 👑 Supporters - -

- 陆 轶丰 - Weihang Ding - Li Fang - TechMaster - lenses.io - Celso Souza - Altafino - Thomas Fritz - Conrad Steenberg - Damon Zhao - George Opritescu - Juanses - Ankur Srivastava - Lex Tang - li3p -

- -## 📖 Learning Iris - -```sh -# https://github.com/kataras/iris/wiki/Installation -$ go get github.com/kataras/iris/v12@master -# assume the following code in main.go file -$ cat main.go -``` - -```go -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - - booksAPI := app.Party("/books") - { - booksAPI.Use(iris.Compression) - - // GET: http://localhost:8080/books - booksAPI.Get("/", list) - // POST: http://localhost:8080/books - booksAPI.Post("/", create) - } - - app.Listen(":8080") -} - -// Book example. -type Book struct { - Title string `json:"title"` -} - -func list(ctx iris.Context) { - books := []Book{ - {"Mastering Concurrency in Go"}, - {"Go Design Patterns"}, - {"Black Hat Go"}, - } - - ctx.JSON(books) - // TIP: negotiate the response between server's prioritizes - // and client's requirements, instead of ctx.JSON: - // ctx.Negotiation().JSON().MsgPack().Protobuf() - // ctx.Negotiate(books) -} - -func create(ctx iris.Context) { - var b Book - err := ctx.ReadJSON(&b) - // TIP: use ctx.ReadBody(&b) to bind - // any type of incoming data instead. - if err != nil { - ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem(). - Title("Book creation failure").DetailErr(err)) - // TIP: use ctx.StopWithError(code, err) when only - // plain text responses are expected on errors. - return - } - - println("Received Book: " + b.Title) - - ctx.StatusCode(iris.StatusCreated) -} -``` - -**MVC** equivalent: - -```go -import "github.com/kataras/iris/v12/mvc" -``` - -```go -m := mvc.New(booksAPI) -m.Handle(new(BookController)) -``` - -```go -type BookController struct { - /* dependencies */ -} - -// GET: http://localhost:8080/books -func (c *BookController) Get() []Book { - return []Book{ - {"Mastering Concurrency in Go"}, - {"Go Design Patterns"}, - {"Black Hat Go"}, - } -} - -// POST: http://localhost:8080/books -func (c *BookController) Post(b Book) int { - println("Received Book: " + b.Title) - - return iris.StatusCreated -} -``` - -**Run** your Iris web server: - -```sh -$ go run main.go -> Now listening on: http://localhost:8080 -> Application started. Press CTRL+C to shut down. -``` - -**List** Books: - -```sh -$ curl --header 'Accept-Encoding:gzip' http://localhost:8080/books - -[ - { - "title": "Mastering Concurrency in Go" - }, - { - "title": "Go Design Patterns" - }, - { - "title": "Black Hat Go" - } -] -``` - -**Create** a new Book: - -```sh -$ curl -i -X POST \ ---header 'Content-Encoding:gzip' \ ---header 'Content-Type:application/json' \ ---data "{\"title\":\"Writing An Interpreter In Go\"}" \ -http://localhost:8080/books - -> HTTP/1.1 201 Created -``` - -That's how an **error** response looks like: - -```sh -$ curl -X POST --data "{\"title\" \"not valid one\"}" \ -http://localhost:8080/books - -> HTTP/1.1 400 Bad Request - -{ - "status": 400, - "title": "Book creation failure" - "detail": "invalid character '\"' after object key", -} -``` - - - -[![run in the browser](https://img.shields.io/badge/Run-in%20the%20Browser-348798.svg?style=for-the-badge&logo=repl.it)](https://bit.ly/2YJeSZe) - -Iris contains extensive and thorough **[wiki](https://github.com/kataras/iris/wiki)** making it easy to get started with the framework. - - - -For a more detailed technical documentation you can head over to our [godocs](https://godoc.org/github.com/kataras/iris). And for executable code you can always visit the [./_examples](_examples) repository's subdirectory. - -### Do you like to read while traveling? - - Book cover - -[![follow Iris web framework on twitter](https://img.shields.io/twitter/follow/iris_framework?color=ee7506&logoColor=ee7506&style=for-the-badge)](https://twitter.com/intent/follow?screen_name=iris_framework) - -You can [request](https://iris-go.com/#book) a PDF version and online access of the **E-Book** today and be participated in the development of Iris. - -## 🙌 Contributing - -We'd love to see your contribution to the Iris Web Framework! For more information about contributing to the Iris project please check the [CONTRIBUTING.md](CONTRIBUTING.md) file. - -[List of all Contributors](https://github.com/kataras/iris/graphs/contributors) - -## 🛡 Security Vulnerabilities - -If you discover a security vulnerability within Iris, please send an e-mail to [iris-go@outlook.com](mailto:iris-go@outlook.com). All security vulnerabilities will be promptly addressed. - -## 📝 License - -This project is licensed under the [BSD 3-clause license](LICENSE), just like the Go project itself. - -The project name "Iris" was inspired by the Greek mythology. - +Stale Release for pre-go modules. Please follow instead. diff --git a/README_ES.md b/README_ES.md deleted file mode 100644 index fec5f5e9..00000000 --- a/README_ES.md +++ /dev/null @@ -1,76 +0,0 @@ -# Iris Web Framework - -[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) - -Iris es un framework web rápido, simple pero con muchas funcionalidades y muy eficiente para Go. Proporciona una base bellamente expresiva y fácil de usar para su próximo sitio web o API. - -Descubra lo que [otros dicen sobre Iris](https://iris-go.com/testimonials/) y **siga** :star: este repositorio github. - -[![](https://media.giphy.com/media/j5WLmtvwn98VPrm7li/giphy.gif)](https://iris-go.com/testimonials/) - -[![Benchmarks: Apr 2, 2020 at 12:13pm (UTC)](https://iris-go.com/images/benchmarks.svg)](https://github.com/kataras/server-benchmarks) - -## Aprende Iris - -
-Inicio rapido - -```sh -# agrega el siguiente código en el archivo ejemplo.go -$ cat ejemplo.go -``` - -```go -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.Default() - app.Get("/ping", func(ctx iris.Context) { - ctx.JSON(iris.Map{ - "message": "pong", - }) - }) - - app.Listen(":8080") -} -``` - -```sh -# ejecuta ejemplo.go y -# visita http://localhost:8080/ping en el navegador -$ go run ejemplo.go -``` - -> El enrutamiento es impulsado por [muxie](https://github.com/kataras/muxie), el software basado en trie más potente y rápido escrito en Go. - -
- -Iris contiene un extenso y completo **[wiki](https://github.com/kataras/iris/wiki)** que facilita comenzar con el framework. - -Para obtener una documentación técnica más detallada, puede dirigirse a nuestros [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.0). Y para código ejecutable siempre puede visitar el subdirectorio del repositorio [\_examples](_examples/). - -### ¿Te gusta leer mientras viajas? - - Book cover - -[![follow author](https://img.shields.io/twitter/follow/makismaropoulos.svg?style=for-the-badge)](https://twitter.com/intent/follow?screen_name=makismaropoulos) - -Puedes [solicitar](https://bit.ly/iris-req-book) una versión en PDF y acceso en línea del **E-Book** hoy y participar en el desarrollo de Iris. - -## Contribuir - -¡Nos encantaría ver su contribución al Framework Web Iris! Para obtener más información sobre cómo contribuir al proyecto Iris, consulte el archivo [CONTRIBUTING.md](CONTRIBUTING). - -[Lista de todos los contribuyentes](https://github.com/kataras/iris/graphs/contributors) - -## Vulnerabilidades de seguridad - -Si descubres una vulnerabilidad de seguridad dentro de Iris, envíe un correo electrónico a [iris-go@outlook.com](mailto:iris-go@outlook.com). Todas las vulnerabilidades de seguridad serán tratadas de inmediato. - -## Licencia - -El nombre del proyecto "Iris" se inspiró en la mitología griega. - -El Web Framework Iris es un software gratuito y de código abierto con licencia bajo la [Licencia BSD 3 cláusulas](LICENSE). diff --git a/README_FA.md b/README_FA.md deleted file mode 100644 index dcdacaf8..00000000 --- a/README_FA.md +++ /dev/null @@ -1,102 +0,0 @@ -# Iris Web Framework - -
- -[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) - -
- -آیریس سریع ترین و ساده ترین و موثرترین فریمورک وب در زبان GO میباشد. آیریس ساختاری بسیار زیبا و کارآمد را فراهم کرده است تا شما از آن برای پروژه های بعدی تان استفاده کنید. . - -برای این که بدانید دیگران در مورد آیریس چه می گویند لطفا در این لینک کلیک کنید [دیگران در مورد آیریس چه می گویند](https://iris-go.com/testimonials/) لطفا این پروژه را در گیتاب **استار** کنید. - -[![](https://media.giphy.com/media/j5WLmtvwn98VPrm7li/giphy.gif)](https://iris-go.com/testimonials/) - -[![Benchmarks: Apr 2, 2020 at 12:13pm (UTC)](https://iris-go.com/images/benchmarks.svg)](https://github.com/kataras/server-benchmarks) - -## آموزش آیریس - -
-شروع سریع - -
- -
- -```sh - -# فرض کنید همچین کدی را در فایل example.go نوشته اید -``` - -
- -```sh -$ cat example.go -``` - -```go -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.Default() - app.Get("/ping", func(ctx iris.Context) { - ctx.JSON(iris.Map{ - "message": "pong", - }) - }) - - app.Listen(":8080") -} -``` - -```sh -# run example.go and -# visit http://localhost:8080/ping on browser -$ go run example.go -``` - -
- -
- -> ایریس از پروژه ی [muxie](https://github.com/kataras/muxie) که موثرترین و سریع ترین پروژه مسیریابی در GO می باشد استفاده می کند. - -
- -
- -آیریس داری **[wiki](https://github.com/kataras/iris/wiki)** بسیار کامل و گسترده ای میباشد که یادگیری ان را ساده می کند. - -شما برای مشاهده و خواندن داکیومنت های فنی میتوانید به [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.0) مراجعه کنید و همچنین برای مشاهده مثال ها و کد های قابل اجرا همیشه میتوانید از [مثال ها](_examples/) استفاده کنید . - -### آیا شما مطالعه کردن در طول سفر را دوست دارید ؟ - -
- - Book cover - -
- -[![follow author](https://img.shields.io/twitter/follow/makismaropoulos.svg?style=for-the-badge)](https://twitter.com/intent/follow?screen_name=makismaropoulos) - -شما میتوانید در خواست یک نسخه PDF داکیومنت ر ا به صورت رایگان از اینجا بدهید [درخواست](https://bit.ly/iris-req-book) - -## مشارکت کردن - -ما دوست داریم که شما در فریمورک آیریس مشارکت کنید و کد ها را توسعه و بهبود ببخشید ! برای اطلاع بیشتر در مورد نحوه ی مشارکت کردن در این پروژه لطفا اینجا را بررسی کنید [CONTRIBUTING.md](CONTRIBUTING.md) - -[مشاهده ی همه ی مشارکت کننده ها](https://github.com/kataras/iris/graphs/contributors) - -## باگ های امنیتی - -اگر شما باگ های امنیتی در آیریس پیدا کردید لطفا یک ایمیل به [iris-go@outlook.com](mailto:iris-go@outlook.com) ارسال کنید. همه ی باگ های امنیتی بلافاصله برطرف میشود. - -## مجوز - -نام پروژه آیریس ریشه ای یونانی دارد. - -فریمورک آیریس رایگان و سورس باز و تحت مجوز [3-Clause BSD License](LICENSE) می باشد. - -
diff --git a/README_FR.md b/README_FR.md deleted file mode 100644 index 1ab7394a..00000000 --- a/README_FR.md +++ /dev/null @@ -1,87 +0,0 @@ -# Iris Web Framework - -[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) - - - -Iris est un framework open-source pour Go à la fois simple, rapide et pourvu de nombreuses fonctionnalités. - -Il fournit des moyens simples et élégants de construire les bases et fonctionnalités de votre site, application backend ou API Rest. - -Lisez [ce que les développeurs pensent d'Iris](https://iris-go.com/testimonials/) et si l'envie vous prend **[étoilez](https://github.com/kataras/iris/stargazers)** le projet pour faire monter son potentiel. - -[![](https://media.giphy.com/media/j5WLmtvwn98VPrm7li/giphy.gif)](https://iris-go.com/testimonials/) - -[![Benchmarks: Apr 2, 2020 at 12:13pm (UTC)](https://iris-go.com/images/benchmarks.svg)](https://github.com/kataras/server-benchmarks) - -## 📖 Démarrer avec Iris - -
-Un simple Hello World - -```sh -# https://github.com/kataras/iris/wiki/Installation -$ go get github.com/kataras/iris/v12@latest -# assume the following code in example.go file -$ cat example.go -``` - -```go -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - app.Get("/ping", func(ctx iris.Context) { - ctx.JSON(iris.Map{ - "message": "pong", - }) - }) - - app.Listen(":8080") // port d'écoute -} -``` - -```sh -# compile et execute example.go -$ go run example.go -# maintenant visitez http://localhost:8080/ping -``` - -> Le routing est géré par [muxie](https://github.com/kataras/muxie), la librairie Go la plus rapide et complète. - -
- -Iris possède un **[wiki](https://github.com/kataras/iris/wiki)** complet et précis qui vous permettra d'implémenter ses fonctionnalités rapidement et facilement. - - - -Pour une documentation encore plus complète vous pouvez visiter notre [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.0) (en Anglais). Et vous trouverez du code executable dans le dossier [\_examples](_examples/). - -### Vous préférez une version PDF? - - Book cover - -[![follow author](https://img.shields.io/twitter/follow/makismaropoulos.svg?style=for-the-badge)](https://twitter.com/intent/follow?screen_name=makismaropoulos) - -Vous pouvez [demander](https://bit.ly/iris-req-book) une version **E-Book** (en Anglais) de la documentation et contribuer au développement d'Iris. - -## 🙌 Contribuer - -Toute contribution à Iris est la bienvenue ! Pour plus d'informations sur la contribution au projet référez-vous au fichier [CONTRIBUTING.md](CONTRIBUTING.md). - -[Liste des contributeurs](https://github.com/kataras/iris/graphs/contributors) - -## 🛡 Sécurité et vulnérabilités - -Si vous trouvez une vulnérabilité dans Iris, envoyez un e-mail à [iris-go@outlook.com](mailto:iris-go@outlook.com). Toute vulnérabilité sera corrigée aussi rapidement que possible. - -## 📝 Licence - -Le projet est sous licence [licence BSD 3](LICENSE), tout comme le langage Go lui même. - -Le nom "Iris" est inspiré de la mythologie Grecque. - diff --git a/README_GR.md b/README_GR.md deleted file mode 100644 index b7d98ff6..00000000 --- a/README_GR.md +++ /dev/null @@ -1,80 +0,0 @@ -# Iris Web Framework - -[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) - -Το Iris είναι ένα γρήγορο, απλό αλλά και πλήρως λειτουργικό και πολύ αποδοτικό web framework για τη Go γλώσσα προγραμματισμού. Παρέχει ένα εκφραστικό και εύχρηστο υπόβαθρο για την επόμενη ιστοσελίδα σας. - -Μάθετε τι [λένε οι άλλοι για το Iris](https://iris-go.com/testimonials/) και δώστε ένα **αστεράκι** στο GitHub. - -[![](https://media.giphy.com/media/j5WLmtvwn98VPrm7li/giphy.gif)](https://iris-go.com/testimonials/) - -[![Benchmarks: Apr 2, 2020 at 12:13pm (UTC)](https://iris-go.com/images/benchmarks.svg)](https://github.com/kataras/server-benchmarks) - -## Μαθαίνοντας το Iris - -
-Γρήγορο ξεκίνημα - -```sh -# υποθέτοντας ότι ο παρακάτω κώδικας -# βρίσκεται στο example.go αρχείο -# -$ cat example.go -``` - -```go -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.Default() - app.Get("/ping", func(ctx iris.Context) { - ctx.JSON(iris.Map{ - "message": "pong", - }) - }) - - app.Listen(":8080") -} -``` - -```sh -# τρέξτε το example.go και -# επισκεφτείτε την σελίδα http://localhost:8080/ping -# στο πρόγραμμα περιήγησης σας -# -$ go run example.go -``` - -> Η δρομολόγηση τροφοδοτείται από το [muxie](https://github.com/kataras/muxie), το πιο ισχυρό και ταχύτερο λογισμικό βασισμένο σε trie αλγόριθμο που γράφτηκε σε Go. - -
- -Το Iris περιέχει εκτενείς και λεπτομερείς **[wiki](https://github.com/kataras/iris/wiki)** καθιστώντας το εύκολο στην εκμάθηση. - -Για λεπτομερέστερη τεχνική τεκμηρίωση μπορείτε να κατευθυνθείτε προς τα [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.0) μας. Και για εκτελέσιμο κώδικα μπορείτε πάντα να επισκέπτεστε τα [παραδείγματα](_examples/). - -### Σας αρέσει να διαβάζετε ενώ ταξιδεύετε; - -Μπορείτε να [ζητήσετε](https://bit.ly/iris-req-book) σήμερα την PDF έκδοση και την online πρόσβαση στο Ηλεκτρονικό μας **Βιβλίο(E-Book)** και να συμμετάσχετε στην ανάπτυξη του Iris. - -[![https://iris-go.com/images/iris-book-cover-sm.jpg](https://iris-go.com/images/iris-book-cover-sm.jpg)](https://bit.ly/iris-req-book) - -[![follow author](https://img.shields.io/twitter/follow/makismaropoulos.svg?style=for-the-badge)](https://twitter.com/intent/follow?screen_name=makismaropoulos) - -## Συνεισφορά - -Θα θέλαμε να δούμε τη συμβολή σας στο Iris Web Framework! Για περισσότερες πληροφορίες σχετικά με το πως μπορείτε να συμβάλετε, δείτε το [CONTRIBUTING.md](CONTRIBUTING.md) αρχείο. - -[Κατάλογος όλων των συνεισφορών](https://github.com/kataras/iris/graphs/contributors). - -## Αδυναμίες Ασφάλειας - -Εάν εντοπίσετε κάποια αδυναμία ασφαλείας του Iris, στείλτε ένα μήνυμα ηλεκτρονικού ταχυδρομείου στο [iris-go@outlook.com](mailto:iris-go@outlook.com). Όλες οι τυχών αδυναμίες ασφαλείας θα αντιμετωπιστούν άμεσα. - -## Άδεια Χρήσης - -Το όνομα "Iris" εμπνεύστηκε από την ελληνική μυθολογία, συγκεκριμένα από την θεά Ίριδα. - -Το Iris Web Framework είναι δωρεάν λογισμικό ανοιχτού λογισμικού με άδεια χρήσης [3-Clause BSD](LICENSE). diff --git a/README_KO.md b/README_KO.md deleted file mode 100644 index 97bd485b..00000000 --- a/README_KO.md +++ /dev/null @@ -1,76 +0,0 @@ -# Iris Web Framework - -[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) - -Iris는 단순하고 빠르며 좋은 성능과 모든 기능을 갖춘 Go언어용 웹 프레임워크입니다. 당신의 웹사이트나 API를 위해서 아름답고 사용하기 쉬운 기반을 제공합니다. - -[여러 사람들의 의견](https://iris-go.com/testimonials/)을 둘러보세요. 그리고 이 github repository을 **star**하세요. - -[![](https://media.giphy.com/media/j5WLmtvwn98VPrm7li/giphy.gif)](https://iris-go.com/testimonials/) - -[![Benchmarks: Apr 2, 2020 at 12:13pm (UTC)](https://iris-go.com/images/benchmarks.svg)](https://github.com/kataras/server-benchmarks) - -## Iris 배우기 - -
-일단 해보기 - -```sh -# 다음 코드를 example.go 화일에 입력하세요. -$ cat example.go -``` - -```go -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.Default() - app.Get("/ping", func(ctx iris.Context) { - ctx.JSON(iris.Map{ - "message": "pong", - }) - }) - - app.Listen(":8080") -} -``` - -```sh -# example.go 를 실행하고, -# 웹브라우저에서 http://localhost:8080/ping 를 열어보세요. -$ go run example.go -``` - -> 라우팅은 Go로 작성한 가장 강력하고 빠른 trie기반의 소프트웨어인 [muxie](https://github.com/kataras/muxie)로 처리합니다. - -
- -Iris는 광범위하고 꼼꼼한 **[wiki](https://github.com/kataras/iris/wiki)** 를 가지고 있기 때문에 쉽게 프레임워크를 시작할 수 있습니다. - -더 자세한 기술문서를 보시려면 [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.0)를 방문하세요. 그리고 실행가능한 예제코드는 [\_examples](_examples/) 하위 디렉토리에 있습니다. - -### 여행하면서 독서를 즐기세요? - - Book cover - -[![follow author](https://img.shields.io/twitter/follow/makismaropoulos.svg?style=for-the-badge)](https://twitter.com/intent/follow?screen_name=makismaropoulos) - -PDF 버전과 **E-Book** 에 대한 온라인 접근을 [요청](https://bit.ly/iris-req-book)하시고 Iris의 개발에 참가하실 수 있습니다. - -## 기여하기 - -Iris 웹 프레임워크에 대한 여러분의 기여를 환영합니다! Iris 프로젝트에 기여하는 방법에 대한 자세한 내용은 [CONTRIBUTING.md](CONTRIBUTING.md) 파일을 참조하십시오. - -[기여자 리스트](https://github.com/kataras/iris/graphs/contributors) - -## 보안 취약점 - -만약 Iris에서 보안 취약점을 발견하시면 [iris-go@outlook.com](mailto:iris-go@outlook.com) 로 메일을 보내주세요. 모든 보안 취약점은 즉 해결할 것입니다. - -## 라이센스 - -이 프로젝트의 이름 "Iris"는 그리스 신화에서 영감을 받았습니다. - -Iris 웹 프레임워크는 [3-Clause BSD License](LICENSE)를 가지는 무료 오픈소스 소프트웨어입니다. diff --git a/README_RU.md b/README_RU.md deleted file mode 100644 index 412456fb..00000000 --- a/README_RU.md +++ /dev/null @@ -1,81 +0,0 @@ -# Iris Web Framework - -[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) -Iris — это быстрый, простой, но полнофункциональный и эффективный веб-фреймворк для Go. Он обеспечивает красивую, выразительную и простую в использовании основу для вашего следующего веб-сайта или API. - -Узнайте, что [говорят другие люди об Iris](https://iris-go.com/testimonials/) и поставьте **[звёздочку](https://github.com/kataras/iris/stargazers)** этому проекту с открытым исходным кодом, чтобы поддержать его потенциал. - -[![](https://media.giphy.com/media/j5WLmtvwn98VPrm7li/giphy.gif)](https://iris-go.com/testimonials/) - -[![Benchmarks: Apr 2, 2020 at 12:13pm (UTC)](https://iris-go.com/images/benchmarks.svg)](https://github.com/kataras/server-benchmarks) - -## Изучение Iris - -
-Быстрый старт - -```sh -# например, код в файле example.go будет таким: -$ cat example.go -``` - -```go -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.Default() - app.Get("/ping", func(ctx iris.Context) { - ctx.JSON(iris.Map{ - "message": "pong", - }) - }) - - app.Listen(":8080") -} -``` - -```sh -# запустите example.go и перейдите в браузер -# по адресу http://localhost:8080/ping -$ go run example.go -``` - -> Система роутинга запросов работает на [muxie](https://github.com/kataras/muxie), мощное и быстрое trie-based ПО, написанное на Go. - -
- -У Iris есть исчерпывающий и тщательный **[wiki](https://github.com/kataras/iris/wiki)**, который позволит вам быстрее начать работу с фреймворком. - - - -Для получения более подробной технической документации вы можете обратиться к нашему [godoc](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.0). А для живых примеров кода — вы всегда можете посетить [\_examples](_examples/) в поддиректории этого репозитория. - -### Вы любите читать во время путешествий? - - Book cover - - - -Вы можете [запросить](https://bit.ly/iris-req-book) PDF версию и онлайн-доступ к **E-Book** сегодня и принять участие в разработке Iris. - -## Содействие - -Мы будем рады видеть ваш вклад в веб-фреймворк Iris! Для получения дополнительной информации о содействии проекту Iris, пожалуйста, проверьте файл [CONTRIBUTING.md](CONTRIBUTING.md). - -[Список всех участников](https://github.com/kataras/iris/graphs/contributors) - -## Уязвимость безопасности - -Если вы обнаружите уязвимость безопасности в Iris, отправьте электронное письмо по адресу [iris-go@outlook.com](mailto:iris-go@outlook.com). Все уязвимости безопасности будут оперативно устранены. - -## Лицензия - -Название проекта «Iris» было вдохновлено греческой мифологией. - -Веб-фреймворк Iris — это ПО с открытым исходным кодом под лицензией [3-Clause BSD License](LICENSE). - -## Накопление звёзд со временем - -[![Stargazers over time](https://starchart.cc/kataras/iris.svg)](https://starchart.cc/kataras/iris) diff --git a/README_ZH.md b/README_ZH.md deleted file mode 100644 index 4494aa5e..00000000 --- a/README_ZH.md +++ /dev/null @@ -1,216 +0,0 @@ -[![黑人的命也是命](https://iris-go.com/images/blacklivesmatter_banner.png)](https://support.eji.org/give/153413/#!/donation/checkout) - - - -> 这是一个**开发中的版本**。敬请关注即将发布的版本 [v12.2.0](HISTORY.md#Next)。如果想使用稳定版本,请查看 [v12.1.8 分支](https://github.com/kataras/iris/tree/v12.1.8) 。 -> -> ![](https://iris-go.com/images/cli.png) 立即尝试官方的[Iris命令行工具](https://github.com/kataras/iris-cli)! - - - -# Iris Web Framework - -[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![view examples](https://img.shields.io/badge/examples%20-173-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) - - - -Iris 是基于 Go 编写的一个快速,简单但功能齐全且非常高效的 Web 框架。 - -它为您的下一个网站或 API 提供了一个非常富有表现力且易于使用的基础。 - -看看 [其他人如何评价 Iris](https://iris-go.com/testimonials/),同时欢迎各位为此开源项目点亮 **[star](https://github.com/kataras/iris/stargazers)**。 - -[![](https://iris-go.com/images/reviews.gif)](https://iris-go.com/testimonials/) - -[![Benchmarks: Jul 18, 2020 at 10:46am (UTC)](https://iris-go.com/images/benchmarks.svg)](https://github.com/kataras/server-benchmarks) - -## 📖 开始学习 Iris - -```sh -# 安装Iris:https://github.com/kataras/iris/wiki/Installation -$ go get github.com/kataras/iris/v12@master -# 假设main.go文件中已存在以下代码 -$ cat main.go -``` - -```go -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - - booksAPI := app.Party("/books") - { - booksAPI.Use(iris.Compression) - - // GET: http://localhost:8080/books - booksAPI.Get("/", list) - // POST: http://localhost:8080/books - booksAPI.Post("/", create) - } - - app.Listen(":8080") -} - -// Book example. -type Book struct { - Title string `json:"title"` -} - -func list(ctx iris.Context) { - books := []Book{ - {"Mastering Concurrency in Go"}, - {"Go Design Patterns"}, - {"Black Hat Go"}, - } - - ctx.JSON(books) - // 提示: 在服务器优先级和客户端请求中进行响应协商, - // 以此来代替 ctx.JSON: - // ctx.Negotiation().JSON().MsgPack().Protobuf() - // ctx.Negotiate(books) -} - -func create(ctx iris.Context) { - var b Book - err := ctx.ReadJSON(&b) - // 提示: 使用 ctx.ReadBody(&b) 代替,来绑定所有类型的入参 - if err != nil { - ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem(). - Title("Book creation failure").DetailErr(err)) - // 提示: 如果仅有纯文本(plain text)错误响应, - // 可使用 ctx.StopWithError(code, err) - return - } - - println("Received Book: " + b.Title) - - ctx.StatusCode(iris.StatusCreated) -} -``` - -同样地,在**MVC**中 : - -```go -import "github.com/kataras/iris/v12/mvc" -``` - -```go -m := mvc.New(booksAPI) -m.Handle(new(BookController)) -``` - -```go -type BookController struct { - /* dependencies */ -} - -// GET: http://localhost:8080/books -func (c *BookController) Get() []Book { - return []Book{ - {"Mastering Concurrency in Go"}, - {"Go Design Patterns"}, - {"Black Hat Go"}, - } -} - -// POST: http://localhost:8080/books -func (c *BookController) Post(b Book) int { - println("Received Book: " + b.Title) - - return iris.StatusCreated -} -``` - -**启动** 您的 Iris web 服务: - -```sh -$ go run main.go -> Now listening on: http://localhost:8080 -> Application started. Press CTRL+C to shut down. -``` - -Books **列表查询** : - -```sh -$ curl --header 'Accept-Encoding:gzip' http://localhost:8080/books - -[ - { - "title": "Mastering Concurrency in Go" - }, - { - "title": "Go Design Patterns" - }, - { - "title": "Black Hat Go" - } -] -``` - -**创建** 新的Book: - -```sh -$ curl -i -X POST \ ---header 'Content-Encoding:gzip' \ ---header 'Content-Type:application/json' \ ---data "{\"title\":\"Writing An Interpreter In Go\"}" \ -http://localhost:8080/books - -> HTTP/1.1 201 Created -``` - -这是**错误**响应所展示的样子: - -```sh -$ curl -X POST --data "{\"title\" \"not valid one\"}" \ -http://localhost:8080/books - -> HTTP/1.1 400 Bad Request - -{ - "status": 400, - "title": "Book creation failure" - "detail": "invalid character '\"' after object key", -} -``` - - - -[![run in the browser](https://img.shields.io/badge/Run-in%20the%20Browser-348798.svg?style=for-the-badge&logo=repl.it)](https://bit.ly/2YJeSZe) - -Iris 有完整且详尽的 **[使用文档](https://github.com/kataras/iris/wiki)** ,让您可以轻松地使用此框架。 - - - -要了解更详细的技术文档,请访问我们的 [godocs](https://godoc.org/github.com/kataras/iris)。如果想要寻找代码示例,您可以到仓库的 [./_examples](_examples) 子目录下获取。 - -### 你喜欢在旅行时阅读吗? - - Book cover - -[![follow Iris web framework on twitter](https://img.shields.io/twitter/follow/iris_framework?color=ee7506&logoColor=ee7506&style=for-the-badge)](https://twitter.com/intent/follow?screen_name=iris_framework) - -您可以[获取](https://bit.ly/iris-req-book)PDF版本或在线访问**电子图书**,并参与到Iris的开发中。 - -## 🙌 贡献 - -我们欢迎您为Iris框架做出贡献!想要知道如何为Iris项目做贡献,请查看[CONTRIBUTING.md](CONTRIBUTING.md)。 - -[贡献者名单](https://github.com/kataras/iris/graphs/contributors) - -## 🛡 安全漏洞 - -如果您发现在 Iris 存在安全漏洞,请发送电子邮件至 [iris-go@outlook.com](mailto:iris-go@outlook.com)。所有安全漏洞将会得到及时解决。 - -## 📝 开源协议(License) - -就像Go语言的协议一样,此项目也采用 [BSD 3-clause license](LICENSE)。 - -项目名称 "Iris" 的灵感来自于希腊神话。 - - diff --git a/VERSION b/VERSION deleted file mode 100644 index b56d45d5..00000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -12.1.8:https://github.com/kataras/iris/releases/tag/v12.1.8 \ No newline at end of file diff --git a/_examples/README.md b/_examples/README.md deleted file mode 100644 index 536a7567..00000000 --- a/_examples/README.md +++ /dev/null @@ -1,219 +0,0 @@ -# Table of Contents - -* [REST API for Apache Kafka](kafka-api) -* [URL Shortener](url-shortener) -* [Dropzone.js](dropzonejs) -* [Caddy](caddy) -* Database - * [MySQL, Groupcache & Docker](database/mysql) - * [MongoDB](database/mongodb) - * [Xorm](database/orm/xorm/main.go) - * [Gorm](database/orm/gorm/main.go) - * [Reform](database/orm/reform/main.go) -* HTTP Server - * [HOST:PORT](http-server/listen-addr/main.go) - * [Public Test Domain](http-server/listen-addr-public/main.go) - * [UNIX socket file](http-server/listen-unix/main.go) - * [TLS](http-server/listen-tls/main.go) - * [Letsencrypt (Automatic Certifications)](http-server/listen-letsencrypt/main.go) - * [Socket Sharding (SO_REUSEPORT)](http-server/socket-sharding/main.go) - * [Graceful Shutdown](http-server/graceful-shutdown/default-notifier/main.go) - * [Notify on shutdown](http-server/notify-on-shutdown/main.go) - * Custom TCP Listener - * [Common net.Listener](http-server/custom-listener/main.go) - * Custom HTTP Server - * [Pass a custom Server](http-server/custom-httpserver/easy-way/main.go) - * [Use Iris as a single http.Handler](http-server/custom-httpserver/std-way/main.go) - * [Multi Instances](http-server/custom-httpserver/multi/main.go) - * [HTTP/3 Quic](http-server/http3-quic) -* Configuration - * [Functional](configuration/functional/main.go) - * [Configuration Struct](configuration/from-configuration-structure/main.go) - * [Import from YAML](configuration/from-yaml-file/main.go) - * [Share Configuration across instances](configuration/from-yaml-file/shared-configuration/main.go) - * [Import from TOML](configuration/from-toml-file/main.go) -* Routing - * [Overview](routing/overview/main.go) - * [Basic](routing/basic/main.go) - * [Custom HTTP Errors](routing/http-errors/main.go) - * [Not Found - Intelligence](routing/intelligence/main.go) - * [Not Found - Suggest Closest Paths](routing/intelligence/manual/main.go) - * [Dynamic Path](routing/dynamic-path/main.go) - * [Root Wildcard](routing/dynamic-path/root-wildcard/main.go) - * [Implement a Parameter Type](routing/macros/main.go) - * [Same Path Pattern but Func](routing/dynamic-path/same-pattern-different-func/main.go) - * Middleware - * [Per Route](routing/writing-a-middleware/per-route/main.go) - * [Globally](routing/writing-a-middleware/globally/main.go) - * [Handlers Execution Rule](routing/route-handlers-execution-rules/main.go) - * [Route Register Rule](routing/route-register-rule/main.go) - * Convert net/http Handlers - * [From func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)](convert-handlers/negroni-like/main.go) - * [From http.Handler or http.HandlerFunc](convert-handlers/nethttp/main.go) - * [From func(http.HandlerFunc) http.HandlerFunc](convert-handlers/real-usecase-raven/writing-middleware/main.go) - * [Route State](routing/route-state/main.go) - * [Reverse Routing](routing/reverse/main.go) - * [Router Wrapper](routing/custom-wrapper/main.go) - * [Custom Router](routing/custom-router/main.go) - * Subdomains - * [Single](routing/subdomains/single/main.go) - * [Multi](routing/subdomains/multi/main.go) - * [Wildcard](routing/subdomains/wildcard/main.go) - * [WWW](routing/subdomains/www/main.go) - * [Redirection](routing/subdomains/redirect/main.go) - * [HTTP Method Override](https://github.com/kataras/iris/blob/master/middleware/methodoverride/methodoverride_test.go) - * [API Versioning](routing/versioning/main.go) - * [Sitemap](routing/sitemap/main.go) -* Logging - * [Request Logger](logging/request-logger/main.go) - * [Log Requests to a File](logging/request-logger/request-logger-file/main.go) - * [Log Requests to a JSON File](logging/request-logger/request-logger-file-json/main.go) - * [Application File Logger](logging/file-logger/main.go) - * [Application JSON Logger](logging/json-logger/main.go) - * [Rollbar](logging/rollbar/main.go) -* API Documentation - * [Yaag](apidoc/yaag/main.go) - * [Swagger](https://github.com/iris-contrib/swagger/tree/master/example) -* [Testing](testing/httptest/main_test.go) -* [Recovery](recover/main.go) -* [Profiling](pprof/main.go) -* File Server - * [File Server](file-server/file-server/main.go) - * [HTTP/2 Push Targets](file-server/http2push/main.go) - * [HTTP/2 Push Targets (Embedded)](file-server/http2push-embedded/main.go) - * [HTTP/2 Push Targets (Gzipped Embedded)](file-server/http2push-embedded-gzipped/main.go) - * [Favicon](file-server/favicon/main.go) - * [Basic](file-server/basic/main.go) - * [Embedding Files Into App Executable File](file-server/embedding-files-into-app/main.go) - * [Embedding Gzipped Files Into App Executable File](file-server/embedding-gzipped-files-into-app/main.go) - * [Send Files (rate limiter included)](file-server/send-files/main.go) - * Single Page Applications - * [Basic SPA](file-server/single-page-application/basic/main.go) - * [Embedded Single Page Application](file-server/single-page-application/embedded-single-page-application/main.go) - * [Embedded Single Page Application with other routes](file-server/single-page-application/embedded-single-page-application-with-other-routes/main.go) - * [Upload File](file-server/upload-file/main.go) - * [Upload Multiple Files](file-server/upload-files/main.go) -* View - * [Overview](view/overview/main.go) - * [Basic](view/template_html_0/main.go) - * [A simple Layout](view/template_html_1/main.go) - * [Layouts: `yield` and `render` tmpl funcs](view/template_html_2/main.go) - * [The `urlpath` tmpl func](view/template_html_3/main.go) - * [The `url` tmpl func](view/template_html_4/main.go) - * [Inject Data Between Handlers](view/context-view-data/main.go) - * [Inject Engine Between Handlers](view/context-view-engine/main.go) - * [Embedding Templates Into App Executable File](view/embedding-templates-into-app/main.go) - * [Write to a custom `io.Writer`](view/write-to) - * [Blocks](view/template_blocks_0) - * [Blocks Embedded](view/template_blocks_1_embedded) - * [Pug: Greeting](view/template_pug_0) - * [Pug: `Actions`](view/template_pug_1) - * [Pug: `Includes`](view/template_pug_2) - * [Pug: `Extends`](view/template_pug_3) - * [Jet Template](view/template_jet_0) - * [Jet Embedded](view/template_jet_1_embedded) - * [Jet 'urlpath' tmpl func](view/template_jet_2) - * [Jet Template Funcs from Struct](view/template_jet_3) - - [Ace](view/template_ace_0) - * Third-Parties - * [Render `valyala/quicktemplate` templates](view/quicktemplate) - * [Render `shiyanhui/hero` templates](view/herotemplate) -* [Request ID](https://github.com/kataras/iris/blob/master/middleware/requestid/requestid_test.go) -* [Request Rate Limit](request-ratelimit/main.go) -* [Request Referrer](request-referrer/main.go) -* [Webassembly](webassembly/main.go) -* Request Body - * [Bind JSON](request-body/read-json/main.go) - * * [Struct Validation](request-body/read-json-struct-validation/main.go) - * [Bind XML](request-body/read-xml/main.go) - * [Bind MsgPack](request-body/read-msgpack/main.go) - * [Bind YAML](request-body/read-yaml/main.go) - * [Bind Form](request-body/read-form/main.go) - * [Bind Query](request-body/read-query/main.go) - * [Bind Body](request-body/read-body/main.go) - * [Bind Custom per type](request-body/read-custom-per-type/main.go) - * [Bind Custom via Unmarshaler](request-body/read-custom-via-unmarshaler/main.go) - * [Bind Many times](request-body/read-many/main.go) -* Response Writer - * [Content Negotiation](response-writer/content-negotiation) - * [Text, Markdown, YAML, HTML, JSON, JSONP, Msgpack, XML and Binary](response-writer/write-rest/main.go) - * [Protocol Buffers](response-writer/protobuf/main.go) - * [HTTP/2 Server Push](response-writer/http2push/main.go) - * [Stream Writer](response-writer/stream-writer/main.go) - * [Transactions](response-writer/transactions/main.go) - * [SSE](response-writer/sse/main.go) - * [SSE (third-party package usage for server sent events)](response-writer/sse-third-party/main.go) - * Cache - * [Simple](response-writer/cache/simple/main.go) - * [Client-Side (304)](response-writer/cache/client-side/main.go) -* Compression - * [Server-Side](compression/main.go) - * [Client-Side](compression/client/main.go) - * [Client-Side (using Iris)](compress/client-using-iris/main.go) -* Localization and Internationalization - * [i18n](i18n/main.go) -* Authentication, Authorization & Bot Detection - * [Basic Authentication](auth/basicauth/main.go) - * [CORS](auth/cors) - * [JWT](auth/jwt/main.go) - * [JWT (community edition)](https://github.com/iris-contrib/middleware/tree/v12/jwt/_example/main.go) - * [OAUth2](auth/goth/main.go) - * [Manage Permissions](auth/permissions/main.go) - * [Google reCAPTCHA](auth/recaptcha/main.go) - * [hCaptcha](auth/hcaptcha/main.go) -* Cookies - * [Basic](cookies/basic/main.go) - * [Options](cookies/options/main.go) - * [Encode/Decode (with `securecookie`)](cookies/securecookie/main.go) -* Sessions - * [Overview: Config](sessions/overview/main.go) - * [Overview: Routes](sessions/overview/example/example.go) - * [Basic](sessions/basic/main.go) - * [Secure Cookie](sessions/securecookie/main.go) - * [Flash Messages](sessions/flash-messages/main.go) - * [Databases](sessions/database) - * [Badger](sessions/database/badger/main.go) - * [BoltDB](sessions/database/boltdb/main.go) - * [Redis](sessions/database/redis/main.go) -* Websocket - * [Gorilla FileWatch (3rd-party)](websocket/gorilla-filewatch/main.go) - * [Basic](websocket/basic) - * [Server](websocket/basic/server.go) - * [Go Client](websocket/basic/go-client/client.go) - * [Browser Client](websocket/basic/browser/index.html) - * [Browser NPM Client (browserify)](websocket/basic/browserify/app.js) - * [Native Messages](websocket/native-messages/main.go) - * [TLS](websocket/secure/README.md) - * [Online Visitors](websocket/online-visitors/main.go) -* Dependency Injection - * [Overview (Movies Service)](ependency-injection/overview/main.go) - * [Basic](dependency-injection/basic/main.go) - * [Middleware](dependency-injection/basic/middleware/main.go) - * [Sessions](dependency-injection/sessions/main.go) - * [Smart Contract](dependency-injection/smart-contract/main.go) - * [JWT](dependency-injection/jwt/main.go) - * [JWT (iris-contrib)](dependency-injection/jwt/contrib/main.go) - * [Register Dependency from Context](dependency-injection/context-register-dependency/main.go) -* MVC - * [Overview](mvc/overview) - * [Repository and Service layers](mvc/repository) - * [Hello world](mvc/hello-world/main.go) - * [Basic](mvc/basic/main.go) - * [Wildcard](mvc/basic/wildcard/main.go) - * [Singleton](mvc/singleton) - * [Regexp](mvc/regexp/main.go) - * [Session Controller](mvc/session-controller/main.go) - * [Authenticated Controller](mvc/authenticated-controller/main.go) - * [Versioned Controller](mvc/versioned-controller/main.go) - * [Websocket Controller](mvc/websocket) - * [Register Middleware](mvc/middleware) - * [gRPC](mvc/grpc-compatible) - * [Login (Repository and Service layers)](mvc/login) - * [Login (Single Responsibility)](mvc/login-mvc-single-responsibility) - * [Vue.js Todo App](mvc/vuejs-todo-mvc) -* [Bootstrapper](bootstrapper) -* Desktop Applications - * [The blink package](desktop/blink) - * [The lorca package](desktop/lorca) - * [The webview package](desktop/webview) -* Middlewares [(Community)](https://github.com/iris-contrib/middleware) diff --git a/_examples/apidoc/swagger/README.md b/_examples/apidoc/swagger/README.md deleted file mode 100644 index 08e23049..00000000 --- a/_examples/apidoc/swagger/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Swagger 2.0 - -Visit https://github.com/iris-contrib/swagger instead. diff --git a/_examples/apidoc/yaag/go.mod b/_examples/apidoc/yaag/go.mod deleted file mode 100644 index e1c27c2f..00000000 --- a/_examples/apidoc/yaag/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/kataras/iris/_examples/apidoc/yaag - -go 1.15 - -require ( - github.com/betacraft/yaag v1.0.1-0.20200719063524-47d781406108 - github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd -) diff --git a/_examples/apidoc/yaag/main.go b/_examples/apidoc/yaag/main.go deleted file mode 100644 index a50b346c..00000000 --- a/_examples/apidoc/yaag/main.go +++ /dev/null @@ -1,55 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - - "github.com/betacraft/yaag/irisyaag" - "github.com/betacraft/yaag/yaag" -) - -type myXML struct { - Result string `xml:"result"` -} - -func main() { - app := iris.New() - - yaag.Init(&yaag.Config{ // <- IMPORTANT, init the middleware. - On: true, - DocTitle: "Iris", - DocPath: "apidoc.html", - BaseUrls: map[string]string{"Production": "", "Staging": ""}, - }) - app.Use(irisyaag.New()) // <- IMPORTANT, register the middleware. - - app.Get("/json", func(ctx iris.Context) { - ctx.JSON(iris.Map{"result": "Hello World!"}) - }) - - app.Get("/plain", func(ctx iris.Context) { - ctx.Text("Hello World!") - }) - - app.Get("/xml", func(ctx iris.Context) { - ctx.XML(myXML{Result: "Hello World!"}) - }) - - app.Get("/complex", func(ctx iris.Context) { - value := ctx.URLParam("key") - ctx.JSON(iris.Map{"value": value}) - }) - - // Run our HTTP Server. - // - // Documentation of "yaag" doesn't note the follow, but in Iris we are careful on what - // we provide to you. - // - // Each incoming request results on re-generation and update of the "apidoc.html" file. - // Recommentation: - // Write tests that calls those handlers, save the generated "apidoc.html". - // Turn off the yaag middleware when in production. - // - // Example usage: - // Visit all paths and open the generated "apidoc.html" file to see the API's automated docs. - app.Listen(":8080") -} diff --git a/_examples/auth/basicauth/main.go b/_examples/auth/basicauth/main.go deleted file mode 100644 index cfc279f0..00000000 --- a/_examples/auth/basicauth/main.go +++ /dev/null @@ -1,57 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/basicauth" -) - -func newApp() *iris.Application { - app := iris.New() - - authConfig := basicauth.Config{ - Users: map[string]string{"myusername": "mypassword", "mySecondusername": "mySecondpassword"}, - Realm: "Authorization Required", // defaults to "Authorization Required" - Expires: time.Duration(30) * time.Minute, - } - - authentication := basicauth.New(authConfig) - - // to global app.Use(authentication) (or app.UseGlobal before the .Run) - // to routes - /* - app.Get("/mysecret", authentication, h) - */ - - app.Get("/", func(ctx iris.Context) { ctx.Redirect("/admin") }) - - // to party - - needAuth := app.Party("/admin", authentication) - { - //http://localhost:8080/admin - needAuth.Get("/", h) - // http://localhost:8080/admin/profile - needAuth.Get("/profile", h) - - // http://localhost:8080/admin/settings - needAuth.Get("/settings", h) - } - - return app -} - -func main() { - app := newApp() - // open http://localhost:8080/admin - app.Listen(":8080") -} - -func h(ctx iris.Context) { - username, password, _ := ctx.Request().BasicAuth() - // third parameter it will be always true because the middleware - // makes sure for that, otherwise this handler will not be executed. - - ctx.Writef("%s %s:%s", ctx.Path(), username, password) -} diff --git a/_examples/auth/basicauth/main_test.go b/_examples/auth/basicauth/main_test.go deleted file mode 100644 index e3f27486..00000000 --- a/_examples/auth/basicauth/main_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestBasicAuth(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - // redirects to /admin without basic auth - e.GET("/").Expect().Status(httptest.StatusUnauthorized) - // without basic auth - e.GET("/admin").Expect().Status(httptest.StatusUnauthorized) - - // with valid basic auth - e.GET("/admin").WithBasicAuth("myusername", "mypassword").Expect(). - Status(httptest.StatusOK).Body().Equal("/admin myusername:mypassword") - e.GET("/admin/profile").WithBasicAuth("myusername", "mypassword").Expect(). - Status(httptest.StatusOK).Body().Equal("/admin/profile myusername:mypassword") - e.GET("/admin/settings").WithBasicAuth("myusername", "mypassword").Expect(). - Status(httptest.StatusOK).Body().Equal("/admin/settings myusername:mypassword") - - // with invalid basic auth - e.GET("/admin/settings").WithBasicAuth("invalidusername", "invalidpassword"). - Expect().Status(httptest.StatusUnauthorized) -} diff --git a/_examples/auth/cors/main.go b/_examples/auth/cors/main.go deleted file mode 100644 index c5b6c5e8..00000000 --- a/_examples/auth/cors/main.go +++ /dev/null @@ -1,63 +0,0 @@ -// Package main integrates the "rs/cors" net/http middleware into Iris. -// That cors third-party middleware cannot be registered through `iris.FromStd` -// as a common middleware because it should be injected before the Iris Router itself, -// it allows/dissallows HTTP Methods too. -// -// This is just an example you can use to run something, based on custom logic, -// before the Iris Router itself. -// -// In the "routing/custom-wrapper" example -// we learn how we can acquire and release an Iris context to fire an Iris Handler -// based on custom logic, before the Iris Router itself. In that example -// we will fire a net/http handler (the "rs/cors" handler one) instead. -// -// https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/rs/cors" -) - -func main() { - app := iris.New() - c := cors.New(cors.Options{ - AllowedOrigins: []string{"*"}, - AllowCredentials: true, - // Enable Debugging for testing, consider disabling in production - Debug: true, - }) - // app.WrapRouter(func(w http.ResponseWriter, r *http.Request, router http.HandlerFunc) { - // [custom logic...] - // if shouldFireNetHTTPHandler { - // ...ServeHTTP(w,r) - // return - // } - // router(w,r) - // }) - // In our case, the cors package has a ServeHTTP - // of the same form of app.WrapRouter's accept input argument, - // so we can just do: - app.WrapRouter(c.ServeHTTP) - - // Serve ./public/index.html, main.js. - app.HandleDir("/", iris.Dir("./public")) - - // Register routes here... - app.Get("/data", listData) - - // http://localhost:8080 and click the "fetch data" button. - app.Listen(":8080") -} - -type item struct { - Title string `json:"title"` -} - -func listData(ctx iris.Context) { - ctx.JSON([]item{ - {"Item 1"}, - {"Item 2"}, - {"Item 3"}, - }) -} diff --git a/_examples/auth/cors/public/index.html b/_examples/auth/cors/public/index.html deleted file mode 100644 index 7f36d6ce..00000000 --- a/_examples/auth/cors/public/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - Iris Cors Example - - - -
    -
- - - - - - \ No newline at end of file diff --git a/_examples/auth/cors/public/main.js b/_examples/auth/cors/public/main.js deleted file mode 100644 index aa83baf3..00000000 --- a/_examples/auth/cors/public/main.js +++ /dev/null @@ -1,43 +0,0 @@ -// https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch -async function doRequest(method = 'GET', url = '', data = {}) { - // Default options are marked with * - - const request = { - method: method, // *GET, POST, PUT, DELETE, etc. - mode: 'cors', // no-cors, *cors, same-origin - cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached - credentials: 'same-origin', // include, *same-origin, omit - redirect: 'follow', // manual, *follow, error - referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url - }; - - if (data !== undefined && method !== 'GET' && method !== 'HEAD') { - request.headers = { - 'Content-Type': 'application/json' - // 'Content-Type': 'application/x-www-form-urlencoded', - }; - // body data type must match "Content-Type" header. - request.body = JSON.stringify(data); - } - - const response = await fetch(url, request); - return response.json(); // parses JSON response into native JavaScript objects. -} - -const ul = document.getElementById("list"); - -function fetchData() { - console.log("sending request...") - - doRequest('GET', '/data').then(data => { - data.forEach(item => { - var li = document.createElement("li"); - li.appendChild(document.createTextNode(item.title)); - ul.appendChild(li); - }); - - console.log(data); // JSON data parsed by `response.json()` call. - }); -} - -document.getElementById("fetchBtn").onclick = fetchData; \ No newline at end of file diff --git a/_examples/auth/goth/main.go b/_examples/auth/goth/main.go deleted file mode 100644 index 0e79e972..00000000 --- a/_examples/auth/goth/main.go +++ /dev/null @@ -1,407 +0,0 @@ -package main - -// Any OAuth2 (even the pure golang/x/net/oauth2) package -// can be used with iris but at this example we will see the markbates' goth: -// -// $ go get github.com/markbates/goth/... -// -// This OAuth2 example works with sessions, so we will need -// to attach a session manager. -// Optionally: for even more secure session values, -// developers can use any third-party package to add a custom cookie encoder/decoder. -// At this example we will use the gorilla's securecookie: -// -// $ go get github.com/gorilla/securecookie -// Example of securecookie can be found at "sessions/securecookie" example folder. - -// Notes: -// The whole example is converted by markbates/goth/example/main.go. -// It's tested with my own TWITTER application and it worked, even for localhost. -// I guess that everything else works as expected, all bugs reported by goth library's community -// are fixed in the time I wrote that example, have fun! -import ( - "errors" - "os" - "sort" - - "github.com/kataras/iris/v12" - - "github.com/kataras/iris/v12/sessions" - - "github.com/gorilla/securecookie" // optionally, used for session's encoder/decoder - - "github.com/markbates/goth" - "github.com/markbates/goth/providers/amazon" - "github.com/markbates/goth/providers/auth0" - "github.com/markbates/goth/providers/bitbucket" - "github.com/markbates/goth/providers/box" - "github.com/markbates/goth/providers/dailymotion" - "github.com/markbates/goth/providers/deezer" - "github.com/markbates/goth/providers/digitalocean" - "github.com/markbates/goth/providers/discord" - "github.com/markbates/goth/providers/dropbox" - "github.com/markbates/goth/providers/facebook" - "github.com/markbates/goth/providers/fitbit" - "github.com/markbates/goth/providers/github" - "github.com/markbates/goth/providers/gitlab" - "github.com/markbates/goth/providers/gplus" - "github.com/markbates/goth/providers/heroku" - "github.com/markbates/goth/providers/instagram" - "github.com/markbates/goth/providers/intercom" - "github.com/markbates/goth/providers/lastfm" - "github.com/markbates/goth/providers/linkedin" - "github.com/markbates/goth/providers/meetup" - "github.com/markbates/goth/providers/onedrive" - "github.com/markbates/goth/providers/openidConnect" - "github.com/markbates/goth/providers/paypal" - "github.com/markbates/goth/providers/salesforce" - "github.com/markbates/goth/providers/slack" - "github.com/markbates/goth/providers/soundcloud" - "github.com/markbates/goth/providers/spotify" - "github.com/markbates/goth/providers/steam" - "github.com/markbates/goth/providers/stripe" - "github.com/markbates/goth/providers/twitch" - "github.com/markbates/goth/providers/twitter" - "github.com/markbates/goth/providers/uber" - "github.com/markbates/goth/providers/wepay" - "github.com/markbates/goth/providers/xero" - "github.com/markbates/goth/providers/yahoo" - "github.com/markbates/goth/providers/yammer" -) - -var sessionsManager *sessions.Sessions - -func init() { - // attach a session manager - cookieName := "mycustomsessionid" - hashKey := securecookie.GenerateRandomKey(64) - blockKey := securecookie.GenerateRandomKey(32) - secureCookie := securecookie.New(hashKey, blockKey) - - sessionsManager = sessions.New(sessions.Config{ - Cookie: cookieName, - Encoding: secureCookie, - AllowReclaim: true, - }) -} - -// These are some function helpers that you may use if you want - -// GetProviderName is a function used to get the name of a provider -// for a given request. By default, this provider is fetched from -// the URL query string. If you provide it in a different way, -// assign your own function to this variable that returns the provider -// name for your request. -var GetProviderName = func(ctx iris.Context) (string, error) { - // try to get it from the url param "provider" - if p := ctx.URLParam("provider"); p != "" { - return p, nil - } - - // try to get it from the url PATH parameter "{provider} or :provider or {provider:string} or {provider:alphabetical}" - if p := ctx.Params().Get("provider"); p != "" { - return p, nil - } - - // try to get it from context's per-request storage - if p := ctx.Values().GetString("provider"); p != "" { - return p, nil - } - // if not found then return an empty string with the corresponding error - return "", errors.New("you must select a provider") -} - -/* -BeginAuthHandler is a convenience handler for starting the authentication process. -It expects to be able to get the name of the provider from the query parameters -as either "provider" or ":provider". - -BeginAuthHandler will redirect the user to the appropriate authentication end-point -for the requested provider. - -See https://github.com/markbates/goth/examples/main.go to see this in action. -*/ -func BeginAuthHandler(ctx iris.Context) { - url, err := GetAuthURL(ctx) - if err != nil { - ctx.StatusCode(iris.StatusBadRequest) - ctx.Writef("%v", err) - return - } - - ctx.Redirect(url, iris.StatusTemporaryRedirect) -} - -/* -GetAuthURL starts the authentication process with the requested provided. -It will return a URL that should be used to send users to. - -It expects to be able to get the name of the provider from the query parameters -as either "provider" or ":provider" or from the context's value of "provider" key. - -I would recommend using the BeginAuthHandler instead of doing all of these steps -yourself, but that's entirely up to you. -*/ -func GetAuthURL(ctx iris.Context) (string, error) { - providerName, err := GetProviderName(ctx) - if err != nil { - return "", err - } - - provider, err := goth.GetProvider(providerName) - if err != nil { - return "", err - } - sess, err := provider.BeginAuth(SetState(ctx)) - if err != nil { - return "", err - } - - url, err := sess.GetAuthURL() - if err != nil { - return "", err - } - session := sessionsManager.Start(ctx) - session.Set(providerName, sess.Marshal()) - return url, nil -} - -// SetState sets the state string associated with the given request. -// If no state string is associated with the request, one will be generated. -// This state is sent to the provider and can be retrieved during the -// callback. -var SetState = func(ctx iris.Context) string { - state := ctx.URLParam("state") - if len(state) > 0 { - return state - } - - return "state" -} - -// GetState gets the state returned by the provider during the callback. -// This is used to prevent CSRF attacks, see -// http://tools.ietf.org/html/rfc6749#section-10.12 -var GetState = func(ctx iris.Context) string { - return ctx.URLParam("state") -} - -/* -CompleteUserAuth does what it says on the tin. It completes the authentication -process and fetches all of the basic information about the user from the provider. - -It expects to be able to get the name of the provider from the query parameters -as either "provider" or ":provider". - -See https://github.com/markbates/goth/examples/main.go to see this in action. -*/ -var CompleteUserAuth = func(ctx iris.Context) (goth.User, error) { - providerName, err := GetProviderName(ctx) - if err != nil { - return goth.User{}, err - } - - provider, err := goth.GetProvider(providerName) - if err != nil { - return goth.User{}, err - } - session := sessionsManager.Start(ctx) - value := session.GetString(providerName) - if value == "" { - return goth.User{}, errors.New("session value for " + providerName + " not found") - } - - sess, err := provider.UnmarshalSession(value) - if err != nil { - return goth.User{}, err - } - - user, err := provider.FetchUser(sess) - if err == nil { - // user can be found with existing session data - return user, err - } - - // get new token and retry fetch - _, err = sess.Authorize(provider, ctx.Request().URL.Query()) - if err != nil { - return goth.User{}, err - } - - session.Set(providerName, sess.Marshal()) - return provider.FetchUser(sess) -} - -// Logout invalidates a user session. -func Logout(ctx iris.Context) error { - providerName, err := GetProviderName(ctx) - if err != nil { - return err - } - session := sessionsManager.Start(ctx) - session.Delete(providerName) - return nil -} - -// End of the "some function helpers". - -func main() { - goth.UseProviders( - twitter.New(os.Getenv("TWITTER_KEY"), os.Getenv("TWITTER_SECRET"), "http://localhost:3000/auth/twitter/callback"), - // If you'd like to use authenticate instead of authorize in Twitter provider, use this instead. - // twitter.NewAuthenticate(os.Getenv("TWITTER_KEY"), os.Getenv("TWITTER_SECRET"), "http://localhost:3000/auth/twitter/callback"), - - facebook.New(os.Getenv("FACEBOOK_KEY"), os.Getenv("FACEBOOK_SECRET"), "http://localhost:3000/auth/facebook/callback"), - fitbit.New(os.Getenv("FITBIT_KEY"), os.Getenv("FITBIT_SECRET"), "http://localhost:3000/auth/fitbit/callback"), - gplus.New(os.Getenv("GPLUS_KEY"), os.Getenv("GPLUS_SECRET"), "http://localhost:3000/auth/gplus/callback"), - github.New(os.Getenv("GITHUB_KEY"), os.Getenv("GITHUB_SECRET"), "http://localhost:3000/auth/github/callback"), - spotify.New(os.Getenv("SPOTIFY_KEY"), os.Getenv("SPOTIFY_SECRET"), "http://localhost:3000/auth/spotify/callback"), - linkedin.New(os.Getenv("LINKEDIN_KEY"), os.Getenv("LINKEDIN_SECRET"), "http://localhost:3000/auth/linkedin/callback"), - lastfm.New(os.Getenv("LASTFM_KEY"), os.Getenv("LASTFM_SECRET"), "http://localhost:3000/auth/lastfm/callback"), - twitch.New(os.Getenv("TWITCH_KEY"), os.Getenv("TWITCH_SECRET"), "http://localhost:3000/auth/twitch/callback"), - dropbox.New(os.Getenv("DROPBOX_KEY"), os.Getenv("DROPBOX_SECRET"), "http://localhost:3000/auth/dropbox/callback"), - digitalocean.New(os.Getenv("DIGITALOCEAN_KEY"), os.Getenv("DIGITALOCEAN_SECRET"), "http://localhost:3000/auth/digitalocean/callback", "read"), - bitbucket.New(os.Getenv("BITBUCKET_KEY"), os.Getenv("BITBUCKET_SECRET"), "http://localhost:3000/auth/bitbucket/callback"), - instagram.New(os.Getenv("INSTAGRAM_KEY"), os.Getenv("INSTAGRAM_SECRET"), "http://localhost:3000/auth/instagram/callback"), - intercom.New(os.Getenv("INTERCOM_KEY"), os.Getenv("INTERCOM_SECRET"), "http://localhost:3000/auth/intercom/callback"), - box.New(os.Getenv("BOX_KEY"), os.Getenv("BOX_SECRET"), "http://localhost:3000/auth/box/callback"), - salesforce.New(os.Getenv("SALESFORCE_KEY"), os.Getenv("SALESFORCE_SECRET"), "http://localhost:3000/auth/salesforce/callback"), - amazon.New(os.Getenv("AMAZON_KEY"), os.Getenv("AMAZON_SECRET"), "http://localhost:3000/auth/amazon/callback"), - yammer.New(os.Getenv("YAMMER_KEY"), os.Getenv("YAMMER_SECRET"), "http://localhost:3000/auth/yammer/callback"), - onedrive.New(os.Getenv("ONEDRIVE_KEY"), os.Getenv("ONEDRIVE_SECRET"), "http://localhost:3000/auth/onedrive/callback"), - - // Pointed localhost.com to http://localhost:3000/auth/yahoo/callback through proxy as yahoo - // does not allow to put custom ports in redirection uri - yahoo.New(os.Getenv("YAHOO_KEY"), os.Getenv("YAHOO_SECRET"), "http://localhost.com"), - slack.New(os.Getenv("SLACK_KEY"), os.Getenv("SLACK_SECRET"), "http://localhost:3000/auth/slack/callback"), - stripe.New(os.Getenv("STRIPE_KEY"), os.Getenv("STRIPE_SECRET"), "http://localhost:3000/auth/stripe/callback"), - wepay.New(os.Getenv("WEPAY_KEY"), os.Getenv("WEPAY_SECRET"), "http://localhost:3000/auth/wepay/callback", "view_user"), - // By default paypal production auth urls will be used, please set PAYPAL_ENV=sandbox as environment variable for testing - // in sandbox environment - paypal.New(os.Getenv("PAYPAL_KEY"), os.Getenv("PAYPAL_SECRET"), "http://localhost:3000/auth/paypal/callback"), - steam.New(os.Getenv("STEAM_KEY"), "http://localhost:3000/auth/steam/callback"), - heroku.New(os.Getenv("HEROKU_KEY"), os.Getenv("HEROKU_SECRET"), "http://localhost:3000/auth/heroku/callback"), - uber.New(os.Getenv("UBER_KEY"), os.Getenv("UBER_SECRET"), "http://localhost:3000/auth/uber/callback"), - soundcloud.New(os.Getenv("SOUNDCLOUD_KEY"), os.Getenv("SOUNDCLOUD_SECRET"), "http://localhost:3000/auth/soundcloud/callback"), - gitlab.New(os.Getenv("GITLAB_KEY"), os.Getenv("GITLAB_SECRET"), "http://localhost:3000/auth/gitlab/callback"), - dailymotion.New(os.Getenv("DAILYMOTION_KEY"), os.Getenv("DAILYMOTION_SECRET"), "http://localhost:3000/auth/dailymotion/callback", "email"), - deezer.New(os.Getenv("DEEZER_KEY"), os.Getenv("DEEZER_SECRET"), "http://localhost:3000/auth/deezer/callback", "email"), - discord.New(os.Getenv("DISCORD_KEY"), os.Getenv("DISCORD_SECRET"), "http://localhost:3000/auth/discord/callback", discord.ScopeIdentify, discord.ScopeEmail), - meetup.New(os.Getenv("MEETUP_KEY"), os.Getenv("MEETUP_SECRET"), "http://localhost:3000/auth/meetup/callback"), - - // Auth0 allocates domain per customer, a domain must be provided for auth0 to work - auth0.New(os.Getenv("AUTH0_KEY"), os.Getenv("AUTH0_SECRET"), "http://localhost:3000/auth/auth0/callback", os.Getenv("AUTH0_DOMAIN")), - xero.New(os.Getenv("XERO_KEY"), os.Getenv("XERO_SECRET"), "http://localhost:3000/auth/xero/callback"), - ) - - // OpenID Connect is based on OpenID Connect Auto Discovery URL (https://openid.net/specs/openid-connect-discovery-1_0-17.html) - // because the OpenID Connect provider initialize it self in the New(), it can return an error which should be handled or ignored - // ignore the error for now - openidConnect, _ := openidConnect.New(os.Getenv("OPENID_CONNECT_KEY"), os.Getenv("OPENID_CONNECT_SECRET"), "http://localhost:3000/auth/openid-connect/callback", os.Getenv("OPENID_CONNECT_DISCOVERY_URL")) - if openidConnect != nil { - goth.UseProviders(openidConnect) - } - - m := make(map[string]string) - m["amazon"] = "Amazon" - m["bitbucket"] = "Bitbucket" - m["box"] = "Box" - m["dailymotion"] = "Dailymotion" - m["deezer"] = "Deezer" - m["digitalocean"] = "Digital Ocean" - m["discord"] = "Discord" - m["dropbox"] = "Dropbox" - m["facebook"] = "Facebook" - m["fitbit"] = "Fitbit" - m["github"] = "Github" - m["gitlab"] = "Gitlab" - m["soundcloud"] = "SoundCloud" - m["spotify"] = "Spotify" - m["steam"] = "Steam" - m["stripe"] = "Stripe" - m["twitch"] = "Twitch" - m["uber"] = "Uber" - m["wepay"] = "Wepay" - m["yahoo"] = "Yahoo" - m["yammer"] = "Yammer" - m["gplus"] = "Google Plus" - m["heroku"] = "Heroku" - m["instagram"] = "Instagram" - m["intercom"] = "Intercom" - m["lastfm"] = "Last FM" - m["linkedin"] = "Linkedin" - m["onedrive"] = "Onedrive" - m["paypal"] = "Paypal" - m["twitter"] = "Twitter" - m["salesforce"] = "Salesforce" - m["slack"] = "Slack" - m["meetup"] = "Meetup.com" - m["auth0"] = "Auth0" - m["openid-connect"] = "OpenID Connect" - m["xero"] = "Xero" - - var keys []string - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - - providerIndex := &ProviderIndex{Providers: keys, ProvidersMap: m} - - // create our app, - // set a view - // set sessions - // and setup the router for the showcase - app := iris.New() - - // attach and build our templates - app.RegisterView(iris.HTML("./templates", ".html")) - - // start of the router - - app.Get("/auth/{provider}/callback", func(ctx iris.Context) { - user, err := CompleteUserAuth(ctx) - if err != nil { - ctx.StatusCode(iris.StatusInternalServerError) - ctx.Writef("%v", err) - return - } - ctx.ViewData("", user) - if err := ctx.View("user.html"); err != nil { - ctx.Writef("%v", err) - } - }) - - app.Get("/logout/{provider}", func(ctx iris.Context) { - Logout(ctx) - ctx.Redirect("/", iris.StatusTemporaryRedirect) - }) - - app.Get("/auth/{provider}", func(ctx iris.Context) { - // try to get the user without re-authenticating - if gothUser, err := CompleteUserAuth(ctx); err == nil { - ctx.ViewData("", gothUser) - if err := ctx.View("user.html"); err != nil { - ctx.Writef("%v", err) - } - } else { - BeginAuthHandler(ctx) - } - }) - - app.Get("/", func(ctx iris.Context) { - ctx.ViewData("", providerIndex) - - if err := ctx.View("index.html"); err != nil { - ctx.Writef("%v", err) - } - }) - - // http://localhost:3000 - app.Listen("localhost:3000") -} - -type ProviderIndex struct { - Providers []string - ProvidersMap map[string]string -} diff --git a/_examples/auth/goth/templates/index.html b/_examples/auth/goth/templates/index.html deleted file mode 100644 index 53652804..00000000 --- a/_examples/auth/goth/templates/index.html +++ /dev/null @@ -1,3 +0,0 @@ -{{range $key,$value:=.Providers}} -

Log in with {{index $.ProvidersMap $value}}

-{{end}} \ No newline at end of file diff --git a/_examples/auth/goth/templates/user.html b/_examples/auth/goth/templates/user.html deleted file mode 100644 index 10ab7c5c..00000000 --- a/_examples/auth/goth/templates/user.html +++ /dev/null @@ -1,11 +0,0 @@ -

logout

-

Name: {{.Name}} [{{.LastName}}, {{.FirstName}}]

-

Email: {{.Email}}

-

NickName: {{.NickName}}

-

Location: {{.Location}}

-

AvatarURL: {{.AvatarURL}}

-

Description: {{.Description}}

-

UserID: {{.UserID}}

-

AccessToken: {{.AccessToken}}

-

ExpiresAt: {{.ExpiresAt}}

-

RefreshToken: {{.RefreshToken}}

\ No newline at end of file diff --git a/_examples/auth/hcaptcha/hosts b/_examples/auth/hcaptcha/hosts deleted file mode 100644 index d11c711b..00000000 --- a/_examples/auth/hcaptcha/hosts +++ /dev/null @@ -1,3 +0,0 @@ -# https://docs.hcaptcha.com/#localdev -# Add to the end of your hosts file, e.g. on windows: C:/windows/system32/drivers/etc/hosts -127.0.0.1 yourdomain.com diff --git a/_examples/auth/hcaptcha/main.go b/_examples/auth/hcaptcha/main.go deleted file mode 100644 index 87e917ac..00000000 --- a/_examples/auth/hcaptcha/main.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - "os" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/hcaptcha" -) - -// Get the following values from: https://dashboard.hcaptcha.com -// Also, check: https://docs.hcaptcha.com/#localdev to test on local environment. -var ( - siteKey = os.Getenv("HCAPTCHA-SITE-KEY") - secretKey = os.Getenv("HCAPTCHA-SECRET-KEY") -) - -func main() { - app := iris.New() - app.RegisterView(iris.HTML("./templates", ".html")) - - hCaptcha := hcaptcha.New(secretKey) - app.Get("/register", registerForm) - app.Post("/register", hCaptcha, register) // See `hcaptcha.SiteVerify` for manual validation too. - - app.Logger().Infof("SiteKey = %s\tSecretKey = %s", - siteKey, secretKey) - - // GET: http://yourdomain.com/register - app.Listen(":80") -} - -func register(ctx iris.Context) { - hcaptchaResp, ok := hcaptcha.Get(ctx) - if !ok { - ctx.StatusCode(iris.StatusUnauthorized) - ctx.WriteString("Are you a bot?") - return - } - - ctx.Writef("Register action here...action was asked by a Human.\nResponse value is: %#+v", hcaptchaResp) -} - -func registerForm(ctx iris.Context) { - ctx.ViewData("SiteKey", siteKey) - ctx.View("register_form.html") -} diff --git a/_examples/auth/hcaptcha/templates/register_form.html b/_examples/auth/hcaptcha/templates/register_form.html deleted file mode 100644 index 26a0cdc0..00000000 --- a/_examples/auth/hcaptcha/templates/register_form.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - hCaptcha Demo - - - - -
- - -
-
- -
- - - \ No newline at end of file diff --git a/_examples/auth/jwt/README.md b/_examples/auth/jwt/README.md deleted file mode 100644 index 1d2e0ae5..00000000 --- a/_examples/auth/jwt/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Generate RSA - -```sh -$ openssl genrsa -des3 -out private_rsa.pem 2048 -``` - -```go -b, err := ioutil.ReadFile("./private_rsa.pem") -if err != nil { - panic(err) -} -key := jwt.MustParseRSAPrivateKey(b, []byte("pass")) -``` - -OR - -```go -import "crypto/rand" -import "crypto/rsa" - -key, err := rsa.GenerateKey(rand.Reader, 2048) -``` - -# Generate Ed25519 - -```sh -$ openssl genpkey -algorithm Ed25519 -out private_ed25519.pem -$ openssl req -x509 -key private_ed25519.pem -out cert_ed25519.pem -days 365 -``` diff --git a/_examples/auth/jwt/main.go b/_examples/auth/jwt/main.go deleted file mode 100644 index 77f9648f..00000000 --- a/_examples/auth/jwt/main.go +++ /dev/null @@ -1,155 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/jwt" -) - -// UserClaims a custom claims structure. You can just use jwt.Claims too. -type UserClaims struct { - jwt.Claims - Username string -} - -func main() { - // Get keys from system's environment variables - // JWT_SECRET (for signing and verification) and JWT_SECRET_ENC(for encryption and decryption), - // or defaults to "secret" and "itsa16bytesecret" respectfully. - // - // Use the `jwt.New` instead for more flexibility, if necessary. - j := jwt.HMAC(15*time.Minute, "secret", "itsa16bytesecret") - - app := iris.New() - app.Logger().SetLevel("debug") - - app.Get("/authenticate", func(ctx iris.Context) { - standardClaims := jwt.Claims{Issuer: "an-issuer", Audience: jwt.Audience{"an-audience"}} - // NOTE: if custom claims then the `j.Expiry(claims)` (or jwt.Expiry(duration, claims)) - // MUST be called in order to set the expiration time. - customClaims := UserClaims{ - Claims: j.Expiry(standardClaims), - Username: "kataras", - } - - j.WriteToken(ctx, customClaims) - }) - - userRouter := app.Party("/user") - { - // userRouter.Use(j.Verify) - // userRouter.Get("/", func(ctx iris.Context) { - // var claims UserClaims - // if err := jwt.ReadClaims(ctx, &claims); err != nil { - // // Validation-only errors, the rest are already - // // checked on `j.Verify` middleware. - // ctx.StopWithStatus(iris.StatusUnauthorized) - // return - // } - // - // ctx.Writef("Claims: %#+v\n", claims) - // }) - // - // OR: - userRouter.Get("/", func(ctx iris.Context) { - var claims UserClaims - if err := j.VerifyToken(ctx, &claims); err != nil { - ctx.StopWithStatus(iris.StatusUnauthorized) - return - } - - ctx.Writef("Claims: %#+v\n", claims) - }) - } - - app.Listen(":8080") -} - -/* -func default_RSA_Example() { - j := jwt.RSA(15*time.Minute) -} - -Same as: - -func load_File_Or_Generate_RSA_Example() { - signKey, err := jwt.LoadRSA("jwt_sign.key", 2048) - if err != nil { - panic(err) - } - - j, err := jwt.New(15*time.Minute, jwt.RS256, signKey) - if err != nil { - panic(err) - } - - encKey, err := jwt.LoadRSA("jwt_enc.key", 2048) - if err != nil { - panic(err) - } - err = j.WithEncryption(jwt.A128CBCHS256, jwt.RSA15, encKey) - if err != nil { - panic(err) - } -} -*/ - -/* -func hmac_Example() { - // hmac - key := []byte("secret") - j, err := jwt.New(15*time.Minute, jwt.HS256, key) - if err != nil { - panic(err) - } - - // OPTIONAL encryption: - encryptionKey := []byte("itsa16bytesecret") - err = j.WithEncryption(jwt.A128GCM, jwt.DIRECT, encryptionKey) - if err != nil { - panic(err) - } -} -*/ - -/* -func load_From_File_With_Password_Example() { - b, err := ioutil.ReadFile("./rsa_password_protected.key") - if err != nil { - panic(err) - } - signKey,err := jwt.ParseRSAPrivateKey(b, []byte("pass")) - if err != nil { - panic(err) - } - - j, err := jwt.New(15*time.Minute, jwt.RS256, signKey) - if err != nil { - panic(err) - } -} -*/ - -/* -func generate_RSA_Example() { - signKey, err := rsa.GenerateKey(rand.Reader, 4096) - if err != nil { - panic(err) - } - - encryptionKey, err := rsa.GenerateKey(rand.Reader, 4096) - if err != nil { - panic(err) - } - - j, err := jwt.New(15*time.Minute, jwt.RS512, signKey) - if err != nil { - panic(err) - } - err = j.WithEncryption(jwt.A128CBCHS256, jwt.RSA15, encryptionKey) - if err != nil { - panic(err) - } -} -*/ diff --git a/_examples/auth/jwt/rsa_password_protected.key b/_examples/auth/jwt/rsa_password_protected.key deleted file mode 100644 index e93fff77..00000000 --- a/_examples/auth/jwt/rsa_password_protected.key +++ /dev/null @@ -1,30 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,6B0BC214C94124FE - -lAM48DEM/GdCDimr9Vhi+fSHLgduDb0l2BA4uhILgNby51jxY/4X3IqM6f3ImKX7 -cEd9OBug+pwIugB0UW0L0f5Pd59Ovpiaz3xLci1/19ehYnMqsuP3YAnJm40hT5VP -p0gWRiR415PJ0fPeeJPFx5IsqvkTJ30LWZHUZX4EkdcL5L8PrVbmthGDbLh+OcMc -LzoP8eTglzlZF03nyvAol6+p2eZtvOJLu8nWG25q17kyBx6kEiCsWFcUBTX9G7sH -CM3naByDijqZXE/XXtmTMLSRRnlk7Q5WLxClroHlUP9y8BQFMo2TW4Z+vNjHUkc1 -77ghabX1704bAlIE8LLZJKrm/C5+VKyV6117SVG/2bc4036Y5rStXpANbk1j4K0x -ADvpRhuTpifaogdvJP+8eXBdl841MQMRzWuZHp6UNYYQegoV9C+KHyJx4UPjZyzd -gblZmKgU+BsX3mV6MLhJtd6dheLZtpBsAlSstJxzmgwqz9faONYEGeItXO+NnxbA -mxAp/mI+Fz2jfgYlWjwkyPPzD4k/ZMMzB4XLkKKs9XaxUtTomiDkuYZfnABhxt73 -xBy40V1rb/NyeW80pk1zEHM6Iy/48ETSp9U3k9sSOXjMhYbPXgxDtimV8w0qGFAo -2Tif7ZuaiuC38rOkoHK9C6vy2Dp8lQZ+QBnUKLeFsyhq9CaqSdnyUTMj3oEZXXf+ -TqqeO+PTtl7JaNfGRq6/aMZqxACHkyVUvYvjZzx07CJ2fr+OtNqxallM6Oc/o9NZ -5u7lpgrYaKM/b67q0d2X/AoxR5zrZuM8eam3acD1PwHFQKbJWuFNmjWtnlZNuR3X -fZEmxIKwDlup8TxFcqbbZtPHuQA2mTMTqfRkf8oPSO+N6NNaUpb0ignYyA7Eu5GT -b02d/oNLETMikxUxntMSH7GhuOpfJyELz8krYTttbJ+a93h4wBeYW2+LyAr/cRLB -mbtKLtaN7f3FaOSnu8e0+zlJ7xglHPXqblRL9q6ZDM5UJtJD4rA7LPZHk/0Y1Kb6 -hBh1qMDu0r3IV4X7MDacvxw7aa7D8TyXJiFSvxykVhds+ndjIe51Ics5908+lev3 -nwE69PLMwyqe2vvE2oDwao4XJuBLCHjcv/VagRSz/XQGMbZqb3L6unyd3UPl8JjP -ovipNwM4rFnE54uiUUeki7TZGDYO72vQcSaLrmbeAWc2m202+rqLz0WMm6HpPmCv -IgexpX2MnIeHJ3+BlEjA2u+S6xNSD7qHGk2pb7DD8nRvUdSHAHeaQbrkEfEhhR2Q -Dw5gdw1JyQ0UKBl5ndn/1Ub2Asl016lZjpqHyMIVS4tFixACDsihEYMmq/zQmTj4 -8oBZTU+fycN/KiGKZBsqxIwgYIeMz/GfvoyN5m57l6fwEZALVpveI1pP4fiZB/Z8 -xLKa5JK6L10lAD1YHWc1dPhamf9Sb3JwN2CFtGvjOJ/YjAZu3jJoxi40DtRkE3Rh -HI8Cbx1OORzoo0kO0vy42rz5qunYyVmEzPKtOj+YjVEhVJ85yJZ9bTZtuyqMv8mH -cnwEeIFK8cmm9asbVzQGDwN/UGB4cO3LrMX1RYk4GRttTGlp0729BbmZmu00RnD/ ------END RSA PRIVATE KEY----- diff --git a/_examples/auth/permissions/main.go b/_examples/auth/permissions/main.go deleted file mode 100644 index 026155b3..00000000 --- a/_examples/auth/permissions/main.go +++ /dev/null @@ -1,118 +0,0 @@ -package main - -import ( - "fmt" - "log" - "strings" - - "github.com/kataras/iris/v12" - - permissions "github.com/xyproto/permissionbolt" - // * PostgreSQL support: - // permissions "github.com/xyproto/pstore" and - // perm, err := permissions.New(...) - // - // * MariaDB/MySQL support: - // permissions "github.com/xyproto/permissionsql" and - // perm, err := permissions.New/NewWithDSN(...) - // * Redis support: - // permissions "github.com/xyproto/permissions2" - // perm, err := permissions.New2() - // * Bolt support (this one): - // permissions "github.com/xyproto/permissionbolt" and - // perm, err := permissions.New(...) -) - -func main() { - app := iris.New() - app.Logger().SetLevel("debug") - - // New permissions middleware. - perm, err := permissions.New() - if err != nil { - log.Fatalln(err) - } - - // Blank slate, no default permissions - // perm.Clear() - - // Set up a middleware handler for Iris, with a custom "permission denied" message. - permissionHandler := func(ctx iris.Context) { - // Check if the user has the right admin/user rights - if perm.Rejected(ctx.ResponseWriter(), ctx.Request()) { - // Deny the request, don't call other middleware handlers - ctx.StopWithText(iris.StatusForbidden, "Permission denied!") - return - } - // Call the next middleware handler - ctx.Next() - } - - // Register the permissions middleware - app.Use(permissionHandler) - - // Get the userstate, used in the handlers below - userstate := perm.UserState() - - app.Get("/", func(ctx iris.Context) { - msg := "" - msg += fmt.Sprintf("Has user bob: %v\n", userstate.HasUser("bob")) - msg += fmt.Sprintf("Logged in on server: %v\n", userstate.IsLoggedIn("bob")) - msg += fmt.Sprintf("Is confirmed: %v\n", userstate.IsConfirmed("bob")) - msg += fmt.Sprintf("Username stored in cookies (or blank): %v\n", userstate.Username(ctx.Request())) - msg += fmt.Sprintf("Current user is logged in, has a valid cookie and *user rights*: %v\n", userstate.UserRights(ctx.Request())) - msg += fmt.Sprintf("Current user is logged in, has a valid cookie and *admin rights*: %v\n", userstate.AdminRights(ctx.Request())) - msg += fmt.Sprintln("\nTry: /register, /confirm, /remove, /login, /logout, /makeadmin, /clear, /data and /admin") - ctx.WriteString(msg) - }) - - app.Get("/register", func(ctx iris.Context) { - userstate.AddUser("bob", "hunter1", "bob@zombo.com") - ctx.Writef("User bob was created: %v\n", userstate.HasUser("bob")) - }) - - app.Get("/confirm", func(ctx iris.Context) { - userstate.MarkConfirmed("bob") - ctx.Writef("User bob was confirmed: %v\n", userstate.IsConfirmed("bob")) - }) - - app.Get("/remove", func(ctx iris.Context) { - userstate.RemoveUser("bob") - ctx.Writef("User bob was removed: %v\n", !userstate.HasUser("bob")) - }) - - app.Get("/login", func(ctx iris.Context) { - // Headers will be written, for storing a cookie - userstate.Login(ctx.ResponseWriter(), "bob") - ctx.Writef("bob is now logged in: %v\n", userstate.IsLoggedIn("bob")) - }) - - app.Get("/logout", func(ctx iris.Context) { - userstate.Logout("bob") - ctx.Writef("bob is now logged out: %v\n", !userstate.IsLoggedIn("bob")) - }) - - app.Get("/makeadmin", func(ctx iris.Context) { - userstate.SetAdminStatus("bob") - ctx.Writef("bob is now administrator: %v\n", userstate.IsAdmin("bob")) - }) - - app.Get("/clear", func(ctx iris.Context) { - userstate.ClearCookie(ctx.ResponseWriter()) - ctx.WriteString("Clearing cookie") - }) - - app.Get("/data", func(ctx iris.Context) { - ctx.WriteString("user page that only logged in users must see!") - }) - - app.Get("/admin", func(ctx iris.Context) { - ctx.WriteString("super secret information that only logged in administrators must see!\n\n") - if usernames, err := userstate.AllUsernames(); err == nil { - ctx.Writef("list of all users: %s" + strings.Join(usernames, ", ")) - } - }) - - // Serve - app.Listen(":8080") -} diff --git a/_examples/auth/recaptcha/custom_form/main.go b/_examples/auth/recaptcha/custom_form/main.go deleted file mode 100644 index 395c7c45..00000000 --- a/_examples/auth/recaptcha/custom_form/main.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/kataras/iris/v12" - - "github.com/kataras/iris/v12/middleware/recaptcha" -) - -// keys should be obtained by https://www.google.com/recaptcha -const ( - recaptchaPublic = "6Lf3WywUAAAAAKNfAm5DP2J5ahqedtZdHTYaKkJ6" - recaptchaSecret = "6Lf3WywUAAAAAJpArb8nW_LCL_PuPuokmEABFfgw" -) - -func main() { - app := iris.New() - - r := recaptcha.New(recaptchaSecret) - - app.Get("/comment", showRecaptchaForm) - - // pass the middleware before the main handler or use the `recaptcha.SiteVerify`. - app.Post("/comment", r, postComment) - - app.Listen(":8080") -} - -var htmlForm = `
- -
- -
` - -func showRecaptchaForm(ctx iris.Context) { - contents := fmt.Sprintf(htmlForm, recaptchaPublic) - ctx.HTML(contents) -} - -func postComment(ctx iris.Context) { - // [...] - ctx.JSON(iris.Map{"success": true}) -} diff --git a/_examples/auth/recaptcha/main.go b/_examples/auth/recaptcha/main.go deleted file mode 100644 index 0648bede..00000000 --- a/_examples/auth/recaptcha/main.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/recaptcha" -) - -// keys should be obtained by https://www.google.com/recaptcha -const ( - recaptchaPublic = "" - recaptchaSecret = "" -) - -func showRecaptchaForm(ctx iris.Context, path string) { - ctx.HTML(recaptcha.GetFormHTML(recaptchaPublic, path)) -} - -func main() { - app := iris.New() - - // On both Get and Post on this example, so you can easly - // use a single route to show a form and the main subject if recaptcha's validation result succeed. - app.HandleMany("GET POST", "/", func(ctx iris.Context) { - if ctx.Method() == iris.MethodGet { - showRecaptchaForm(ctx, "/") - return - } - - result := recaptcha.SiteVerify(ctx, recaptchaSecret) - if !result.Success { - /* redirect here if u want or do nothing */ - ctx.HTML(" failed please try again ") - return - } - - ctx.Writef("succeed.") - }) - - app.Listen(":8080") -} diff --git a/_examples/bootstrapper/bootstrap/bootstrapper.go b/_examples/bootstrapper/bootstrap/bootstrapper.go deleted file mode 100644 index 0d24c50c..00000000 --- a/_examples/bootstrapper/bootstrap/bootstrapper.go +++ /dev/null @@ -1,123 +0,0 @@ -package bootstrap - -import ( - "time" - - "github.com/gorilla/securecookie" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/logger" - "github.com/kataras/iris/v12/middleware/recover" - "github.com/kataras/iris/v12/sessions" - "github.com/kataras/iris/v12/websocket" -) - -type Configurator func(*Bootstrapper) - -type Bootstrapper struct { - *iris.Application - AppName string - AppOwner string - AppSpawnDate time.Time - - Sessions *sessions.Sessions -} - -// New returns a new Bootstrapper. -func New(appName, appOwner string, cfgs ...Configurator) *Bootstrapper { - b := &Bootstrapper{ - AppName: appName, - AppOwner: appOwner, - AppSpawnDate: time.Now(), - Application: iris.New(), - } - - for _, cfg := range cfgs { - cfg(b) - } - - return b -} - -// SetupViews loads the templates. -func (b *Bootstrapper) SetupViews(viewsDir string) { - b.RegisterView(iris.HTML(viewsDir, ".html").Layout("shared/layout.html")) -} - -// SetupSessions initializes the sessions, optionally. -func (b *Bootstrapper) SetupSessions(expires time.Duration, cookieHashKey, cookieBlockKey []byte) { - b.Sessions = sessions.New(sessions.Config{ - Cookie: "SECRET_SESS_COOKIE_" + b.AppName, - Expires: expires, - Encoding: securecookie.New(cookieHashKey, cookieBlockKey), - }) -} - -// SetupWebsockets prepares the websocket server. -func (b *Bootstrapper) SetupWebsockets(endpoint string, handler websocket.ConnHandler) { - ws := websocket.New(websocket.DefaultGorillaUpgrader, handler) - - b.Get(endpoint, websocket.Handler(ws)) -} - -// SetupErrorHandlers prepares the http error handlers -// `(context.StatusCodeNotSuccessful`, which defaults to >=400 (but you can change it). -func (b *Bootstrapper) SetupErrorHandlers() { - b.OnAnyErrorCode(func(ctx iris.Context) { - err := iris.Map{ - "app": b.AppName, - "status": ctx.GetStatusCode(), - "message": ctx.Values().GetString("message"), - } - - if jsonOutput := ctx.URLParamExists("json"); jsonOutput { - ctx.JSON(err) - return - } - - ctx.ViewData("Err", err) - ctx.ViewData("Title", "Error") - ctx.View("shared/error.html") - }) -} - -const ( - // StaticAssets is the root directory for public assets like images, css, js. - StaticAssets = "./public/" - // Favicon is the relative 9to the "StaticAssets") favicon path for our app. - Favicon = "favicon.ico" -) - -// Configure accepts configurations and runs them inside the Bootstraper's context. -func (b *Bootstrapper) Configure(cs ...Configurator) { - for _, c := range cs { - c(b) - } -} - -// Bootstrap prepares our application. -// -// Returns itself. -func (b *Bootstrapper) Bootstrap() *Bootstrapper { - b.SetupViews("./views") - b.SetupSessions(24*time.Hour, - []byte("the-big-and-secret-fash-key-here"), - []byte("lot-secret-of-characters-big-too"), - ) - b.SetupErrorHandlers() - - // static files - b.Favicon(StaticAssets + Favicon) - b.HandleDir("/public", iris.Dir(StaticAssets)) - - // middleware, after static files - b.Use(recover.New()) - b.Use(logger.New()) - - return b -} - -// Listen starts the http server with the specified "addr". -func (b *Bootstrapper) Listen(addr string, cfgs ...iris.Configurator) { - b.Run(iris.Addr(addr), cfgs...) -} diff --git a/_examples/bootstrapper/folder_structure.png b/_examples/bootstrapper/folder_structure.png deleted file mode 100644 index 8dfba29fdebca2b941c0dcbf56a72303f5bb2fb5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30487 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 \ No newline at end of file diff --git a/_examples/bootstrapper/views/shared/error.html b/_examples/bootstrapper/views/shared/error.html deleted file mode 100644 index 9fde08ad..00000000 --- a/_examples/bootstrapper/views/shared/error.html +++ /dev/null @@ -1,5 +0,0 @@ -

Error.

-

An error occurred while processing your request.

- -

{{.Err.status}}

-

{{.Err.message}}

\ No newline at end of file diff --git a/_examples/bootstrapper/views/shared/layout.html b/_examples/bootstrapper/views/shared/layout.html deleted file mode 100644 index cf920444..00000000 --- a/_examples/bootstrapper/views/shared/layout.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - {{.Title}} - {{.AppName}} - - - - -
- - {{ yield }} -
-
-

© 2017 - {{.AppOwner}}

-
-
- - - \ No newline at end of file diff --git a/_examples/caddy/Caddyfile b/_examples/caddy/Caddyfile deleted file mode 100644 index ecbee979..00000000 --- a/_examples/caddy/Caddyfile +++ /dev/null @@ -1,9 +0,0 @@ -example.com { - header / Server "Iris" - proxy / example.com:9091 # localhost:9091 -} - -api.example.com { - header / Server "Iris" - proxy / api.example.com:9092 # localhost:9092 -} \ No newline at end of file diff --git a/_examples/caddy/README.md b/_examples/caddy/README.md deleted file mode 100644 index e8c601c3..00000000 --- a/_examples/caddy/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Caddy loves Iris - -The `Caddyfile` shows how you can use caddy to listen on ports 80 & 443 and sit in front of iris webserver(s) that serving on a different port (9091 and 9092 in this case; see Caddyfile). - -## Running our two web servers - -1. Go to `$GOPATH/src/github.com/kataras/iris/_examples/caddy/server1` -2. Open a terminal window and execute `go run main.go` -3. Go to `$GOPATH/src/github.com/kataras/iris/_examples/caddy/server2` -4. Open a new terminal window and execute `go run main.go` - -## Caddy installation - -1. Download caddy: https://caddyserver.com/download -2. Extract its contents where the `Caddyfile` is located, the `$GOPATH/src/github.com/kataras/iris/_examples/caddy` in this case -3. Open, read and modify the `Caddyfile` to see by yourself how easy it is to configure the servers -4. Run `caddy` directly or open a terminal window and execute `caddy` -5. Go to `https://example.com` and `https://api.example.com/user/42` - - -## Notes - -Iris has the `app.Run(iris.AutoTLS(":443", "example.com", "mail@example.com"))` which does -the exactly same thing but caddy is a great tool that helps you when you run multiple web servers from one host machine, i.e iris, apache, tomcat. \ No newline at end of file diff --git a/_examples/caddy/server1/main.go b/_examples/caddy/server1/main.go deleted file mode 100644 index 0f7f87ec..00000000 --- a/_examples/caddy/server1/main.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" -) - -func main() { - app := iris.New() - - templates := iris.HTML("./views", ".html").Layout("shared/layout.html") - app.RegisterView(templates) - - mvc.New(app).Handle(new(Controller)) - - // http://localhost:9091 - app.Listen(":9091") -} - -// Layout contains all the binding properties for the shared/layout.html -type Layout struct { - Title string -} - -// Controller is our example controller, request-scoped, each request has its own instance. -type Controller struct { - Layout Layout -} - -// BeginRequest is the first method fired when client requests from this Controller's root path. -func (c *Controller) BeginRequest(ctx iris.Context) { - c.Layout.Title = "Home Page" -} - -// EndRequest is the last method fired. -// It's here just to complete the BaseController -// in order to be tell iris to call the `BeginRequest` before the main method. -func (c *Controller) EndRequest(ctx iris.Context) {} - -// Get handles GET http://localhost:9091 -func (c *Controller) Get() mvc.View { - return mvc.View{ - Name: "index.html", - Data: iris.Map{ - "Layout": c.Layout, - "Message": "Welcome to my website!", - }, - } -} diff --git a/_examples/caddy/server1/views/index.html b/_examples/caddy/server1/views/index.html deleted file mode 100644 index 3d4a81f6..00000000 --- a/_examples/caddy/server1/views/index.html +++ /dev/null @@ -1,3 +0,0 @@ -
- {{.Message}} -
\ No newline at end of file diff --git a/_examples/caddy/server1/views/shared/layout.html b/_examples/caddy/server1/views/shared/layout.html deleted file mode 100644 index 141a75f7..00000000 --- a/_examples/caddy/server1/views/shared/layout.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - {{.Layout.Title}} - - - - {{ yield }} - - - \ No newline at end of file diff --git a/_examples/caddy/server2/main.go b/_examples/caddy/server2/main.go deleted file mode 100644 index 45a9ed80..00000000 --- a/_examples/caddy/server2/main.go +++ /dev/null @@ -1,68 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" -) - -type postValue func(string) string - -func main() { - app := iris.New() - - mvc.New(app.Party("/user")).Register( - func(ctx iris.Context) postValue { - return ctx.PostValue - }).Handle(new(UserController)) - - // GET http://localhost:9092/user - // GET http://localhost:9092/user/42 - // POST http://localhost:9092/user - // PUT http://localhost:9092/user/42 - // DELETE http://localhost:9092/user/42 - // GET http://localhost:9092/user/followers/42 - app.Listen(":9092") -} - -// UserController is our user example controller. -type UserController struct{} - -// Get handles GET /user -func (c *UserController) Get() string { - return "Select all users" -} - -// User is our test User model, nothing tremendous here. -type User struct{ ID int64 } - -// GetBy handles GET /user/42, equal to .Get("/user/{id:int64}") -func (c *UserController) GetBy(id int64) User { - // Select User by ID == $id. - return User{id} -} - -// Post handles POST /user -func (c *UserController) Post(post postValue) string { - username := post("username") - return "Create by user with username: " + username -} - -// PutBy handles PUT /user/42 -func (c *UserController) PutBy(id int) string { - // Update user by ID == $id - return "User updated" -} - -// DeleteBy handles DELETE /user/42 -func (c *UserController) DeleteBy(id int) bool { - // Delete user by ID == %id - // - // when boolean then true = iris.StatusOK, false = iris.StatusNotFound - return true -} - -// GetFollowersBy handles GET /user/followers/42 -func (c *UserController) GetFollowersBy(id int) []User { - // Select all followers by user ID == $id - return []User{ /* ... */ } -} diff --git a/_examples/compression/client-using-iris/main.go b/_examples/compression/client-using-iris/main.go deleted file mode 100644 index 65d97131..00000000 --- a/_examples/compression/client-using-iris/main.go +++ /dev/null @@ -1,112 +0,0 @@ -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - - "github.com/kataras/iris/v12/context" -) - -const baseURL = "http://localhost:8080" - -// Available options: -// - "gzip", -// - "deflate", -// - "br" (for brotli), -// - "snappy" and -// - "s2" -const encoding = context.BROTLI - -var client = http.DefaultClient - -func main() { - fmt.Printf("Running client example on: %s\n", baseURL) - - getExample() - postExample() -} - -func getExample() { - endpoint := baseURL + "/" - req, err := http.NewRequest(http.MethodGet, endpoint, nil) - if err != nil { - panic(err) - } - // Required to receive server's compressed data. - req.Header.Set("Accept-Encoding", encoding) - - resp, err := client.Do(req) - if err != nil { - panic(err) - } - defer resp.Body.Close() - - // decompress server's compressed reply. - cr, err := context.NewCompressReader(resp.Body, encoding) - if err != nil { - panic(err) - } - defer cr.Close() - - body, err := ioutil.ReadAll(cr) - if err != nil { - panic(err) - } - - fmt.Printf("Received from server: %s", string(body)) -} - -type payload struct { - Username string `json:"username"` -} - -func postExample() { - buf := new(bytes.Buffer) - - // Compress client's data. - cw, err := context.NewCompressWriter(buf, encoding, -1) - if err != nil { - panic(err) - } - - json.NewEncoder(cw).Encode(payload{Username: "Edward"}) - - // `Close` or `Flush` required before `NewRequest` call. - cw.Close() - - endpoint := baseURL + "/" - - req, err := http.NewRequest(http.MethodPost, endpoint, buf) - if err != nil { - panic(err) - } - req.Header.Set("Content-Type", "application/json") - - // Required to send gzip compressed data to the server. - req.Header.Set("Content-Encoding", encoding) - // Required to receive server's compressed data. - req.Header.Set("Accept-Encoding", encoding) - - resp, err := client.Do(req) - if err != nil { - panic(err) - } - defer resp.Body.Close() - - // Decompress server's compressed reply. - cr, err := context.NewCompressReader(resp.Body, encoding) - if err != nil { - panic(err) - } - defer cr.Close() - - body, err := ioutil.ReadAll(cr) - if err != nil { - panic(err) - } - - fmt.Printf("Server replied with: %s", string(body)) -} diff --git a/_examples/compression/client/main.go b/_examples/compression/client/main.go deleted file mode 100644 index 6c39294a..00000000 --- a/_examples/compression/client/main.go +++ /dev/null @@ -1,102 +0,0 @@ -package main - -import ( - "bytes" - "compress/gzip" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" -) - -var client = http.DefaultClient - -const baseURL = "http://localhost:8080" - -func main() { - fmt.Printf("Running client example on: %s\n", baseURL) - - getExample() - postExample() -} - -func getExample() { - endpoint := baseURL + "/" - req, err := http.NewRequest(http.MethodGet, endpoint, nil) - if err != nil { - panic(err) - } - // Required to receive server's compressed data. - req.Header.Set("Accept-Encoding", "gzip") - - resp, err := client.Do(req) - if err != nil { - panic(err) - } - defer resp.Body.Close() - - // decompress server's compressed reply. - r, err := gzip.NewReader(resp.Body) - if err != nil { - panic(err) - } - defer r.Close() - - body, err := ioutil.ReadAll(r) - if err != nil { - panic(err) - } - - fmt.Printf("Received from server: %s", string(body)) -} - -type payload struct { - Username string `json:"username"` -} - -func postExample() { - buf := new(bytes.Buffer) - - // Compress client's data. - w := gzip.NewWriter(buf) - - b, err := json.Marshal(payload{Username: "Edward"}) - if err != nil { - panic(err) - } - w.Write(b) - w.Close() - - endpoint := baseURL + "/" - - req, err := http.NewRequest(http.MethodPost, endpoint, buf) - if err != nil { - panic(err) - } - req.Header.Set("Content-Type", "application/json") - - // Required to send gzip compressed data to the server. - req.Header.Set("Content-Encoding", "gzip") - // Required to receive server's compressed data. - req.Header.Set("Accept-Encoding", "gzip") - - resp, err := client.Do(req) - if err != nil { - panic(err) - } - defer resp.Body.Close() - - // Decompress server's compressed reply. - r, err := gzip.NewReader(resp.Body) - if err != nil { - panic(err) - } - defer r.Close() - - body, err := ioutil.ReadAll(r) - if err != nil { - panic(err) - } - - fmt.Printf("Server replied with: %s", string(body)) -} diff --git a/_examples/compression/main.go b/_examples/compression/main.go deleted file mode 100644 index e1d989d7..00000000 --- a/_examples/compression/main.go +++ /dev/null @@ -1,64 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := newApp() - app.Logger().SetLevel("debug") - app.Listen(":8080") -} - -func newApp() *iris.Application { - app := iris.New() - // HERE and you are ready to GO: - app.Use(iris.Compression) - - app.Get("/", send) - app.Post("/", receive) - - return app -} - -type payload struct { - Username string `json:"username"` -} - -func send(ctx iris.Context) { - ctx.JSON(payload{ - Username: "Makis", - }) -} - -func receive(ctx iris.Context) { - var p payload - if err := ctx.ReadJSON(&p); err != nil { - ctx.Application().Logger().Debugf("ReadJSON: %v", err) - } - - ctx.WriteString(p.Username) -} - -/* Manually: -func enableCompression(ctx iris.Context) { - // Enable writing using compression (deflate, gzip, brotli, snappy, s2): - err := ctx.CompressWriter(true) - if err != nil { - ctx.Application().Logger().Debugf("writer: %v", err) - // if you REQUIRE server to SEND compressed data then `return` here. - // return - } - - // Enable reading and binding request's compressed data: - err = ctx.CompressReader(true) - if err != nil && - // on GET we don't expect writing with gzip from client - ctx.Method() != iris.MethodGet { - ctx.Application().Logger().Debugf("reader: %v", err) - // if you REQUIRE server to RECEIVE only - // compressed data then `return` here. - // return - } - - ctx.Next() -} -*/ diff --git a/_examples/compression/main_test.go b/_examples/compression/main_test.go deleted file mode 100644 index 62cbb459..00000000 --- a/_examples/compression/main_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package main - -import ( - "encoding/json" - "reflect" - "strings" - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/httptest" -) - -func TestCompression(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - var expectedReply = payload{Username: "Makis"} - testBody(t, e.GET("/"), expectedReply) -} - -func TestCompressionAfterRecorder(t *testing.T) { - var expectedReply = payload{Username: "Makis"} - - app := iris.New() - app.Use(func(ctx iris.Context) { - ctx.Record() - ctx.Next() - }) - app.Use(iris.Compression) - - app.Get("/", func(ctx iris.Context) { - ctx.JSON(expectedReply) - }) - - e := httptest.New(t, app) - testBody(t, e.GET("/"), expectedReply) -} - -func TestCompressionBeforeRecorder(t *testing.T) { - var expectedReply = payload{Username: "Makis"} - - app := iris.New() - app.Use(iris.Compression) - app.Use(func(ctx iris.Context) { - ctx.Record() - ctx.Next() - }) - - app.Get("/", func(ctx iris.Context) { - ctx.JSON(expectedReply) - }) - - e := httptest.New(t, app) - testBody(t, e.GET("/"), expectedReply) -} - -func testBody(t *testing.T, req *httptest.Request, expectedReply interface{}) { - t.Helper() - - body := req.WithHeader(context.AcceptEncodingHeaderKey, context.GZIP).Expect(). - Status(httptest.StatusOK). - ContentEncoding(context.GZIP). - ContentType(context.ContentJSONHeaderValue).Body().Raw() - - // Note that .Expect() consumes the response body - // and stores it to unexported "contents" field - // therefore, we retrieve it as string and put it to a new buffer. - r := strings.NewReader(body) - cr, err := context.NewCompressReader(r, context.GZIP) - if err != nil { - t.Fatal(err) - } - defer cr.Close() - - var got payload - if err = json.NewDecoder(cr).Decode(&got); err != nil { - t.Fatal(err) - } - - if !reflect.DeepEqual(expectedReply, got) { - t.Fatalf("expected %#+v but got %#+v", expectedReply, got) - } -} diff --git a/_examples/configuration/from-configuration-structure/main.go b/_examples/configuration/from-configuration-structure/main.go deleted file mode 100644 index 93908cb4..00000000 --- a/_examples/configuration/from-configuration-structure/main.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - app.Get("/", func(ctx iris.Context) { - ctx.HTML("Hello!") - }) - // [...] - - // Good when you want to modify the whole configuration. - app.Listen(":8080", iris.WithConfiguration(iris.Configuration{ // default configuration: - DisableStartupLog: false, - DisableInterruptHandler: false, - DisablePathCorrection: false, - EnablePathEscape: false, - FireMethodNotAllowed: false, - DisableBodyConsumptionOnUnmarshal: false, - DisableAutoFireStatusCode: false, - TimeFormat: "Mon, 02 Jan 2006 15:04:05 GMT", - Charset: "utf-8", - })) - - // or before Run: - // app.Configure(iris.WithConfiguration(iris.Configuration{...})) -} diff --git a/_examples/configuration/from-toml-file/configs/iris.tml b/_examples/configuration/from-toml-file/configs/iris.tml deleted file mode 100644 index 6eee1e11..00000000 --- a/_examples/configuration/from-toml-file/configs/iris.tml +++ /dev/null @@ -1,9 +0,0 @@ -DisablePathCorrection = false -EnablePathEscape = false -FireMethodNotAllowed = true -DisableBodyConsumptionOnUnmarshal = false -TimeFormat = "Mon, 01 Jan 2006 15:04:05 GMT" -Charset = "utf-8" -RemoteAddrHeaders = ["X-Real-Ip", "X-Forwarded-For", "CF-Connecting-IP"] -[Other] - MyServerName = "iris" diff --git a/_examples/configuration/from-toml-file/main.go b/_examples/configuration/from-toml-file/main.go deleted file mode 100644 index b0c02935..00000000 --- a/_examples/configuration/from-toml-file/main.go +++ /dev/null @@ -1,21 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("Hello!") - }) - // [...] - - // Good when you have two configurations, one for development and a different one for production use. - app.Listen(":8080", iris.WithConfiguration(iris.TOML("./configs/iris.tml"))) - - // or before run: - // app.Configure(iris.WithConfiguration(iris.TOML("./configs/iris.tml"))) - // app.Listen(":8080") -} diff --git a/_examples/configuration/from-yaml-file/configs/iris.yml b/_examples/configuration/from-yaml-file/configs/iris.yml deleted file mode 100644 index e68bbdf6..00000000 --- a/_examples/configuration/from-yaml-file/configs/iris.yml +++ /dev/null @@ -1,16 +0,0 @@ -DisablePathCorrection: false -EnablePathEscape: false -FireMethodNotAllowed: true -DisableBodyConsumptionOnUnmarshal: true -TimeFormat: Mon, 01 Jan 2006 15:04:05 GMT -Charset: UTF-8 -SSLProxyHeaders: - X-Forwarded-Proto: https -HostProxyHeaders: - X-Host: true -RemoteAddrHeaders: - - X-Real-Ip - - X-Forwarded-For - - CF-Connecting-IP -Other: - Addr: :8080 diff --git a/_examples/configuration/from-yaml-file/main.go b/_examples/configuration/from-yaml-file/main.go deleted file mode 100644 index a872d5bd..00000000 --- a/_examples/configuration/from-yaml-file/main.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - app.Get("/", func(ctx iris.Context) { - ctx.HTML("Hello!") - }) - // [...] - - // Good when you have two configurations, one for development and a different one for production use. - // If iris.YAML's input string argument is "~" then it loads the configuration from the home directory - // and can be shared between many iris instances. - cfg := iris.YAML("./configs/iris.yml") - addr := cfg.Other["Addr"].(string) - app.Listen(addr, iris.WithConfiguration(cfg)) - - // or before run: - // app.Configure(iris.WithConfiguration(iris.YAML("./configs/iris.yml"))) - // app.Listen(":8080") -} diff --git a/_examples/configuration/from-yaml-file/shared-configuration/main.go b/_examples/configuration/from-yaml-file/shared-configuration/main.go deleted file mode 100644 index 483cd7a5..00000000 --- a/_examples/configuration/from-yaml-file/shared-configuration/main.go +++ /dev/null @@ -1,21 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - app.Get("/", func(ctx iris.Context) { - ctx.HTML("Hello!") - }) - // [...] - - // Good when you share configuration between multiple iris instances. - // This configuration file lives in your $HOME/iris.yml for unix hosts - // or %HOMEDRIVE%+%HOMEPATH%/iris.yml for windows hosts, and you can modify it. - app.Listen(":8080", iris.WithGlobalConfiguration) - // or before run: - // app.Configure(iris.WithGlobalConfiguration) - // app.Listen(":8080") -} diff --git a/_examples/configuration/functional/main.go b/_examples/configuration/functional/main.go deleted file mode 100644 index c5a3a473..00000000 --- a/_examples/configuration/functional/main.go +++ /dev/null @@ -1,23 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - app.Get("/", func(ctx iris.Context) { - ctx.HTML("Hello!") - }) - // [...] - - // Good when you want to change some of the configuration's field. - // Prefix: "With", code editors will help you navigate through all - // configuration options without even a glitch to the documentation. - - app.Listen(":8080", iris.WithoutStartupLog, iris.WithCharset("utf-8")) - - // or before run: - // app.Configure(iris.WithoutStartupLog, iris.WithCharset("utf-8")) - // app.Listen(":8080") -} diff --git a/_examples/convert-handlers/negroni-like/main.go b/_examples/convert-handlers/negroni-like/main.go deleted file mode 100644 index be09c9e3..00000000 --- a/_examples/convert-handlers/negroni-like/main.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "net/http" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - irisMiddleware := iris.FromStd(negronilikeTestMiddleware) - app.Use(irisMiddleware) - - // Method GET: http://localhost:8080/ - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

Home

") - // this will print an error, - // this route's handler will never be executed because the middleware's criteria not passed. - }) - - // Method GET: http://localhost:8080/ok - app.Get("/ok", func(ctx iris.Context) { - ctx.Writef("Hello world!") - // this will print "OK. Hello world!". - }) - - // http://localhost:8080 - // http://localhost:8080/ok - app.Listen(":8080") -} - -func negronilikeTestMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - if r.URL.Path == "/ok" && r.Method == "GET" { - w.Write([]byte("OK. ")) - next(w, r) // go to the next route's handler - return - } - // else print an error and do not forward to the route's handler. - w.WriteHeader(iris.StatusBadRequest) - w.Write([]byte("Bad request")) -} diff --git a/_examples/convert-handlers/nethttp/main.go b/_examples/convert-handlers/nethttp/main.go deleted file mode 100644 index d78c14ee..00000000 --- a/_examples/convert-handlers/nethttp/main.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "net/http" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - irisMiddleware := iris.FromStd(nativeTestMiddleware) - app.Use(irisMiddleware) - - // Method GET: http://localhost:8080/ - app.Get("/", func(ctx iris.Context) { - ctx.HTML("Home") - }) - - // Method GET: http://localhost:8080/ok - app.Get("/ok", func(ctx iris.Context) { - ctx.HTML("Hello world!") - }) - - // http://localhost:8080 - // http://localhost:8080/ok - app.Listen(":8080") -} - -func nativeTestMiddleware(w http.ResponseWriter, r *http.Request) { - println("Request path: " + r.URL.Path) -} diff --git a/_examples/convert-handlers/real-usecase-raven/wrapping-the-router/main.go b/_examples/convert-handlers/real-usecase-raven/wrapping-the-router/main.go deleted file mode 100644 index 8abc1a53..00000000 --- a/_examples/convert-handlers/real-usecase-raven/wrapping-the-router/main.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "net/http" - "runtime/debug" - - "github.com/kataras/iris/v12" - - "github.com/getsentry/raven-go" -) - -// https://docs.sentry.io/clients/go/integrations/http/ -func init() { - raven.SetDSN("https://:@sentry.io/") -} - -func main() { - app := iris.New() - app.Get("/", func(ctx iris.Context) { - ctx.Writef("Hi") - }) - - // Example for WrapRouter is already here: - // https://github.com/kataras/iris/blob/master/_examples/routing/custom-wrapper/main.go#L53 - app.WrapRouter(func(w http.ResponseWriter, r *http.Request, irisRouter http.HandlerFunc) { - // Exactly the same source code: - // https://github.com/getsentry/raven-go/blob/379f8d0a68ca237cf8893a1cdfd4f574125e2c51/http.go#L70 - - defer func() { - if rval := recover(); rval != nil { - debug.PrintStack() - rvalStr := fmt.Sprint(rval) - packet := raven.NewPacket(rvalStr, raven.NewException(errors.New(rvalStr), raven.NewStacktrace(2, 3, nil)), raven.NewHttp(r)) - raven.Capture(packet, nil) - w.WriteHeader(http.StatusInternalServerError) - } - }() - - irisRouter(w, r) - }) - - app.Listen(":8080") -} diff --git a/_examples/convert-handlers/real-usecase-raven/writing-middleware/main.go b/_examples/convert-handlers/real-usecase-raven/writing-middleware/main.go deleted file mode 100644 index 82ef598b..00000000 --- a/_examples/convert-handlers/real-usecase-raven/writing-middleware/main.go +++ /dev/null @@ -1,57 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "runtime/debug" - - "github.com/kataras/iris/v12" - - "github.com/getsentry/raven-go" -) - -// At this example you will see how to convert any net/http middleware -// that has the form of `(HandlerFunc) HandlerFunc`. -// If the `raven.RecoveryHandler` had the form of -// `(http.HandlerFunc)` or `(http.HandlerFunc, next http.HandlerFunc)` -// you could just use the `irisMiddleware := iris.FromStd(nativeHandler)` -// but it doesn't, however as you already know Iris can work with net/http directly -// because of the `ctx.ResponseWriter()` and `ctx.Request()` are the original -// http.ResponseWriter and *http.Request. -// (this one is a big advantage, as a result you can use Iris for ever :)). -// -// The source code of the native middleware does not change at all. -// https://github.com/getsentry/raven-go/blob/379f8d0a68ca237cf8893a1cdfd4f574125e2c51/http.go#L70 -// The only addition is the Line 18 and Line 39 (instead of handler(w,r)) -// and you have a new iris middleware ready to use! -func irisRavenMiddleware(ctx iris.Context) { - w, r := ctx.ResponseWriter(), ctx.Request() - - defer func() { - if rval := recover(); rval != nil { - debug.PrintStack() - rvalStr := fmt.Sprint(rval) - packet := raven.NewPacket(rvalStr, raven.NewException(errors.New(rvalStr), raven.NewStacktrace(2, 3, nil)), raven.NewHttp(r)) - raven.Capture(packet, nil) - w.WriteHeader(iris.StatusInternalServerError) - } - }() - - ctx.Next() -} - -// https://docs.sentry.io/clients/go/integrations/http/ -func init() { - raven.SetDSN("https://:@sentry.io/") -} - -func main() { - app := iris.New() - app.Use(irisRavenMiddleware) - - app.Get("/", func(ctx iris.Context) { - ctx.Writef("Hi") - }) - - app.Listen(":8080") -} diff --git a/_examples/cookies/basic/main.go b/_examples/cookies/basic/main.go deleted file mode 100644 index f9b789e3..00000000 --- a/_examples/cookies/basic/main.go +++ /dev/null @@ -1,64 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func newApp() *iris.Application { - app := iris.New() - - // Set A Cookie. - app.Get("/cookies/{name}/{value}", func(ctx iris.Context) { - name := ctx.Params().Get("name") - value := ctx.Params().Get("value") - - ctx.SetCookieKV(name, value) // <-- - // Alternatively: ctx.SetCookie(&http.Cookie{...}) - // - // If you want to set custom the path: - // ctx.SetCookieKV(name, value, iris.CookiePath("/custom/path/cookie/will/be/stored")) - // - // If you want to be visible only to current request path: - // (note that client should be responsible for that if server sent an empty cookie's path, all browsers are compatible) - // ctx.SetCookieKV(name, value, iris.CookieCleanPath /* or iris.CookiePath("") */) - // More: - // iris.CookieExpires(time.Duration) - // iris.CookieHTTPOnly(false) - - ctx.Writef("cookie added: %s = %s", name, value) - }) - - // Retrieve A Cookie. - app.Get("/cookies/{name}", func(ctx iris.Context) { - name := ctx.Params().Get("name") - - value := ctx.GetCookie(name) // <-- - // If you want more than the value then: - // cookie, err := ctx.Request().Cookie(name) - // if err != nil { - // handle error. - // } - - ctx.WriteString(value) - }) - - // Delete A Cookie. - app.Delete("/cookies/{name}", func(ctx iris.Context) { - name := ctx.Params().Get("name") - - ctx.RemoveCookie(name) // <-- - // If you want to set custom the path: - // ctx.SetCookieKV(name, value, iris.CookiePath("/custom/path/cookie/will/be/stored")) - - ctx.Writef("cookie %s removed", name) - }) - - return app -} - -func main() { - app := newApp() - - // GET: http://localhost:8080/cookies/my_name/my_value - // GET: http://localhost:8080/cookies/my_name - // DELETE: http://localhost:8080/cookies/my_name - app.Listen(":8080") -} diff --git a/_examples/cookies/basic/main_test.go b/_examples/cookies/basic/main_test.go deleted file mode 100644 index 8dd99467..00000000 --- a/_examples/cookies/basic/main_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package main - -import ( - "fmt" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestCookiesBasic(t *testing.T) { - app := newApp() - e := httptest.New(t, app, httptest.URL("http://example.com")) - - cookieName, cookieValue := "my_cookie_name", "my_cookie_value" - - // Test set a Cookie. - t1 := e.GET(fmt.Sprintf("/cookies/%s/%s", cookieName, cookieValue)).Expect().Status(httptest.StatusOK) - t1.Cookie(cookieName).Value().Equal(cookieValue) // validate cookie's existence, it should be there now. - t1.Body().Contains(cookieValue) - - // Test retrieve a Cookie. - t2 := e.GET(fmt.Sprintf("/cookies/%s", cookieName)).Expect().Status(httptest.StatusOK) - t2.Body().Equal(cookieValue) - - // Test remove a Cookie. - t3 := e.DELETE(fmt.Sprintf("/cookies/%s", cookieName)).Expect().Status(httptest.StatusOK) - t3.Body().Contains(cookieName) - - t4 := e.GET(fmt.Sprintf("/cookies/%s", cookieName)).Expect().Status(httptest.StatusOK) - t4.Cookies().Empty() - t4.Body().Empty() -} diff --git a/_examples/cookies/options/main.go b/_examples/cookies/options/main.go deleted file mode 100644 index 70d7e272..00000000 --- a/_examples/cookies/options/main.go +++ /dev/null @@ -1,76 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := newApp() - - // http://localhost:8080/set/name1/value1 - // http://localhost:8080/get/name1 - // http://localhost:8080/remove/name1 - app.Listen(":8080", iris.WithLogLevel("debug")) -} - -func newApp() *iris.Application { - app := iris.New() - app.Use(withCookieOptions) - - app.Get("/set/{name}/{value}", setCookie) - app.Get("/get/{name}", getCookie) - app.Get("/remove/{name}", removeCookie) - - return app -} - -func withCookieOptions(ctx iris.Context) { - // Register cookie options for request-lifecycle. - // To register per cookie, just add the CookieOption - // on the last variadic input argument of - // SetCookie, SetCookieKV, UpsertCookie, RemoveCookie - // and GetCookie Context methods. - // - // * CookieAllowReclaim - // * CookieAllowSubdomains - // * CookieSecure - // * CookieHTTPOnly - // * CookieSameSite - // * CookiePath - // * CookieCleanPath - // * CookieExpires - // * CookieEncoding - ctx.AddCookieOptions(iris.CookieAllowReclaim()) - ctx.Next() -} - -func setCookie(ctx iris.Context) { - name := ctx.Params().Get("name") - value := ctx.Params().Get("value") - - ctx.SetCookieKV(name, value) - - // By-default net/http does not remove or set the Cookie on the Request object. - // - // With the `CookieAllowReclaim` option, whenever you set or remove a cookie - // it will be also reflected in the Request object immediately (of the same request lifecycle) - // therefore, any of the next handlers in the chain are not holding the old value. - valueIsAvailableInRequestObject := ctx.GetCookie(name) - ctx.Writef("cookie %s=%s", name, valueIsAvailableInRequestObject) -} - -func getCookie(ctx iris.Context) { - name := ctx.Params().Get("name") - - value := ctx.GetCookie(name) - ctx.WriteString(value) -} - -func removeCookie(ctx iris.Context) { - name := ctx.Params().Get("name") - - ctx.RemoveCookie(name) - - removedFromRequestObject := ctx.GetCookie(name) // CookieAllowReclaim feature. - ctx.Writef("cookie %s removed, value should be empty=%s", name, removedFromRequestObject) -} diff --git a/_examples/cookies/options/main_test.go b/_examples/cookies/options/main_test.go deleted file mode 100644 index 7f064d46..00000000 --- a/_examples/cookies/options/main_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package main - -import ( - "fmt" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestCookieOptions(t *testing.T) { - app := newApp() - e := httptest.New(t, app, httptest.URL("http://example.com")) - - cookieName, cookieValue := "my_cookie_name", "my_cookie_value" - - // Test set a Cookie. - t1 := e.GET(fmt.Sprintf("/set/%s/%s", cookieName, cookieValue)).Expect().Status(httptest.StatusOK) - t1.Cookie(cookieName).Value().Equal(cookieValue) - t1.Body().Contains(fmt.Sprintf("%s=%s", cookieName, cookieValue)) - - // Test retrieve a Cookie. - t2 := e.GET(fmt.Sprintf("/get/%s", cookieName)).Expect().Status(httptest.StatusOK) - t2.Body().Equal(cookieValue) - - // Test remove a Cookie. - t3 := e.GET(fmt.Sprintf("/remove/%s", cookieName)).Expect().Status(httptest.StatusOK) - t3.Body().Contains(fmt.Sprintf("cookie %s removed, value should be empty=%s", cookieName, "")) - - t4 := e.GET(fmt.Sprintf("/get/%s", cookieName)).Expect().Status(httptest.StatusOK) - t4.Cookies().Empty() - t4.Body().Empty() -} diff --git a/_examples/cookies/securecookie/main.go b/_examples/cookies/securecookie/main.go deleted file mode 100644 index bca6e0a5..00000000 --- a/_examples/cookies/securecookie/main.go +++ /dev/null @@ -1,72 +0,0 @@ -package main - -// developers can use any library to add a custom cookie encoder/decoder. -// At this example we use the gorilla's securecookie package: -// $ go get github.com/gorilla/securecookie -// $ go run main.go - -import ( - "github.com/kataras/iris/v12" - - "github.com/gorilla/securecookie" -) - -func main() { - app := newApp() - // http://localhost:8080/cookies/name/value - // http://localhost:8080/cookies/name - // http://localhost:8080/cookies/remove/name - app.Listen(":8080") -} - -func newApp() *iris.Application { - app := iris.New() - - r := app.Party("/cookies") - { - r.Use(useSecureCookies()) - - // Set A Cookie. - r.Get("/{name}/{value}", func(ctx iris.Context) { - name := ctx.Params().Get("name") - value := ctx.Params().Get("value") - - ctx.SetCookieKV(name, value) - - ctx.Writef("cookie added: %s = %s", name, value) - }) - - // Retrieve A Cookie. - r.Get("/{name}", func(ctx iris.Context) { - name := ctx.Params().Get("name") - - value := ctx.GetCookie(name) - - ctx.WriteString(value) - }) - - r.Get("/remove/{name}", func(ctx iris.Context) { - name := ctx.Params().Get("name") - - ctx.RemoveCookie(name) - - ctx.Writef("cookie %s removed", name) - }) - } - - return app -} - -func useSecureCookies() iris.Handler { - var ( - hashKey = securecookie.GenerateRandomKey(64) - blockKey = securecookie.GenerateRandomKey(32) - - s = securecookie.New(hashKey, blockKey) - ) - - return func(ctx iris.Context) { - ctx.AddCookieOptions(iris.CookieEncoding(s)) - ctx.Next() - } -} diff --git a/_examples/cookies/securecookie/main_test.go b/_examples/cookies/securecookie/main_test.go deleted file mode 100644 index 0754c9bd..00000000 --- a/_examples/cookies/securecookie/main_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - "fmt" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestSecureCookie(t *testing.T) { - app := newApp() - e := httptest.New(t, app, httptest.URL("http://example.com")) - - cookieName, cookieValue := "my_cookie_name", "my_cookie_value" - - // Test set a Cookie. - t1 := e.GET(fmt.Sprintf("/cookies/%s/%s", cookieName, cookieValue)).Expect().Status(httptest.StatusOK) - // note that this will not work because it doesn't always returns the same value: - // cookieValueEncoded, _ := sc.Encode(cookieName, cookieValue) - t1.Cookie(cookieName).Value().NotEqual(cookieValue) // validate cookie's existence and value is not on its raw form. - t1.Body().Contains(cookieValue) - - // Test retrieve a Cookie. - t2 := e.GET(fmt.Sprintf("/cookies/%s", cookieName)).Expect().Status(httptest.StatusOK) - t2.Body().Equal(cookieValue) - - // Test remove a Cookie. - t3 := e.GET(fmt.Sprintf("/cookies/remove/%s", cookieName)).Expect().Status(httptest.StatusOK) - t3.Body().Contains(cookieName) - - t4 := e.GET(fmt.Sprintf("/cookies/%s", cookieName)).Expect().Status(httptest.StatusOK) - t4.Cookies().Empty() - t4.Body().Empty() -} diff --git a/_examples/database/mongodb/.env b/_examples/database/mongodb/.env deleted file mode 100644 index c41f59a0..00000000 --- a/_examples/database/mongodb/.env +++ /dev/null @@ -1,2 +0,0 @@ -PORT=8080 -DSN=mongodb://localhost:27017 \ No newline at end of file diff --git a/_examples/database/mongodb/0_create_movie.png b/_examples/database/mongodb/0_create_movie.png deleted file mode 100644 index 17e8a71e53565a240bdf9f111b1d6449b6b194b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 93838 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 aGdm`|tF1?T?t$rXAik%opUXO@geCy%3SdJ3 diff --git a/_examples/database/mongodb/1_update_movie.png b/_examples/database/mongodb/1_update_movie.png deleted file mode 100644 index d0482aa6b2e9d8ab5d749c3459480fbb169d4c25..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70592 zcmbrmby!sG+BPmdNX^jF3=&FrHwXxbh$6_)Qc^=V2n;ebNJ}Y#ii98?g1{i%NO$MZ zUEku_``M5C{r!&PJKp2_Lxh>N*4*p5uXV+Fp4WsuexyQlo96bdTepbRRF$6Gx`ji2 z>lP+62p4!o_DIAN_z%P7iHgFlq8_?6;16soc}@9Sw@P9NE=+NNzwzO!`YyL_k-Fae z!Y1kSk5Ra26G>S?r@fs;M>FPdwO#bip`|qj(zax*d z3ch}Q7?geU0l=pq+2n72FAK<_20r26FM^nzAN=Qto5P@1cRBu7Z|6%9{QGLw0?Ss3 zEAQUXh>9%nrh&5;v|+GKk%N0zB5yi69#%ek{yfy@1zwr(ytb|`CAvLEAvzRW`R|oz zJ}}2o#zy7oe10L2>N;ayl5)<8Sk+USc#WQ_UE#j3`}FB(SE^vMV~G4nk>Nfi1%Wif z6T*;x-$t24sb#mb0wy#FrNk`3Q&03>`n_Qr6{1SvBfshW1J4_K{L9q+>uoLiptwio z<00eY<2yQYeGCiC^4fpzLw@tDeo~kMh-6EiIs6qgB-o>rmBbKln+L;8=u+l>G1Y10Qd_;Cr_A`RIJRA#}!$2jX;gur|kD`mNz={6Q2A zg}*J`e;?gkce~c&0MT|Ezs0U@7tW##~hJ@SqzdaD<{qb+_nA{!a|KW4&9^ewPFN8~>prm$})T@#;;Of-sB(GQx-iXtz zRUPLjRV<;z(G{BEF+E0U=-R(y;BeyERry|Te-57Sdnm7dar9B&?OD}x5cB$noS}IF zUJHvfw0(=M9VI$F8E}I%VcVqNLqiB3#OJE2(eg113yV318)G7yUy0v&WSQ3 z+OqZp(IszNlJFb414Y8#6#E>bi!{Sq%;tCt@iHcT87;fz1yal2Z&loQS*61itd{%c zInd@PD|@e}t!-L4=^WvAb-Gf~&XzWs>4RSTRhoHyxgBt{S=u|^&Yoo#!CUWHB`Uk> zVd&ICA!6EufNO>OU!INSea>7zE6@xC++q0>D~|FqEsFJ|l`+88TwC^f7L$N$_LreL zcXmZ%`eGlrhf&KkdsyAA;7k~y?mMN&=@K?UExe<`7icYQ`$U>a&nmUm+t}_^Dl%G{w%&B{K?&}f1bwfsA1D=&>GDUMyw-a$Ue=!Kx)aR3Zvg5Zntew^`{@_=-QrOtP!Q3>#Mcf z^`(cy2H$#wy#{jB+$ZcS#|%BDEPAE(BmIuXtSZ`|5qjT@eoSt!F^Sae_ei3Zd32@L z`aWMCH(cA#_@5V^M^5Z1l1RS<>{3C-c6PM2;ZN{uM%T#5XvGYqM{Vf4+v2bj^Li&H z;G+4?Ih;^oS((akQHcWe8d%D&2a(jKwgn|`YKeIUM5kQirvk1o9|>K~g)&Zh$!tM% zN-hjM=R&s7wcGCV%>=x4v-8bPU7cIojWSKDqx!5#LM%kG7dwizN8`3zK-ThDLnwc$ z?3%|BHLU_-k|A}K2!jxe)}GnhzR4Z%iqVfTGV29Dki2V``@OQY8!XPi@~Dmu2DNJU z1#(L{r21lv{7)@tW&M4J?Wf#E><>~x1d_I^sk@di53xE?K$wPWy^14U=dw8JjWm$Q{#SdQS+s4X(2;+N6N)e_mw1sT_8HlyD5F<-`++|w5l;jdr zPsO;=+{$u2BKz+&z^sJPR2K{~Y7QmoeHGFyh16@-Oc(3FI;w0K3&dksc2K3l@T&Yr_2 zi^I+OwDj-=>3nw@9j051{ZCt3xFtqdlAcvgd*_qkk;q=akEu9Wl}0(Vqz@Cw)QQDr zZ_$d_rPRupF)7?95VdQ#JbFZ@09F#hQBqNQ#FZ2+eWWKEz-l9>_fgjtMhl7C*en}- z^r+8orx7pXMD^WfjqR)Z!q~CEqtF5PljyM_xeVw9NPBEnH2R)UvBtst`_S*J&1Wbw zEwK{W`^CGG2INJ}!!N*@8l1xW((&pdyX~%ANsXs9aP@yuC6CGNZ}je?jVZ$$EmX#? zK@7T{+A^n$WLDh^A%a{~F;aV~9y~=c+P1l_#l%tveTo|*h*FL!cLwJ+W^@g$eOa9S zkHcXH2RKS|8L#y_d~>wqkqPz{v|~<0f5s$phx7q z!5KziHo1wgI&otDf!cbk)>tE$74T@41G!=%7vDw^R@XvihNqi@QZJ+DXwa+5ZLar) z1sRZ{np`iQK1ndVRtRbU$}0aUOzzZAY1vb&$bYhZzk?j8Ih>?ZLaEdh<5u9U=LWjg zN3+lwDsj#JmnL_&oEL#J?u|*4$LgrZwe0j!pF#tQFGU16v`)KlREMF5(+^#b}fF!Rp-df_cx{Crow8<)i(H z*BDq$#?DxAA>v(Nj^ZG*Xb}`>*^x^LOg6|ZHE84psqz{O{ojtJcg#M`rhD_w)D5B zO#c*JwL$V%%V~}dA5~)9hb6U7wt%YVoo%K(%&}x$5!?2Whd}{ZDB&HmhO4uDGKy+; z-3aZ@2H30w=u^7Zs5C09%Cx$TzdMWs>lk%;=eb3LY4`6~@V#+Hy>e)MiSh~q*He(y zP!0G))T#1mL?RS@YUgXoXs`A(askFGQbFl2PmQ`ha7QFla>=w{YJ*|`XWWMAKyIz@ zg+c>d3}L@m{#a}9=~5$%tx!Js!g^%B5M}h3356vk)h=z4 ze1D6IGe)uls~-(n7?jb2XD*u9LWr~39mcxO*9^}~h7@0$<5+Q>foD&;WVT7W zO46IF3%S$xg631qqn%uuEM557iN_{WAsP_n)GT3Rb#{V)A2lvY~Dl zkfrVy^K+G;NFS-nA!}DMeKvt`33p)?$TC&$)g}0*4dzwknV&J5mNU zW+YJL>0`4<;C%#l<1bOmM^ofEIel{Y{z8({4-^LMMuQV!>#}Y42uuk_vnc`n%aCzs z;(#J+pZTVGeF=R=Bd@EQ-Ji?9WUnY?)G&?g2n#C(D+p1JXK6SVTN^JQcT;9G^PB&w z>KO*sLyfkV(u92a^a+y+A16+Cb=n(1S$581$`X0nCE8D&eQZOpHZW{rW~OUL_ICn8 zSUaR(#d(=rDhO1`3ASd3=24FJ{;CV3la%Fr+Nr=FrC(|}MkG2pJIN=VdL&G#J1enW zw?Fv`#(@2Uv#6@6yS1O8(JfHTdxK03NEZg@t+H39K3nC5FGPus59R4J8+XfG zU${u3s}}5Hq>qXRwPdI0xAXGyN|KGd+oQ$iLC2B-r#=3vZ1F%g|5kkoyKW-jO}AAR z)%sLt!v)kssRqu{eo#~0$eQb`bHkMHaq8Z}!qtd;nYXg_j>466CeK!gooKVh*l#N7 zzv}p;Krj7|x?%m|6sdy!!C%@+_7(GQhciazm$&d{m`?R(p(`3ky2|im^ZA8{t|xL? zmbu!yt&VnSvo5{*xxIbOf2#NaWzk$EIdI!aKtk=|{y0oq;jauWzN zvt*<%M0i2g9@Ac*x9ZQ)4p38>%3=@Aq@#DYFv2Di0%?hu=Q2jleBFE-!5qo-Jc>?KYoVmIlM|08_L&(nGK} zAS@4Fk{3b3FTcJ{Ra!Xf`PV}S*vJ{j!=BR7EaG;QrhNYxP;)W_zbL2%%Z^?IaS??P zfFK~*sHG7bHJ{Z|nhEd6Vf3XAd44hcP+5IkG_NV>s8E4P;ew6-tIOWB; z39RV|R*ll#eExFdh_^zS3ONzFV7v9DTz#v}WMNdsP#`o-?E5+=L3{C&-iGT-M<1Zd zoDw(&qCvssPBV!+&`(Jal*h5CjHfx)ug!a$Z&mh|$0RmPdv9=`ujhYDw+^Y@0qQ9< z+t#8)OH0e6yOR4|f`#hIJZ=ii$6m{+R(8N8Dy}ZiYyDmyP694umtXKboD5QbedS}| zG37SpR>jsd{_MHo5=scgkDe*FeeS^%MBBMu`j#6?n@>`bJz^HYy^I}^|E+!;a8_cU zy>|AM+r|enkBw^{Qx0tJ13jTZmW&_Z{|RIT=c8L$7YHOT6V$bmm97QdD#_68IL}q&GWpw zg-5ESW{)QvYVC_=Fd}3Jkmuh1K&xz}57e6mHE=%t^`&HEbWzN#S{3`FbTKXO-Qm}# zMCkc*`mrGiH)im4%zfpV}#Ql>kG$^b5Q!CTC@aJfbMe^he?9?H4T#x zz4M*axk@j!tCPT%WCpX6%rRP?amIBuiABdxm#Iuwdb!>odK`1u4>P}OiK|^__~<-$ zW=-aUP-4Re5-&a)ojyCNV$7e3OP=xFk0Ky*do6)~n2{FcJMdS(lFj-)0Q2-nTP)@( zAFSZn2i>z*-!t_3k!#YGMH0dg69o5Sm}Iv+FVr;)EqwMWpy$!JR)BDw)WvPT`HJ(0 zEftThpOT++dK`&jn-SV=FiyY?`Dc zt9!c!4%IEcqUkpf%D1KN^R+5#J`6bD60KBDrc%*ROt>lInxtK3C151#5?t%xOpzI1 z7xu~1FhK})wd}ADGLUO9h7TWPRfR{U)uSS$Fx&Z{!W9F(KWZNHS1Vp{t5;%!iyg@v z$)w=4O`)sT7{-j)UyRpsKUOK0+AMCKbOgd*9+|$+(dL>GDQ`Vla8&m?yxT(iW z_Y|#9f!%{iocG`aKnChUph1K-H-S;CQwIA*!9z7X#9bK``l;l^G^ra zguj!o7*HHsf{-eRR7pk7MIXrYQ0?q3yYGY7AqQ{_8xh|VcycHzN+2%kU9uxc)`C6R ze3`0)017)>-j8TV^;c1Kd}Rc*R69Di3y7o_wTJd%dqEMIe?*+yAwgjBhRlSrbD6w~ z37Ie7m1|n;;oHkZlnM|`3Z`PN(k_8Vur?|s#)8)3cZ&Qo7RiR`st7kKXy0EIC>mp) zu1Rw!l)i*;t~HeXb~dxwg06x664!AR38ha;-uGENg=t#Hx;d_Mup(r zt2Apr8~Q?GY@lVvYPIi!TZ8#n<>k?YWQ682{=q&)P$jghf|S&33g|r1N$hw^%{QP= z$nN#k_I0{-CoB{cg1qsZWc806pzs_L1&Gt46xSND_#&9SX@`D;$6w{8M!-k;7fLM+ z2X)MmSh$36Qx-!=X!~>C#~4BEr(N4s1o1}552e&leUQd^FB^eca1&2`oCTEgS zHdKKiz&{1Jr-M#qh984skwUK@BQ}JxSyI_ryQ0~&7Gm6m4$OGLVUdhg#l=mnU`i@7Xo9MdvAo)_3+HU^)L-sme7b45JSkr1am?=$$lhj#YZke zJF>2C;=+PhW}|zM@<_?l$qb-4d+9V{(ee`Jl)6E3 zytRypv7Q~l^ZjGAL`V0f$FDn9i(IRwzwv$0)t_BzTMln9BX@^NkPoP`pCT(TL>+tp zW)>&r)I>4&v|gqx^*S-O2oS|_-^axq4)ec49n>|_r#wp<3*8WPSp1yf{$hGx#1kAX z3-q@uJ)0rsO>RKtAX#aNngKHAwm89;Q#m?_l~eo?t;;L3jO2T;Q&NMM@RNIz)pUcI zazZbaow)o@J3UC|xfR$b6YYGX>l40g!~Uv>j)-~JmOd~ecKR6lcox;odu$vo>P}A| zukLbypNUg?!JWllat+A0AJI|_f&+^s6v1W~^pgn4$Ux(>JEGRn3p9Gw!tP5ZC|+2~ z;CA!zmk8nEgsRK=^(c-Lpy;T+Bx^mDi1k+32XLS32K<6JvN>XaWfVo z3gg}Vr4VzwEj_B=YokrDXP1*McZF!!=OWst+9OptHu8nx-c+wSJ~B4vbU>Y#9-WG{ z6tweJWNo%6Ds9iHm40PeF*1o=t7t8Yc$XQLLB#(Dt2M=*Y zIVIUpQ#5IX8A=plx zQ9U}LefvPCBB@?u_f@dz?#Mz7$aZoim_(-d20Ragq=)`yj>zNlU{s(rqehn?t@S`q zs53+M7?rUv#7JBgyb3_?(xNKNO$;W#TRZv-3et`E!7X*FAW%qEpdcPI*rQ zm>v=>&U|?h+|`Pl5DL1lz|1p;$e0O>kWIRrOcTG-n;S7;etVRI?*emnZ0h*|D%DaP zh(EXNpzZn454}{?*~>`G{WL4#A|zn(;*Mgpg^`h#y{KnqAV zgWJcT6!qOXq(qqEO~}sMAbuGdZF5wkLW~MP9^DV~4E(9^z;p}ozOhj+{Wl&|xgzB5 zZ3v2ddAwO#Wc{Hh0I-PLmfKg1{le!)>J&WHFe~ZcLD#LF>v35etoHXbfg4FGrrZrg zV;C_>C>^?ttAI+a)&*`Qy_{kW8^?qW12KPtYcP9%n)&hf7yO*+@!Cj7q<*i=c>#g! zeqqTD(l|Z%;TwwyzvHQuf}J)+7%OCAG!&$4L@J{60L3|f=Ld;U0?#B~gyN({H3_8) zS5DCTu)bfDAzW`1Jn@?WG;Brp0bBj1`Jt7rGTUU=LaQ720PeCp4tj$~#!>jf1+qTh zEY&g`pQY?xM5ns`@wQ5?gHXr<6?JCwd zl)?K8+3~<&1VskKsx((N%Ferb_oVCtAu~_BXadgiI*b3>T*p%tYet%{EA5Ok9{J+z z0hi-`t=)GzQ81KJk(TcO^OoRNFWz2y&6}3{=$3tT9YkKr231V$ z0^_hVRU-|79VYqJ7P)k%fiftCOZ+CYqF(SnUGXuA~bfTJLjmHaq^E(h(f4>)0(egP-(QdNMNPQu5z({N3aNw_)9o zkdT1LT4ri_{8!)muOD%O|3%Y*#s7hhZqEJxysiE08S8(*rN54#oe8-9@efW1EJn#e zBTL5czl|VD8uka6cXJT>AGGo&>HP1w$^SQI^Z$A_dBS@!%Pwlk#aPA7iU|jT<1)?r z_wR24So-G-&-pMBi;e`iV`tpj6%c&$wn|zVjxP3lYqzucPJp7_?)vh$5~$bjO|rZr z%k}6KbX$K~3y@m&+dq!oC$=hQ9E631=f2Sg9~_BhSz-4oW=2RcZm^6jya@l~PrQBy zVA5{vW6Dg>BIR}X`?)=UYLoz7|NY7Md4SM^pQ}VtL(q`ww;F6)K)qBs_(-xF07H1$ zC1B3&tVbK)8s4bn>@=Z(l4~QndikC0W{m6=C_od~I*Xfjf!+xPaoF*i4a6JAB9SsF zwdy5~QRO#n!uB93YCc3)uP~&EyI7uVObS^|1J2fcD0+KW`to3K3uvq>*4NkJjuY=6 zHyasyi{d0S+yMAjSH}$#2Wx{Fu|e+@^dlYiS-xvzN{!{(*UxKL6rXVGq|~1-(@LJL ze$3!Q$dTiivJbjt2a&j)r&?u}h)#PpzagTvtlg?eEBtXZt_y?FF~p_*LQv48i99w= z>l@u67byEy_Mt2eHFwhz9aiMF>qcL&Vf>2&M>gej-wt2+73G5U{y?4uYZRcz8uSb3 zAOywm7nZ3Oc0XTZ%uNqTmt?N~&QIoUxY(OB3OsqIhE!bvELCv>Fut+{u!oP)&e`(- z(P2Vm=o%NrC_7CrXgkbxe#2k^O!cR~8f}1<8~vjFG2KMieq6|d@N@@g;KVVUc4iwL zVjFjz_tM{qRhbYM>(2W%VmXoqz-^{lqdS zCZcV?^D{HWf5RL8#V!J!!vsEiy2-8*qPk4Y0Q?|li7VU5gawi|ih+I#&sT8{qK&upSe@#gCXp3r-GG>zRa|0Ht8f4E3g2 z$Qv9ePsry?@2`??wvqR!VDP}w$9H6Wt0uM$XGTwMtUO{!t6l|=pMBLeUep(vEvxxJO(m89?V? zJeg*WFAGrmBu*y)K0Ak93H$jXmJe>0pYGb0!e5Q%>kBx`_N;PNDspgaIND;cUfzs)NloNMP^JUTkq*jb^w4vjEewB;=#jZ+aZ~Q$+ zHC`AFiR30974KfW5Nj91{KGm(rJr}aagO;=VeCTHgBk-yv-?HEgr9!IwtE3U-gCp# zx$PS$>>LP{8Inhd&yCjRLnqi8R0P9=(AZ;WGMHzCt*5)q+s`= zTyV+C&t`k>4D=XaopQMAcADm<$uG|i31ltUqzMx!1_G0*Gw%pmjy99XZWcKBjYTQQ zcy zFS05K$?g;7v(J>7E(jh<&WJR|b4w+pS!XmH45%CW+5`(U{;(lY!&`@alE4{K91wir zA<(Tn*5{Ok zW+VEzB^T(pB)97Z82}<$0wb~t$|f+|v=zNTss9opI(mpn8$`)7(q-@7CyyuIxB(CV zh3Z*n0QXOo-c}BT#p)A5>snx4>3w*Fd(^L?NlcXRfTqAD5{Gt~j4I+L9)$@2A2I_z zp;R(?hk0}EHjR zwdW21Y0op=r4ss#GT8Cw+wg;5&XIL(<(pn#e1=4E_l8&oQf$Fgh)$rQn8sH`h9uMi zd0tFPP}zG_dPul~Vky&ZU{#LL1m5Oxv@dxM5w6M%4J0-rP{{GHRm7I#!bT}@eJRdX ze80mq%>R1vowjL^{2fdXR@y3)C_OeAZWdB{GWnc^i)kGwY;2Ei)FcaFwUfw0+F-G0 z$>T|vj8$9|qo`3q5p^BEi3M2m%=38m%!Eg9zSXVdzI>T7oSEUL8`!a!XTKFf+@vUR z8lqN36~wS6`mzlyDmo6}B3lEI2W*V0?0eXiasyGlsRPM@qF4sF@AQn!G~bvgomAnT zLkOr%EWf{jb{U~eem<-=ja5s5NJEU&*bAbm3x-#M)>_oA#dW5k&SoKs>0#&o=UY~O z=SOa*%e{w>c}lWb=}*;V1Y#}a(ur^{3DMQdK+4-Vio-?fH(YKx@=S3IPPW#1 zn^`D(>u7QCRwqf5IDPUpT|=_6WFs1IbuCe}yQKZ$-bVm3^^IpbwF%8kEV)${Pxiho zEtpuM4PQNhV7->t7Lmqxio@@GFFprDfuU$?dOoR`iOt1tfQ9U8JVCSrf34#Xl3r~2 zfY63xOL~zrTh=~0^y~q>dCvoEDr`d~UzjGo_XOJchZ1iy_1?v8_vhhf4^a)n2H&`cxraJ8y90v1YWU(Ho9FkC(29d8j~O@K zOb*5b)^)n3SD##S{P!aFO%-5E?}pSnGD2NSelF>C;2nlg(F1yc8e3XvBKnnyCr$00 z!mx6u{ZEt7y*Ux$>Y-y;2lpb43dv#e3jZO;*>J|o~?7_wM81%i-mc;(CD_MgJ>>c)Od7tY)$qV4a^>08@r0kNKn zSKQFBO7Fc>&9mR4Bg{(x+ux@A;+6uQR|xGIQ24JQR$Sv)XsZ)`aDZgjmeOq>Yw3Yj zZZur9X56Ol>rS4P35HB5W_l(+*;z{ZJ{w|&hLkIWz&h`qD%F7%Ue|q;>Ca^P`m)J5 z&HNraioo_hg1catBfdIE+6|-g6{TNTI1`8u#E;|#G3l8@zryW1#7_8Pm$d^26ffnz zER2sKw41`fidDt4dtORLOafkU!ne)t*(hhQkn9ESA&^KhjXES5rjS`JmDxVCPQ6My z<*@I-n;K-_6!}X6lBDWM-gn7E)z;N93a4_|M_?H)44c;Mru&D%R>`5ZE)3b3j3KK62*^cSFu?w{UM8vgIewY+c8+3!J7ViA8KE9^=u7mAB)U^|w!RsE zdeaXB9pIo&Y!DRdWK|A2_&&RYPc=MTak`Lb?j9}SRY{5}6&v*d6V$|Jr0;e5hM-CG z3-zD|hNkFB-1(|6Au8m!u2nf^9~$YN=rQq+b|$*+#vLFP#PG2wm9?qAK$qbG(T(@9 zJ87H3a|wbl_eXLGxQXP`^+WDJf;LQ-khz4EhOij%4)A7`Y&L6?ro{Aj5GTuIDgZVZLAV}QynMCf^EI&EQjvdbNA~)tK9%!LK5*?cj#2*~*c9FZ2j2tM) z$t=ELgX|R(?mP4%C<4huPwb8lM;^S~-8Ew&uCjD7;<3?6l|!Jszt)QZ?#J5nXtc_x z;=~KgSJK2nI9AksYKMG)l#^jdP@j*>lm6g4Siw9g#AZAo{}k$Age)W(pdEoBxF&y= zAodmDY=7mP_NPUG`_49G*+L2KYhLXh=q%zT<`-I3B!^);10oO9WTWAyRmyqWVvNsG zSF5FjRMti>O})??WUV95XK3$NX8O*nGQ?IO-)Nf(Jv9HXjWlza$5UrOU|}boDXAA2 z6#M_gWRviG`8aaPK#`K>=OKh-poO*w11U{dL(Sy`t69PYJ1jRV$f3p~+pkh3!!f*c zv?3YS+`Yb zNo-IayyQ&lCWUXP*YHvSE>h;FTw)`CYut0t8#{)*5L^C}H+EhTtem>3lN;}YiND{F zokcb4_eGg{5tWnsCl@`I{i-QoT{u>2BHwKbl1hDa*aXw=gDz!MehjR`ND)pXg3Yun z5a|G_M3Ntd`1!Y$Ye3&=t3Zz6slTS~@E6u6e!48bC%Cq2*1QK$%05aEY^nh!#!fRv zwB0V&UX;XZ9M)sypO!!oIo}(Bv&^vME7HM<9$MRF^4A787h|(z?cuxd2;HS)d12b! zb_u~u{k9L(nD9ecvazOjj^o9=@e%e#_Cf5)W$L}^*Xe3_5H1?Fak26HO|%qqVr(=b z(Ja$44w-MF_nmUP9<)eZPtA-Zcb={L_$`S%EONqz73x35{U9=-UhX^b_v5$Uw~W)W z`kvz<+XkK-XphJ2B3hWFm6$=Q%7GCR3g{-l1k_Kxof?B@QL}Hvf6`z!63WM(pThZf z%x{If4`!vq#0t3c-om-xLN1bkJxPxcC7#r1`jjcd82oD#?qv?%yd&*hMyqNr-1L5^ z`F*Usu&y_fYt5xRu0nfYFnJ%ssM>lU&%UNO&iD8L-I|zV7d^IH&BUQWa?QA@obxO$LYYt!!ZO2Wb zLY3)w$?HzYSw}<~b&SV%p}{9`dRZduk$E3)0}#@$|4e;)?t#WR*lqhW(XJ_0Q%5Hm zwhMa2W>swd;X6190B6|%34U8D)ES^=cnzwf-rCYt;|{{W!*=rmixdAT_(HQw0lZ#H zVujH6j$JYTzol?FjM2NYCV!TSwz%%@%;T(eq-v^SgQmQ%4f5gde58#nr@Wf zwFjL^l|y75^udk;iGgCK%A-meaxdjv_tv`oanXo7RQdy0jZsqUMQf)D^*U_DW#P9? zQFxp@O`6ojKh0UqWOUrcheM-;n22-4hl6sQcr17gF0qXLt7TSL-tx8H-9KcmdlLFR zguacpz*k>B)fI=)qv!Cr^QpTFcf8yc^zM^ZHNgUpdn1_#2S+OP^j zLBt7kxU~fXdZL;too_~dhtHmiLabHQ-*cPJk+0)Le0W^>z0r+>4Afh1hqaWdtf@-2 zev4qY@6lWLx=kjHvX;~ycInjkq#Bhpb>EVsyM}5cS=*0|_3~svCPcYJ$Fuc|{9YZ7 zLuy=KAs;wmh|2M0ripUt=T`1CpMvaBS-{2b8PrjKm^^iUtPqER$5{fUo({Oabbw>%MeX+p{%f}ag_+UKH|5%kDs9~_SVjp z5qoo9JkAbf2=>K&(AD{isfPrSQkNMhfq5&~AzE?qu9RL=Nf5iK$9rIv+}|)H~*zp*3SKdPn%Wy&0GZ5|=V_0H>;AaXC_>Sf-tP*^(cl zZsRT@>DKboo*Z$|Cg=|!eFQmV*K*?5muXn+5LoiTI1j+C5R?nI&*9v+Ks}`lmKgxp zH)2zO_sa9YJ?)f(-D)j)2U$#Phq?0Mwefq{z zqxztU!3}p~*t!ZIYwe*w*kL{t6uJ|im;MrKH||+vm|zo$X|C`76oKn&IVCacL7KGZ zphtSIplqbP2!AETf&On_GKmJ>Ca$X)ENd$v?`m3O4cLSiE4cPNAIBCMf7C<>xLW3$ zCPjUDj*kq`wp}}DW);5GtB(NaZeE!!F>+Uft`jO#Kef-)*UzvAT>$V#ce7o2Jo?4) z8jfl@6_^dl;KY-j{fN&(PiL4%oYU0lAlCSJyx3nF#yUu{**SlFuFP9Iz0s`RFiiet z@+vZ6Vog7T<+16#aj^&^>x7MbZbc9+pDDu3Fd)qD$O`OJ*ojBOo4);VF_5;b zfc)PRb^pI?6YA^NuWxleY4rbbHEU7SgXpqRB!n`*K!{fGmsw*HLHjdZ{*7trizMhB zUypOex52onhZ|J>WZ8c4HpG8SJR+?3Q4gZNpRmLX;fHa{J8zYDdmj`p#xf^uPKdG! z5mTGAvnGLJz}Z`W5^h_#?9geCtd>mg`}sI#&ZEUcp?l8k7Z$8(6brqwD|S=VE&4)l z2Md-K$^eceO*3_#i)96m*H}*NN$^VR1Fe}MxU$jsS zpPp?LZicZpN#7&&JJVYlHZWLvB&mORwh`)M5IQ=P$CJLR7GH33zCBfc!rP#yUF;Pu zd%-9C%{=qzw~{x%iRr9=ZxpV~>jO&GIbH=JUI30Kmd%a*gKE7^!-cV6m1(p4Ig9uh z`(V{H43Ge$(6zlzHV(ELDYNsq4$~@154ae{o@@8NZ(&J_L`he-P$rF<;;jsDE4eTw zTm7qb0vw?Xzs}a>qGqE>8Uqy8%3xdGxV*w{*E>}GoJH)>yM!0z-a}t@MnFqTkDhAa zrlFMkhyLIrmE_5M)>tEE+$ZWN!{}923zF~Ya9#bPr8FlP=r9l;W_HpR;{SsHVvIXF7*dvb6^p(6Omj0t*y%1UTye-vXX17W(pXs*?93fOh?OY|E{}d1WHOS(rq3(Z&y== zOavwiLg|OO@{J>oBL1LYg-CQh>FxTTi;GT50ABa*99_Byh&;dPb3+;ljJV238F*=8 z$fy{-ITELB9QxbkgVPDBu?^w~{#?@{lM%&Mg+azMm~-N@Cqci7CH3s)Q3+oT`xN)X zk(X!P5Xi*(t8V*S*viYfU8_%`CCdsZm8Ji*V*ES`)h&|7@|2lWz|qXY;#GgF>xe-Z zvM}7>V7dOB>uRTYE|Yvwc}w5wo)${#zfKL*)2q8Y$`c27c4lyHNnt`&mAIsWq|E#2 ztg5L?UL+KA48;AzZzI_n!@|-W(aVpNGzz>HA*C2t1xSii&ij-6?dU1)u-K~WD|9V~ zMtU)T7VqDVpfbGs-1?s}S_F8%7v|9OA>~WR({Y(pL<`F1vv`E^p1!Mw0DkyCW4oX@ zs@-_4BC?FTY!!^fcMI=GkH2!PYOKyv1jLhtp1Fz3Mn4Q(J^vv5p;mCWXh5iYz6mp9 zWvh@R4P|uro#nTDg*ngfVj*UiMs z)v`jrLv1d0i~nW8S?%^_T)*gBB%hsFJGv_;>pRNbIe@rd)w1IRp!;$U|NtrXmNpV7laH2IDh;WcSn2 zhFRim`lcC{cCw;ulLmbU#Sk9&DYi<$KgL0l1FlRrVnVrCtGdy+|iFUi1s8aekb)z z(VMZTyy)j|t?JF*>LbSu+-K$RewoU#r)=@y-|~xbVwb|ru7?fcHL4Lu_-J(4LbOZP z!tu22?naSImU8O{wLc!|GUJQMupWusoo1aZMfDu zxWudoo|-m4$}Pr!=Jye8s=KD4sX)#sAhmUDke=j3(Y-ZrunD_7_Q+ZQbmNq-ApdoI zN@z7KBbC=NjCInAc_8n{+?$#`=8=`?n~CFpTTr1(bLh9%R{7F8*E+jdBMq(Kr=m^d zf5ovb<^IIy9l!M#m0hE|PYNqv*r7nj`ej;w+^`uj8Jn0qNbk3}xOMC~my)8A;X(wl z^wXl=E$Tnk|E0NbC;~k6EsHf;l4p`riMZ{sy7|wvdGG#xuB(GVw0RIkW@qP=6|=K) zQ7=8#AD4gw#egeMZ|tZ!$?3wz{aN zLR&koW#Mom3Rq9ZAuv+dxF8^}asdn`7UR!N5*7n&`WU5wohhwdaUcN}{nQOCb?J_R zsOWjU6ws46cy8#H_?IdJXo$L83OR13&4I5L7^5`y-G#?+U;~09&D%7Iz_@#e&t5PF zI7-cX%$n#%>j8}HR|50JLn0G)rSNZKy|UMK*T4kS=8cZqZnDaWo5pAzWGVsZRSJQL z{C!_XO+aR~RlSl~I%4G0EzO}?3D7y6Nd^w$5iMpe^v$nR4-Bm`-0VgSJ<4$?^?qJv zYOvWq?HlttnF}=(2XJ6O{%|v*Uv-2SAAO0vM%PZ{m~fEAj_MLn?sT zm1_6j@r4ECH2vQvfYCxgVe~{t#~k3@qqzaW`^}U!!e=GxK*|%ChS>tf`w0UyO90iz zlHv1v@i$XJoGt*xX!fX=?mGP(&?7ZVySOyrvya}4dddu10vepOBS1h@<4yNN=5Q65 zPx0to;uzvI?(wbjIb62@bpM6GS64 z53H1UdLv=u?Y`qr#xcezJNUiIZpKf}lM@p|RD>9?TSBOe#B3!Md?7J{bDg5G^=S?@ zHp8w!?cHCJa_8Xsj4`0@946@PIz{Js*nfGkHuw3{N*}X@dn08=p^8`6D^mHa&k{Dd z%KV(1B56{RHtaHjgA7*%_oZqqek$z#6z;IQC_~VntrF7inroh@55}iUkC|n7znQrm znz!OkAiMMcNR-tf{-l@Z6N@(!)s|Mn1^P!_g1w`FG6a3VcJ}CiEdT3Q*tHuVIkFwt zm3QIy+IzV%R=TrCA`lg}@i8ao?nS~pK<3!{5hzO(w=(z?YyqOr;X(t^^X-7^4O|bx zF6R(TVSs}h$(y$R7&U2v@8k;13pmUGn54B~jVpc(B|ScF7eMgE(B67r3KwliqSv-w z1tv&rISYyvs@PjX8U3vR>5*MNfhV_`qK*3011UL^AB%6*Cuu)RAB{E>MYl%Y5gg&q zSp)284LDYYEhB^HEXFYy0}+42OcP5VJOj_oUMz-#8z$UGZK+a`Sp2SIf2eIV zo%ldvDQu2mlGEF<;zn4O1Zc`?sCa;mwhksc*qkMx>EqFH?{k+My-}Z+Wl#FrI{oeu zed$?;PmyWF9uSVkS50;x6#W|?KX{L)@R8q6;8Zd?W4sw(nF5%_M~DMnsds7e!MNS= z4t57o;I)138KC5mz%`ulpSX0}XJ2Mw6A_jC_IMqIV!YBAwXD=Et*3fak-2hdfhQx? ze0BLqIU*t~+v)D{%*h2vz%10_FCA);&B_`7B3Wc;cOxF-W~3_cO#`$H z_g=*7Qjr6i8F>TXyCNnhc5irUTw=Oa+@rzID_2RufdsnYdS*95zn*mj#z?dzdiBV3 z?R6W+-U2XxSbjVc&@dfke)~>=Vx8(zV-W6K-aXS>Q?(wBRu&ubstN~9(A+$wuL=P8 ztbA8tw&g8&?v|!kYE3JPiG;E53{{yXI$SNBR~5$&kJW&u?$P^qR7xVx-z;^lfgd9+ui#SD@;K=7F0L-t&tDe zf{FO+3>I|%hqt$ki>eFQcSTa^?rs@Ux;vyqly0QELAql=x+JBQ&Y2+v>6Gs7?heo9 zdH?4@CtT z$-ug;uGeda099mo{h<~Lg?8=X-I6Ku@h)AN`ZfbF6hw>v`6m{uAmXE{d__yc{rud; ze#)MDbk+x(LNxt7YE4 zu2F2*vyDBR9(v;Ea|3NRdwsn2(ko$~FRG0Zsx2OB=Ge3rIZMm+|3p?ReRQSDI?TDB zJTJz3^zpcxlQl9!k#h$u&K5-DD}ASaai7P&&q=nw+}3tpa_MtE#5Zh%UWuxg@6dcI z>%9>#mq|$aA8jT^p|EROsw#Th`Ph9MO}z??m|A2?pFjG@eEZLN;!BZJ0&C{EC<1j? z;5wTVz6l@fBbZ~mv}q{?K#|v+j=uNj~T)QGATiYg2sqW zN#Q?tvN`m%Us`EZm0hmNM*l)|DzBgVHh>tvk0XlIGr`g^AZnPxTp9vKibjeZ(W-Dn z7b8*?3lpHT{AeW&W3O<1&ZF9#+{6fm{OZ1)z+O{;mLNX~p>q-VY6+P&GOliTY!&~~ zNps!!CYtj$G%`?35@{-I*J>bughg$S{w4nP>8ciu&%Q$AI8y><-K&UDL*L6}yXMnw zH!D>V9D*}PfWWkmf-n14^7kNL*qFTQ6nehtjJ_fadgX<^s{h3FR!a%z2(ZsAYzo<- z)8Ju=on>-&zUrbpX&b(vlVTudwV z4er0nf1xE4S=(tVY)tc$P$;&+Sj8)AtkVIbrro?35Hc*CTR=eYwcTnIij9h1cqvb4>rM^K*tCw>~1dJl`9mz zVZ;Xaln6mipH|)jd4p+=W%7Ohu8H1ZK3+{Y1h{)o@(nF$ipfSW;kwe2hlD zrBEgDYe?W#wDX1gpWVWvb3N)dXMr#)eUx z2s*S}rl9hT*q^1=D0tD8^Dj@c94QhgpV1pLdFB^(-B3kcU8(zopkztK&?y2%EE9u-5PpurxsY zepZW_)7#}t_S>c-f^A`z(uY!^y{wjE74tjdOnr z-__V#v~dqG3|lt8xx0?xy5`x-zsm9`v%IjphH)_&UP>5-aK7?&yBktd<0QZ1idNro z870j3m-df8C8A)x@Yp3CGcnS{slEz8kJ;`*zy6~Xu~w&N@wXH9ZV#U*0;~W%gw*W zblw|Sf`(Bke9#W6WPJ~+dlr6S8^c5RNrGHPM5bXGoDMV3DI^5OGR@g=vogwyGxL|D zND^!PES0V?(H<@599q#)FK`)ETr2FjH7G*Rr4d0pH9S-i%qZH7S*{7FLgzj-B%DSY z4?CP8@etbWOqZ{?I03I?WRAt2PB95%-;M~6^Aw>l%^Eoltz>y~y)g3=CV4|5pIc1_ z(o5wwlKQ-U*NJTzO`OCfMsly684xIf?(1u{k6eUij*UswOf%u68iEGuBtn5dgv6LiQnh_G3FLZk4Z-=7wYPe&wVo{Y4CZQrs0et+-B+nBL0m7R- zFs7W8abe~u62~{n35yOD0ae0zdH*p_Ao=Zn8Mr?>OXaY`AJ-b8pmnO&+Sdjw_<@7uwN!kNN;|=^UrVPj&!wP!dauc>I)RB$;JR;x z>F~~rGhw8eqmz;|(i;o22uC6y4;OwS^;upp$vG#r7LohSK`4RQwtzZ_WVd1X559P#iaw=0?fL1%DHSRt2}q z2nf@d+Tn*78DS{bJAG=hkW}x4BGIz{7G0ok?RlWDn<q3$EoP*bBj;bP<5o9XSU1y1T0nrU= z$n6p@MU9Gh@%c$jj(ig-3hhfDw>0wT9U6u33~N$6#{Ersz3~f0cuCrTnLtEL;4sTO zCa|4D^7R^_g9H;8&DwXp>lgYdopoO)6#*xx(Gf8Q*WqJLA+{tDLF1B4PSsofZsnXn z0h&~?FkkMHPO$86U4Kq0y4EM5APNHdSrQ$pEFy7QCC)!ZtDhbB5M?@L*OcMA9%rif zY3$LY1KasCDC0~-wn8J7-lsnL5VjiN9swBqvNkv8HtA{c_p3b9qV}qA30|z>=ij@b zsCNuWg*%IT^~!$H?&D*H z!zNh$TGQ)`y^|&v!WCSf7>-QsqV6oxkJ97JR`C_UWV)oj-AOHdSfbLMy*w>ciZjs4 zQKRs(#6?1&0<~k^_{{O)X$;HV#71dG*oN?p&x`dlZX1PeSN1f+HmKdQedw1uW6qTM znU~e7--uxLiiNm!>LKt*zw7KSDUlbpJjXJDGML5QAr%nj3FAt+l)K7nBIqm_C^&R< z*O$N_s3OOIBSeiz9ChSFI28tTbNWzhC>BbeT<84Vo}}oZd_z^d1&SH45l}dg>e@?s zJf$?RK%6Ihy2dg6Wv>qpX^(!o7=5*ILnI}pPJcH@tBwp;qaWl(r{ln^If43=U^szj zz->&tS2_KMGs$U8?CvFUwcr~;-j9^~ihP(OpnlwKTmpiI`~~xVv9;cT*Jpg>dY4`V z@$MnPgrsDu!q4|avgS)7x}YZwYRBWAWcRb$w}-s9O3~{IyWcjzM(ISzgM4fh!>n% zf|5i?K$z2#^8LIe9sN-fguxvpD4pU7a9=F? z2ng6^hD4Ur$U(`37y(dDluIK{Ia6X~brOqCa!_A@Y}O4;naPl(o>hrUXjs-{R=NWQ zShmas^QZu>p$fb>oe3<}4*M`sKQfauSExu>oeU-hs4|2=VN~rUGZSqyFa3Q&O<( zNrr!wIZM;-DdHM7ejEyJ2hs+P#xUbk0qSldtC(<-DyRm_+~=mc6~H)UvDGNl!2D_i zP&TuH#PU`gc7L(8VIC~|DuVM&aQI&crM%|tKlA+;c#MVvVDP$L<~um z4z-Ebtc1V<5klCmUMJJi!{eQMv&S{Hx_g)&-YC@)n!@8v+NTT>`UZTPm3AUa;w+qh-#&kyioiv&%TAZy9&!boM%Oj0m zf$rT~aE)v$&5^~s^NYH*Lfq@GtxYteXK zd3|yFs_P_djxV8kwy)sQwjmweN#FQK0U~YN>s$@{p>I`qqRwGIa$+Jve&=&BfC>2G zwi5=S!JG){oIsFKTJr8=^RKRa_!0EZ4yFroY!ZRkCjnnMgQ#%_b0wr^sJT)g>cw-? zw&Hj91^2}~QSqs_;)h-xw7SMz`S6T(T2gWyF`}5D*O^06)Z+nC+#*_j94N-?wek{D zGWj^<3uoj5w9;T#xS}6MRgoDSV8u+wj#m|{%?C9DnVT9eQc_>*@d@;~4^WH;1=1DB z`VcVT7JRTjRYgnQ{Hno%8*G~4>@Ajvo$_8A^pF-BOEblGt}2q2|8@49#&co|N~_>= zMHjbhf0-=N8Xk@o{G}7lz&Wk~gob0+ODa`V!_{UrOVlj%#r6DXf>q6ZoLU6Rj(MSU z8~@bAXV_%OfRm~W~lYCWlA)MKTSBsZ;44mnL%HhM1Nziwp^ zuJnMYqVRVzt7hvi-l1U;XPfPU@NhKhzuTP#!C^wS6CV&uaYC^F7SZBzTcYuf?^A9& z>4Rutj4`rBg70XfP{f0Ge|H;kX1M89aI}%cu%MTR2Z~6dbr|9yU1&9NKnQm?7K=!O zEDAjn0@NCfUP&qrL`oIKVgGTerq#)qCk=D1Gok zy4w{@c_tu|Wm!5l{;DP!U$w$&cfRw&xnGyNBj%Gn?*j~qY=PVF%-jS^u+dV$+)^xf z8^FRu9_UKlCw04_EiUi_^DHLyBakRr)_*dopL5ep(?{|#@_*gJ+(6{xth?J)R&_-wb&kG0d*%XGgL*? zWJQUJBA1_0;f)z{m~_>eD! z)jnGcyBaY)K)=g!E(vEWSik) zz>x%ll`wYBLrwowtMQ)je6{MPMf&x0S;!<^f<1-|fpKJwXDl?i0lSHTo$iZqb^Q-* z7v*aR6W1s8ia%|q<20uonW7lu11IUbX=zcfXweq}iRFrespS8LRTDh&b|>m#Vq)gz zbVBiH`I?uZ26rh#EI$O8KeIAq4`tQ7H;NlFLK%3~_L@F%ZCxm~$@TlqR}TaxmQVwO zF=GztLeuv>xnMZ*W#S9YfIRFxxHEXJ1y*d{nVw(K&SAe+yD*W=pqnlt0NfYBqlu?? z#$Vi8mp9t+DbcQAO|#R+BQ+W8z84wWH;ioQg1%H`~gA@Z2K z4Ga`KHBoy}(I=ALgRKZ6*>*+YlY9a1C7q~bHDI{qn*YT0r|VnXdDVvv3Lge^ExdqG zTC8BA=){V&3S7glrd_62v>zQQJCUwVg|LvuUKl5=lQbf&(o`y#vXi~EQiWoxy&~PN z`N`fRCy}<|Cz_=t9PW|_Zt|>2PG;J*dKE#o5T44|nmNW`f-S4P(JE?yf|tG}3+{j= zseYB?U-RkD%K6QaT9bhZ3rptC2dxheW;)J-MwoMws6m+6+5pvtaBbu-_z+eiy-lS{ z5x0f%^+Dy%S-(Qnv!$wkA+ioVB=+8OGzR0ks#XmrkCOReQ3o?Va~kCpyE*8*Es)3dVNH8K>>bERlDesu1%W* zd^UK=h=q3351EN3r17!HoXtH zmODmYpcMJelRL8X(X_6pV5j*7QmJbNF;Nv~npCp#aYV6Hablp9RF7HEJ@rSUtN?li z-d;zfv<2|jx4{g3@Z15mwiab z#HdcbWg&Vn2@NU4F;-F4t=L9xo-kV*tS-xyX_jYS0&$8V!P_ohVabg}PrAKA_PU0& zJq{%k=I};H47$l{X{|&yn{|CWEB$W6(aVqxGQp}}$s3|3e>%_k3*{~zG7fxsMi3YY z$2+~Tgtm}g8oXYmW#WhVcM9}v2}NYr43XrWVhC<0+k&iD2{msbrj|J_XQa_DP+EG*c@L7Aq`ZZEI5n3x=X}UB2CflO);w)eqH+ZIp)10{ag7H-SF6_S7Kt z3hV$Z0_^IsF4b(+g;d@yFsEMZO~S~88*tP{`LayA z6xT325$bo(QIw--z&r6(yu$drAQgU(+l1rR1&E+GxfU&`@isg5I;8LYC~oDrx%y?8 zV}*G$=!)XXuxpB?c{OVB9gT|+<1*!ol2`PU?j2@G>h_Bf30Nj)4rs|D0wxxB-h!_(oE3Ft9xsj0-}hJo`04PrXfxUO z@-0@Mx<`Nx9DQO&?N+o$Tv`!Gn(_bZ=7Xt@~4;~s0}-| zLKW|=^ZiPz*%>ApC$m!zK7AHbRhjV@%fdZMzQdo@2>y^a0bc$zPbxO4)n?DBYg&z? z>lz3>to;Hbhsrt*xeb(id-ZpHk^MBr`oP5i)u>fdH?B_T$k^LFCf#&kmNTro2qn}b zHWlsqnY)~W-W_Edjku$khv=0Reu_m963s&FkcWSo8gu%pXMB4dkz?Ka_%UQ>Cw5cN zQZ0Jl*D$^9LTnVCgJMM|`tL266K&nUIqPhf5dyiG>&nPU zy$OHFlq?!Vcf=C~(8(F48L-lbn2gmlP^dgP;#dk4RAh`hq!68gyCj;^{*Nv~w`jk* zM`souQ_FdVqm)=wcwwGnal|28rulgX#=>E4RvYDtDOTXx9Bqt2lkV`6^5HX^u_Gaf-PA@(1Jo~wu!WWSt<>I!}kA@FZ$LLzTBk3i0Wp)6m;o;+bf z5X2?FX_NUQlj={?ea)xyyA~NDXCbqyrX7jE?!hzpqpa*RMt99OJ((?IoG*YUQ>td^ z0yJ36QKE$LK24uwV3|-5=y%$7;e%jXd*-%^Y}ij!fbJ!KbsM61P!&8WdS?l|ZtifC z^U~2|)XZ^gKOH>I1RXY#7__Q9q0?Cd1< zpjWc`){>ndsyd#w-19g3;vlzYlhhap?Xx%M(W?8RcJ9*$i1|`Rw&@@UDKosz#VOOi1rQ2e8 z{|_P=LhCg7iCJ?y>NSh#K^0It5km{GMqRCsQ@#~b50Qsa4A^*yeV=a>A{KH7OBSAo z-t!MXQxz}r6_S4>0*Q>5XlM%$Z-S7ZtxdKsy&62w~ zsSi0arQ;vF^{YSs0;mmppnv4qAEFEN(v;QJO+-aSku)oqnHA1Ai_=M0P%+df|DkL9 zpQk}l;{Y`s)T|a8E%2Iz;5)R!?xVX*fRS_Lk|YGEBonhM(b^)5=mflLx&$xL+VGJy z9dzx(%d~O)22>uVboUXu=Hw{rqskj01gYX z#3Zn>@D%9S+5WeFCeLoAE7YLniy0nqnpCwtMRVMUlC?we4bSm z&Sku)TrC6J2A>@0<8q@}!+cbGYFHXa`#Y>6mNy_k$f^O@YVAGT-0H_;0F3E=Y3aFo z0^l^W*)X;wYf=6m;N7wf4`6f`^*pth?{4u!d!pnA5g2s+x+ZLDYO~g(f<7- zhXqMiN}uef=y#*P5e#?OjxFDw? z-B+Pu>o82n296^1_;i3>wfyDdA>^pZavmz9sTIKJ>fk>0!=aU#x*Go9K*4#8E*uHr z&Y#1{$oDMe8)b7QfO6b7?{Iay=VHxq?c}$PSmI^VFAKO8lcpI=Vv`ivDgR%&08*l2aZA^(>y zsPVpbtYo5#YP;zmKshUU-gvnFsmxowJFRaK37C~VMyq!K3g?EoOD|}x&T9PM3vW?j zUdI|_$yx@qfK#vaSq(62S8ZSjS-P#f44TYvQuhGwRqYJR5W)nwWO@q!BfkE%!|9-P z{=D(M);=gq?GT}k01F)$^|3ZoNmpsN`K@B+(K8Ef;_+GJ(e?&^lcR8QF^&2f^AFfs zCyL7e#ShMcrWw;)N|ynoZVDM!CyrFOHT|kN18|YX#Wkgsg&x}nX30^+SF!xtl%)2a zipc~<(TD!<|@VL=)aRN zh@RIx8iaKZpBlNapj*6qBUy&4C}n1fJ+*C zXf@EqG}9YTyqHfe@`c}+vwAg*InZgQ>I8Y!X(|G;xYgMS3z_qK1UbzZYXIsSXI4Vu zf1kYp)rFmgt@Tv)oe^4tEmVMrmc~>LZy+-wf}Tbr$Fw`dTOC>_aKHf>YgovT@%`s! zCVl@suOl)FD(4*^@0(td5$@C*H?b@c++jFJ$R4>-}j48D7F^Y+4Xd)$jwb{2_jl?j(1Aj*|@F>v6yS zXKL=ehk6l71&%%r@nV`r=&m3-JwN-kL@;O;QhC2HmzSTR>b%zZF*5@5r3u5Ai!@pq zdzcwiJ)-;HMIm_xvwCI~Q5KjpBg3^NDYbaZ9L*_bpufZ6JJ{{|2&hhSD%JIF_KZOJ zHZ+D)#}s2J`_DHZS@70aGRtur^uj6G+^<_Lf6D+HChn+_h>{`|UW6cB_9oPl;orw| zzl8ki8xboORn7W_Ln>9}S_Y5W+v^b1t}PVC!Y)(|lu7Z5jO1I+|MMvWm;VhV1_`yO z@BgzD{qK(X|F7Nf|6AS`_2m`-&FpSYR(S!vwPP$6`Z?fNo&)sE*nYTnS-?&Bep~FX z6=2%4g3A537>T%2IP@OT*~Aama^9+QRP71m$MqN!j|hvPhxhyY=#jx|_s#8SVfI;` zSXfvHG_id?^<2M{?F<1rtlmDDYkc@%^4!Yx4BY`8L=;E($}({=SHnWb{HqQC$H|77 z@e-k{+O%g5iPUzbUsnAsumrdVUX(3hdYdX#Om%b^muU0>)O;0#tSuK~t4mktCQD`7 zwR!^bJz$@7Kbv=Zs8Wh2r%8qf(IYuEs42@+Q`(LS_n-Uun;zy@uP*CeX^8#&x^P$!Y04Z4{ofB}4G=FRbUbS-<>rfp@*RgGDSHp9X^ zKNjBeiP$q(q)#f^*8F#xsA;!{?=Zs(ckz0YV8=#|wf;N$ZhgqTLCO0He*iN)$$)Kt z9?2H5d-f0k{dD2pGOZI66ElF~${0}R)dIl~NGz{6P{P$P@j(%GeA~eTd{i#`^N>o` znqC^<4Z@9>W!ua?x2oxuA3j$Dd`phf);RC?FLU2OP08e(J&bbOwLhKYtxm{#8UYz> zTn({DSn)WB8W+kL;_CSaIy%U6q?C9aQiHE|>`o{7&^;PnM(UJ$?JJa$pGMF#BKz)9 z>1ix=tp!ijjftr8>`(9rbBJN#mD&rBM)57oMorDKEzAqkS*Sub(kfXwH)E+pc?hKZ z-yD8ErB8v(1fhn@McUG}-ZRN}hIFOs)0Ut}%nhZP)aQ#;f9{H2v5D`xV>3Q|8i0L? z&*bV$5c4M{YXVG}_N(}3@XGA{&*)z>K@sf5W7PE-Vo4B`ti-bL}3==tn^7 z(2<;+{9lWjgCEsF3&2yaLQ>!)oYp!cc}=^c9Y-EGttXf?yM@tIU{8R$uR|oSMIB!_ z+Wz4QUAJlag|2ry+|~J@*x>?uPAxj2PPYNEduB`hX=HOe&#JRBXl>kp%O=oF&e~1791#oOxGht}NYl0r|$QWhwkZux*VrS9sVy6I? z1f>4de~SR4L3%$SQ*`!?1OKqKm}g%UWM;Yl$*FBV3L-kQ2F9@E;;feVX|B5lhLmp& zcyy4Li@PO%T6X(7DeNDPU)~avob4BzoOMgdGP}H^ zG~X3z)SYpFS?fx=`h~*f>J4$)d~70fT2b0IF=?Eg=L`w*4`>-Qh8yONMQdhWij;en zmzP|;hR8v;RUbDU6oW2b!Ml{nZxMn%C z8J=?#PenZ3y^O8OPhI*$06H{TR1};wR;;k7myo)K0e;pW%Cza*F zZeBoNTBeNgbE)4V8$y**^J)0O8cv&&l5RkQ86f_0nTl-g?bC$rp={jgN!0BD!nA!x zqut0!MveV*Q*C+Jwi&~1B1?KUbtsBitgFfXTzzSm2`A&5J6~nvLshSepFdx>Jv(;G zmHwob_&o^LrmL4ienLcd<=N@2-V}7DmtbS%!|q z>JuJEoYt(H9sYjQDdQT9;(N?M%nCl~eOc(-K=1c3Xo3o|JjI`?*SZevmiL2?%K5YXZxVTEjNKqjDc7r)r^;{i~hP-$2EYrUkZw1*rt?bjx$eP9S{G z8cr`2648X?BG7LNJ#oYc&ID$-9mV;uWRQxORj3S8FjJYxl!3RMu2Eo;7w;)>afM{g z(-Kfo9H%q_ZqJ!{hqlAD!|!NuQ(8g^s#=>y5|WMa1W?RGceKwh6yu%+(8FVK5*Y9T z?05-`&!Lt9_>LZ50OR%IJ87RpZ;uUp-&iW_$l4*9)~rkBw6%mL%xoGd-2wA)(T^3w z-2ZN=U4Zt?4puxk8Wi1NVIUBXg#_YnQj4gBMvYAC>16{PD4mz02r~b3myuS+DpgI55)T~+O; zMdzPg_ZN`0tXQ|6;$_0X=l@Y=SzewAO(naJ`6S|*PS5yofD!9#TSrxNgb!>%e*0uEymK4>P!9 z&PZv-+lgiA@+PU&j#gfU%qFthP%j7v|W667;Y4-Q+oFN2Dxos*|?no6+SCs8(jNVkbu7HjL^Pv%pu+^f=Sy(JUo$bFti zN~sm;ko!$i#gIJG9zt}qwcP>LFKJLsEQ(G+d6idp`fWa>1*3T>MAt3!rRF2#N8hYV zAJ4K@vR#C^O(jV9!5vf-kxt9nHH}Z}eihG{4p?O6QvD51a4=WKUL|Ae zJx9dHKVqcK4fjWBJVVxPe*P-W!Os0HPK+KYWnKxQPv(Q~T@7B4TY^CR0Yl(OHZ{^$ zdF0bkIz$|C#wS5>0l5KMfj0sC5^`x@IkWtRSM@3aH_5a7Iz#DGv^v}(UJuyKoX3|k1*;CgnONWac~|S0XQTF(AOLz?*JLQzFgY=bGA#R?$=^eJJvm{fpF_J z{#ddrO?F5!6c-bzURTmtHs<#oV6dRnUMy7v)Z`yNHxFq}% zEHYKSRy@`Kx6H}?I`#waqN_UJ&FN-us!YcdkbrBFpbb{*hub8F2>YE|bqf@*Y`+g9 zN^-XA==ZHb|AGpaQ(0gp*ope!5a9+~Q8e{+-b08o6AAtP7#iy5W3&O+1N*9XOSCFZ z!d{2xxFn6S>=sG5{YZy!X5r^&KN6ur%eUv=_M)BTcdV30S*hEMK4ykW_d^(l&LXglmCZ40bfPelyf3zL`BC~z5PSb{nX@XM zRS`Pe*qeA3@SdeMMrk=te$t!;T*n7rSM@@CI#Yo5w`Ew~hixp2Ud26nNB=WVFl$2z zZpJw5Vt!SEVp41q@z&8Yjy+VqsIdzbc`S`L=wbx8=;)2bKS=z^FJIL{;A1~2NGxCc zEM`KrMs)f0DsjKoOCo|d-9~-;0rkaMbOX3*jKNtrFYzx%>l4iaE@i)x?==lZ-S6hA z)!BD?o@{?GaJQ63l3kgkgu%?-5gwV8hyKzzoXsF9;rvCQ;~8ZBj&=^cqswX35AINS zgv$WKX%G;->d#@d*^b0XGR&VZitS_hc!iDnB}{jwHYD>WR&H<}ve>a%bqz@MgS;ej zY-g&BE9_S0gsK zM`+)O&Cg8Js+(=qXkKMIBB`fDR~=d;isCzJUG}py3x6Dc=Pt7J2y9lCGh_d_57O{m zMkF{Eo9X}BvJ}O)JhG-(`I)mbw_9sX`Tn={vd>^tn624qR|>kvu%gMDR%z=wC4r$e zJ&VwuHOtaxhwYcT=WTzrMt@Cax#_MIkCfj%fy*p6ziYS;x@k1G4{O}tW~AJlx-eeB z_NPC>ZgjhpSVZouS!TE1^T`@3 zx{=F`Wg<*aFKRY!j#)K6#XGNtrmGKW@4Fq^%M2hJ8+>L~RJr|)vo0s3C=w#bm~EWS zw@V0C_Y3l-;nsEriqL{#j46}!WXoajoq9-*FE?8js*34+o$+ZSfEoA?klyuef{ihv{ zs&g7tCwg+?KM5(yaJylM$OO~{s4pq~TQ*<8qn*XVkp#=|BA{NyA5#EoNJ_6?ze20b zgR4vh+Qqr8-2xrupW;dw2RGv8tHFp)OqK*@kJ>%b(^PHpLaJ=na7fo^UziQ` zz^)?@mEoV|4aAf94VJ|RnA@Xo{UF}m(RJ{5nAKf09jhIis8Egvjam2N&rrZ4p0!Ce zFM5Blj!` z_w*3A=MTXL#veI#Bf{{n2(RVn*4~;4Q<5|iuC9OUe07uMS?IyP2XBm1{mq3boW1oX z&)aGB_dB8+^y;|%#HG5~CkmLTE`K)nsU7|yftRG{Rt8%rhF9=R|J!J8+GBaj>}?c? z=yE{aiih;4>>sn1QO(bXE#FW<2i9WVzoQ_+f7akNJqT>I%vW*rgsem8v8rEMFL}+G zJR&3CV>)VBR8zE+dxqy{@({Yv$|`()VxniLXv)IJT%3%I+;v>;)I1ij`Azgv)zL7d zcP3A<>6RiGxrE;4r~3BUAlgx6Z;0h&CY`9)WLa}5z5``vj0}GeI%iy)AJF!RfxQ(4 z5u6DHFY5`@NHV&d(EHu@y>sUuE5z?HF6{I1sn2O4rkF(gIMlF_(3((MoSNEQs~J((>19i5_913_N_@vgGk&*HZ5WSv%?zkWB38H>Yt|!=} z24&AOk3GioCMr8=`1>4E+sg2(((C2GG86BA(GHf4Kso5KE@Gy7%%_2aPp}j;>G~D$ zc8>tKDf@psSZ~%t)G3=LLc5g!Q7M_O{x(WHlWcv9HHh5NAHdXN`+gYe_i<2m@WKo~ z!t_fz^T&wToLsTSLR8-*kG(8*p$W$RmdbEo5}l#s?J9hWchA;4f=|l1Xty=p|D1D{ z6p%8^Udu4QnL0K{S8G(UTvkbsOZWFLm zTcTQ3`j8v_ew+n!>kS%h$S)?4tdvXAG!@ zm^`3T_de^h3K=oUth)-ng~H>liN&L-HR+Z=|7U){TPSFJvZ~H@xu#zS)0`oiLfaSw zJ&Zx)nQj`NGsDw5z4~6oBa#$98Gnk^I|R{y`Q|+;*7Je+kfdNApA?15_s)*d&Nk9P zjJp)AyCbVnr|+wr&}jA9f`0i{A8BT&u1g}(d138NhE4L`+3@fiEJA1bhpTnrp3X*u zb(yj?NqJm7CzeY7IyS##i^H^crL&jULUdmBpacGw=Yi1`42<6 zP?Mzz_o)AlopGcXpMIm;uAb!FCL=8R`MUIR3!YKwKITCQ>2XakN^#3Ti^0IQFYm6! zK#%xfeiuZq#MzvSJAM}6_mTA_#l`oa}ib>y#@OCaXZ{P>8Z;QjEOQ?-ea);q9nXv=n-8u)i}i4sOb}(tZGYeWx(~k=R-|&E9IN zu(|(ZnMqYydwQ=))t9?LMWr%ZlPv8c=b{SPWg7ay)VvB2)ak^scY)cGor)-K%T~*m z$4n?pOE!I_5rq>)tnONkrA3LX#r5$P9jG(=_J`s2Oi?H#jR@axpY~4af)xBgjnB(# zZT=W2q^*)TWhcRC!=?arfBSZK)b%!tJ2#sK;RC_5=#MW;#*~WH=|`c%3Tv*+dT#cI z?6LFV5k{paW8XorfwbjWjDT(J=!Dm^lV(GyGB=hOti3i(*+D*pdA^=(>mNeTVy-jP z#0+k=<%p#KcO@B~-|3OwzX12u)IQnJBWF8ARxj&p(%Z&#_pB1V9kvo_gz!Bs1 z3tjPPKTP>lFutzI7ydch=ysdnbsvX0i)WR%zMnpeImTeGM%{zpDqKtt%&@W^)&754#Jk>|bVr43I38aer6OnBGcC;+W#FxsQ)A1Mj064l?O%?K9DIBuz zYOssqZNqZKlT7-C099*y#V=Gh$AgkZTArmWYG>x{3i!1glr6ry0N*J}XAW*nQnaGu zvi-5@Bw`CL#jikj;sYyTm1jFws14V0O1O=>D3HAAkb5{EBCQyJ?QTpGWg<3V-c;iT zqZ{38`~3}gjdv)hD5>ZzSR`XMuOM^oyf-nXbEI0HV+08mbx!FkM1b@_FcJOh_s3xk zOn$Kz1IfG7^rLpp(QQYm>oX&f-a0}pVrReBsrB8HyutNylp8y4tghh9Kr{D?*U(eK8AcLSM<)=8Z= zltF)SRFXOyS*N@?6*>G3Hq5-8_b88=iCpeNJHN2no+gLsoL zCmdIl#JJT`u(0uAT3&T5^PIROajOi2#7)_LM-&E>XHWKx<-$=clvh6TpJQfdXILv? zkq#xHMpeH&^+qYB4U@(_1n-O@T1y4hOQ|^$#yUWrrQ%hpw08XR0>6Ko`-3B8{N-Q`w>P#507vLN%Ln zGq83<&*m&3KSTz0h}x)82&b=3R|LcXDpj>{;|$G;{3`lJtGTm2BDx@sQi$k zhpx#*k8m02b^xMr-*(SBOhY*MoiKn$+xcKx3Eopd6*%T;3-o8_>#R<)M3^3p%%y z@1=}q73Qm=5-zW_Vj0@uGGa^#yQuf~v!ZAYop=uwJzB}w*rf}a7ora`sMdVL#+)uh z1UFDseOUve*WCo*m)-4V=nI-&cIySyQ({06>|rr*)B7^1?j3B?O2cV5A#O$U3I0zh zcYwsETsHc>E@AcxzlMalffVG$J4M{EAMOv=_JM>JaPof0#uXlZovyte2x@EEy6gSc zf_+r%2_RA21s95{59o~-ecCQ{SX)*hoimj|fi7-u%DZFTSLqipIs|QGt-q%-&=9!3 zPDD|6t=hezEuo^}FdF&X62}4vDZ-kvDGQ2z8$}6tW8v+jjd_{XxH6bne0nF?F57@h0;k2<6A3{KXUR$w_2d)%`0nki>=Bm}hHIN@{+#+u$d2%V@vkh`(3vzv`#is8$c9hvI{-g=s-W})vcO+(`F*~Vo41z>olTc9dJvgo zxtwHG^&JrfVgfV>#>kf54+|aXC6z;`c5F0QfX$!R?*F3hEu-Svwzb`rK!5}d1PLxl zAh^3r2my*D1a}DT6oo?tcL?ro3GOaI3YXwkKyWSG3cZuH_C9BS=ew<)zxTGrAE+tR z7-Nn(M(=NbAKK|`mb_t3MZYq!>cDEGFqenOs=y!*2Ju<)p?==GCZ+lPjJUG}%%dcJ zd(qswf~0h&>UqjJBPtLSyJIAlSlibDOW|NS!$90a9W}`5jWTJTSb>KozD?KrIhrmm zX6qblXuc_iwMv%cO)&jY5UW1gordgORBcxjZ>->;-j!JE!Uo@*P5uiSit%f+)0p1S zt7FZFxQ|UV*Bh-NWj;-o&;tE%LSd-7cvs0UVJklR!wIam5sP=iM2=|rLd%5@A?QTd zd)k#Wt!-q5r7~ts*NTntLbQm|Pc4aL8F`CEkB$$Kt#5ct_3X+DwLp-f_4qw#smg+D ze${ai7>Rwb+a=P)(J@(77PseB2}>ZcQgKe*_8a+=Md~;fy3wGQgVFH?$OrqBizYPE z$2wQ6&}dEiGa=_ARc{YfYzPg19hW$kjk8QahnqKRGFokTM&PNHd(69QW1)n>p{h$= zAwDA!e{?66(6@&r*>c_S(49*>N2+IlH(i7|YLH!DMqBkOCU*2y7|CsGC94hOtC2w> zbxZWBtQJe@KF=f(X19gSx>ZMH9`$r0e>V$hr^T>n6RC|tv@M5&t%=0=-bbE;(%cHHx+oV%H)Lvc9rYC$L7x1QRcE?!q+f8+Zaw?rzn1WAsIB4$@$4h*6SvdW$I_3PI*VIK(H^B(j5$h+j`7LEW&3q-;7kX^H?*IKC;Rd$1$}2-tkA|Am-)WdO zS((x$LIoU{HDB>x<;G$Da&IgCeAq}W7Kw~!``47JEpSwj7mH;f$e}6?9 zzh2D$kS77A#;O0IvI5TNefj^NkAwfE$q{j{{l7FhCp+N}MrHFRgNe(vr9kbxb(TMo zLrO12p7FIbl2Q6ZY9TvaF^LoAiMFEwcsgr~tX6$=|CihJ`y&7rQyY<~4tV4(d7Olk zC4Tj7?{gSnF@?ck%al=1|8lCtZ6W2v1nTuzS&oTK}vtEFRA zp96~B2Y0A_TPb#S4ZzHgTfEO_tkN^vgD~6p5^&AiA?(YhPAma3jmvcrzW;TmAVvs_ zXdtaBP6L+0w^e@KukXxfML)GZ8@)BHy zzVerw2!p;pf=<0>fkcEaUVdNa`sUl6I{w^jzdDu2GJe5jH5}NMH_b-LQknzcM$1e2 z~pJikatTrRP6H zYG$*MKfN~1Q;;Jl%mQG|f23Em&Opwu?j>|-IG?KOE)|hGWOY7N(6IFEQCDYwPif8C zY2Qx@9u?K2-*Kwdm(;sX2#j5~t2CnBQTj8jN24n~hDK(4u85=!&;TGk8Z9g;LOdX$ z07opyRGD7eA@OMHkBBvpwRH(o#^C&UFJ0u!1JfABB@N1*ChqFWTWVNpyuFJdR4b5H z6vcI0jcAaTVLlZ6tYbNJ&XA-q2N>EJ0rpcW^#!+FyG!(qLsIAo5&NeEyda2&Z(CKV zsKtJS?RO9l@c!XqyGe0(M??r&7iCJhrD?#54>MoHMcy%O3ENum=(Q5;CrPnp>ztvp zHPo#-x@d({x2oJwtwV z*LA+~LZ<)egK$<5)i|x>U!Nz62QHKXENadRJddqSF+%D{yzkw#-si8*6tCqpa zapzuicL=mlReqo`aqKC%Ou`itj*lpXd2SJ583&o%VCU?7A0=5kzJd>)( z!IG1G+rJ{p+_rU@7W8F9FA!Aw)=vOA(2%LE<{9zqu9fbW;Yy8ZD%%>pHmZG$71CVS zvz{_d1a1!Sx==dnB~AtEoGw=OMFARTEyin!Hk(jSW&4{AU%LWe${h7(*tL=wC^azF zqR38`IzmPz({sPg^_xtjTc4>g)W#2jrSQy|1%`A{*9o9_iR#}!dbnn-%;yCMQAF8U;fs3>aS;IS@^2wu$p#Kv z^P$g!Ulk<&$EV(b2ft=O%f#bseYtdhXDR_+K1Vv-0eZp4)3szEi504~9LMYD@$i1r zxhiYgZ-lIHBSCXumIy76BiMo$Q4{~NAA$CK6=06h=&A0L=DLwoy7<8LwaM57%rc#f z|H72%{{`R+^@vNmj%Y=ac@F!KnJO{5EWpJ z>a17V=?e6oS7Ik7ghMN9vZs6utK_m8hsOSu5}HU(agAJUJm?OtHCKG^gE_GF%hl9VhYyLijoWXg zSr-6iN@?o(!BSgk>u0_Ux1G0Y8;LzpoV}(IRGeRXwb{mcAKH1~K~I*zH-ya!`^fo~ zscM$1_-bLZ*lhWA+GR}ejvAHYivH|yk9u)6GdzWMsv+gIsX|4vt!R1lBp;-0+UqQx z;H~`h!f>H3bRr~Pb96;Sc{}=YU8{)Vq$aMoWk`5h(yq`0h`F!XE*O)A13H7ZZ+e|W9hhe8krGNCNHXjoM?qAVC&+zIC@5*}7l zr_?P8bsB0EHWius1~M4If9|Smg!>p9hJpP3P(hi7{e3%xmfH7Q$Tcf>QK8+@504eJ zqG!iFCJNXqO`5;wanP7(crx0IgMsZ}r8UmevBD~Ol(C+5WjXWje33JITA-?adbw%$ zRCni5TKOm28E%yIc1w;SDxzMVj09A6l0gwT(;jXGW&rbxC zwJ86<^NW^TyG42yM(FhHM)n%LK8RPdN$I^^G@>cGMKbMPMY@+*)n&F(o$}$~K4+5m z_0oUP!B+0PQ@w==O(8Qei#?X0sGbSlswboO+DqOELlONNs%LP7sxUjrNKJ>lUN;kq zMb->J4nI`(T63dJgQC@8ag#6~09<&d5s{1fN9gP%O*@4}R=`B*jDpXLN`&SDy%XqJ zI|b-iVA^qD8N4ni+e6`;N_K;kySas117&z%+GoDbf^zVLb_Mz0+U9-YFPBmI#sJ!M zPrA#>Q+ocjWG6?G=f)50B0fAVd)OBPSp{hY!Hq;C?Zs4JT>&bWa-0Q{?{HDn05x4# zSn!uw5;3plrp*Vb{aBhe-SoTIL-xO9Q3ZjB4&s5GRXP;&M$thM&sXvo{D6KXJ8D`E zAWJ3baP7kVaGOsN^N(XVzK;w`w{uAlD4>2YZ%1gNIDoc5nH;e7%$@WdAs zpS&H#|N7N9-g#r9P3(Z!@Y=?xCj!#(WZg1Gk=Gu~)q2!TR$4qp`MdPvK}vS1 zDW>d;6+aST$E}a_t<>+L-eIJFV$wQ~q3lXp!aFuEXr}hN3@LvAJvSNQwFF_B??LAu z44s-Ah>V{_`4fZ0b(Pi5m!QxDoQY|mvusL{$AG&4Qc*`1@151^$%B4Dcdk0ONf08U zX7S;(WE_10m}}kA6M=6?0x|R2kp}wI0pwF4`)$| z0u2kWm;mXcLQ+mDu!m~h=Q19bLavHF?8gbXo?|`bLc|2Rbyi_Sjkfuj%Ne#1IT2YA zDrwsi;%eLUy*;Vrt0Cx7xAN8{+KtAK9+L=@{!%>)ZYoVEZfb#D<2s~mX>TCpLH7d? zhv#!U46G1}`Qe_sfkvH+e2B;ejXdZUOc~nSzkH$5N1CEhS9E8pGveMAtiBB<9CcL! zU31lUcTORar&9@E#e6sNPQr{Efg4Urpf{bg6KmEn={l4y=j~dpdI7u(lRPqn%>t`C zE5;_7YUAuuDu4gHr{H2*Wc{F_j{DTmPw4_t3T6`11^avgrzV|qpZO59Qk$xM;U4_9 z;UuFPryE=ee%*>;S-tgrmDb%O)w6vtNW7SiVcxIC>}Q;BbIL`YIATOkbMpSqXx%-{ zVxbf|(0F&E!8E@V|I98?|$$h4#5 zsy4T6d3Y*pM0D=6Hmdl1?!FY>s|wjvzs|oIWi-q#ka+_0C(>lNiKS{t4}9{Nf(R9V zG1ic$Q~VcZ$RNxQ^4n?NdK1mqO3SLk|7>S+VA1nJ#~F({c@L!Q;)N38m;8;;|uvzuwj9||u(d$WLFa$2798wLO-b#*+LndUJItnO0F{XPc$ z_RI8BmlV)HS)s`$M{)OaVv8=PWrqa1JKzvyV?=uW0j1^KT;6Po2Kgb?xdv?oWWHny z+bc2em`Rm0&s&zY?9BP{OlyzVJl8hz`dQZM5=7uz4kVI)uhSXiEPg-FEkOT-8u}iJ zWys)Dj!Pe}2}cJIbTnxUt9N|5wen0eRIfS#tdBg3mD)&K_#k`D^U@N4iUekm&#Lx@ajrXo* zJk3Qv3!R*Mer?87*)C8$9xE|C3j_#s8eK=@1P3vnjHMd!$2ST?c2besEQrMa%5 zjvK1Tkf!`idaawmZzRjoogMwFQG1*3h0mrxZCJa#&@KW5X^0NeRmGc3p48r#{t;!n zvFI0TiIr&)PGCX~=kMqeWsWDFIE2+CT2>>IvQqI0<$G3c9*DTc{s_Lj~Gt*9RZd z;VJZn_Q0m;ofK4L)unca8IXo&KAKljZFVqQ{|P^VFAHbOR^nZbAU!}R>3PspGBgJ5)Xg51p4 zZ#L73uq8aRSo1ntRg2_-4LmBlb%GIt%RY*W4jcuexjdGPJo#POQPZlgN8ek{LN8Hm6Km`*&_IsOZT{z zh=rA5LrA=DlN{}Cw4DXz8QL>SX>l~_MV@CQX3RAcpTWV3Sno+t-ReOTD;=0205hPT z?688vxFZ<~%D;AA_mQ-A3|-^Dk7i!1^5IDeMfp{6-EJeVY0} z1d9mBgj)-(hH<5yjnf2@uQ2HkBRoz<5wG4r&qi@hQAPTaIkW3%0eFlN^TCY}UKnh~zK#*c` zA+TW`?;6iZWP&XtZR({T<0$?=(-lUfzRcocOD^LQ0LOQ6|@yweDd*N)ivTW^`BZl z6-wjhKPjZ!!2dD!q?w^FN!dkNb#sp3b?YTH)2zO%DK;@-Qsw8*@%RiP52~0?}d8hlQs4UZHwht|};M$H&w>`OD z5c>~_#C9IuMuV4=pQ{t92T>(4P6DI4t?D&4o|R74D^meMUmF}2IO}sj{8$tV=!zDe z8q~kyEF)qKRoATH9!e_15bPqXpk;h#Ah$J6n&8|eTkKrU&?y+za8f=c1=s%`Zs#W+ z$iIbts{VvVnA63SJt8rPT85-TeT`iDU2%XwpadFGc+hKY0K|>UT!p8S=pM;FsH9Jd3P!nbcE)DEDH1!sU;0h<- zroqq;KDcNxLCpA_14X~W#NByJ3fu2W3^`!IvJAJee^i@1p>9 zwi+UMsJ-hnR5XR?PbhJ0iQm0nlQg`!;N9I&))9m>ZQ1`FP<7Zryp`{r%5+e**oP5L zr)Z^y;bYnL*9r|b>Kw<$;mi*)>ebJiXxCq8mrhzg%IExp?CpL4<7MN?t-Qno;liq3 zMn(CLS1LYLz8*p+I+&aenTB^9{$+RVbB8wK5@g_r@4CHdUb*RF|C6vxc*5cxG&-3x z-!PvLmlFSOMzFd*GpGhPl$)EIVbwWe^)mmlGZz{;7Ljle-3rS~&Cqy- zf&33m+U<{fv_dP80>vZ>MlJY+o#k)|YLt!(0Eo~iK-41t`Y|c1{aL&CEwFcYviYS; z-I+H%LNgQ1t=4MT&`HZ&knUDUz?8@|(sW@kx;akD@f=gQxc5@{q119p&K(t{I3IBF zOYyh6`9^l3Q5F-rX4HmBr{1TPXq6TIREmTdhc^UhfYJ_ z{}~i4-$?ip?0F^d=ER$yruXwZGE8JB6DRn4eiP9NndFBnTlF|v(wMS4kK;GDBrEIY z48`i1_9drF4L0(Uvmcxr_*X8!gOA?NylmlTWBKxB7J@*7)-iqlPcd7tCVIY zmwX~1l@ux|EJr4WkZ%2`E2pM?@7W}swkq>M>id)enYiGIp&w^|HMzeu^Ls5K#38#L z4wz}mgIgHRg9-FVdS$`!<886+4HB z6Mxi<88l6`G!%@FNb({-a_hrf{pYE}YT9lSl}SWw(sO=7(OfIN>I*1+4&$*FV2$Y~ znK1WL`+YSCN?J9yBIvdgCYBESz(w|ynJ0;gF`8KM2|`#B;9~TR0@8|Rq{R* zGvwDd6a(*Y3C2>_UwWD&9e)BB*ankfWD%2Vxw8hkQ);cDvD9EZOY zv5$hisrNHkI;s-gpMUU}?Rd!i{zdyNRGt~VBCI3iJE2llJM~|dbVP&V%)d0B z;f0rHAKMI3cFA_(tLm7vIs508Qh%o=l3oxOK#Pj9v{(E?3Ezbg>p5N@Qv|*EAn=+p zmT7Fd4wspKA`!_SOaR`g`2NgLa5^VV;_?u)bgkoemec~def=virNQxIEHFL3>c;2O zvuBoq`2>fqVefq>iNJ>VXkF3~!6Clb{&Acg+TrRfv^TV%&lyP;)H>g+ZOl+e@%ysv ztc+x~wdeCTeh?^1fQ3zaZRd!jRe<6kZ-;i;4?!p4kJ^)u2Qg8hL%$({C8gJ zXG+)S(Mm`&3p=S&xAjLC?^1ABLbJaJdxpODqEf4~$V|zw>y1}ET2r)HH;7oCNd^{x z8q*ZSry&EWgod7WEQ^&*$Y)iKCPoWx0(?|$ndq!d^|O`V-aEW2tO~!b${3-4wm&;L zI8LH1gxs`MJv!tW7OAs=bo>R>)p_jW)IFw~E_AtiQ)g&+v;#yNzCR@@d#el76McQM zo!PlBcqf6LKAEOtDq`lVzMVYm227+j#uliGN>=TE5;NhnIE^@-{C%#m(L8*0YkS+O z$Te(;!Pj*Qzvk$gI-E!g5OWzRY9ZCAMU1~xtF$ZE#I!E347%IG-W_lgA$@Bko(rlQ(9e*eTXPr!5f z7=Z((q~>B<98s+M3{-ch*227qLhEISS*k1!;krF0OZM?iARt#2*v743)h+|a)KLvK zSr)o5tRplhlo*vVrD%VgP#VrV*L%C}4u-6}v?_08r=0zFC4|1 z)4235r%fie?|Q!Pj9Y3&9vZsywjgx{Eef67?i+zh{k}mU#YU;TuvScduNvA^kj9O1 z`}36{#$o0$pSWzjLmGm54lZZP?995$!KkkoBIFW?1>|C$Tyt&EvQaLgc#E^T3KyRi(#LZ>(fXRstTBO4$Y@ zki0ewIryv@1AeBF&PyDmKfqiS#?&qBi$Q~fY5D6h#G~74yeAu;6k^w0@+G*pcAQ1 zNv_-s*93i3xI-3Q4?pYfD-8MLC1HBKHdK6Gm$6{TxcvfGcfL@}YjUWHf3=y~R>-*q zgq})pTDv*nyidWjYc)PH3xmKdMWOS82+u|W1v0<#J^PT|k5yw8yO(-SL6aUlVp~~qs7oB86)+hWSkZP-tnLdgl$@6GcAciSjBdMt@XIl zTvxDf8gARfkW3OLXp7=30Ib}h^Ome;32MPL46m@Ey-b>>GHZx<4zm>o}` zLR8S(RHHk@qvqDN-WK z{PLHU2bv((7Rg}wUypnl+77=xq#bqJ=kN_Ep2v-R`yL`5qCQ2!XFAH;ZV^k&0)SVB zwJ~vOP@8!o2?@0d=*loIUf|S!9BI6BVbXBcVp_1uu(Q3zqtf;na1x?{bFncCe&$)> z*!2L$noiZcP)QV8eZxrW33*+JOTKr=gD&J*Y%(LTOL$A9XZDHdetvs-c&18Kd2Af}?o66a5fEn@?=!7! zRdn@9EhP=Zl^MG-vlvw4(w+6|lCNiqse}(1Rhl^rz?s8s)t=8DEn=FmMXGiLA7@LQ-dP*_~U=y$-e=d zbZ`QQ8XQhEIn`|CKXKbZcAeG-Y;Y(x#w7NhQ=kw9C3$tcvl%7fyZMVZU!(7iUp|Ip`v{>SgS|BF`We|`*@0|Kq%XGT+~2kkVuTh*4o;baB64@gs1 zt*oPKjUEqZ95q^M9X<19sr~hM`Cka~YF6g{e;J%*`zKZ|cAtd=XW#mK)UKY%-naD_ zm0@lj{7iJPFdx$KkBOc2lfU&n(r6A9v`naYZv@j^isKNi^7XPW1gq{nLx+H}XTT^D z{9^>a#tDAuV;MPd_nmZNXLWzTXH9gSdH_D` zU&j;t$MHxncdbo%Rt&&3;#pi*{gLYR0RKe-F;VbQTVq?z(!E)5Cfg#>r)xSOckHO} zpH@T|G!AJ0A2SvDFH1h4zZ~AgV_gC)6>GqL@c-hEV(*3nrY`3|aHFA(%XAp);y=&S zBs*#A)EiK$8IZfE^hQC~OkmZ4djVbaFn<1io}ZU3KUnLWurSgx3?~e5#RnrK z6b8F4k5<#Zzn669cz!w9D(ZPvANF6T0E>$664HB%EluOc$v#N@7fg(dsVYY9s2A3# zFss89?dE@L=zzIWD-%d=g9a?0J+P2j_>&X@mga~7Pq(xI&LaSLT3u2**Kb&n*m8S5 zzt0!(_ptuwM%lj&ETpQN^YsBA$f-X-O?BNvvi;Ut&IaJJ3gF83KN|Fcbwp7D7y(wJGQ>4NSv}AH`436^7!ox)AK28?)GYH= z0af;Mi$K(n50?&#{97;b?^fA*|Ni5kBru)<8hkKtB!K1mtqZh={F|6spo5y0`2P*K z{<{JFP+`o>z(D6UAA5BT45!V?FKb-aK&j4uH-_KemwY@G2qX!rlekP93G-#cNS14X zg4hnkDxU`6j{DESm-pxUs5TMVpd09G4jR|TG;nGkZAohCgrH}%OqunJjKvrON3zZm zN1}LTI`)w1v&X7xPuh)Sj{ekTQZq4xFaU+T4L)#cQ|je-KdC;bsED#FV_MR7@^0VB z8nXFhM=d=meY>=@uyp?pq*C`PoR5HLdN4ywj9Ih#hf6XCE_D*8@rOii^UsO=6`sxZ z`|t(>05oaaOgjHYDII<(AN@)W_|ZJV8%PmxcUo0(-WW_W!j*aWV{~^TJ+c2`UXE1# zZFe`>P7xCu&a&SKx9)pVtw%7fVSYMtXShAgaV3~OK$g-qm%|k1)MHzQn~_`&J%V02 zGYtwMUsK^?5(`hcn4b2^LCc1(w|=6`-*MkASYe_gq3*JtZfot!ZLU=0Hx~=6ezOGe z>BFKmqR>~c>aecHzEHaJQmS0Ay(W)0 z*1lK9ujV5`;Wg)U`FvBeaLlCRi+4sESRKak2XTk@+0!e49@_ z@x=WbCsY^)SBx}P%`&S)r2VWSPF=V9c-|Ef>nH;(1$DCxlbO~vQWyX?ufEnuW^QB# ztu}A=oSR80T+!%FX0IpKQ9G_zc_JW~Kpa+O+%gLz*J5DTOaM)(%_On)Jk0ox(iVe= zlSS#4A+%;1*I?)4@kRC368X(YJ)>VJv0wQ>k<{g)49%bpdB-kJ;mGt%6>Tbsoq>Z( ziRkgYde>d2SJ&yj(saS)oTvPN^5jzU0<3In5XZt}HX0Yz$d8SFO@w&#&MT%ZKt}WC2rq(BC!Fm4B$E|EjpTFngi&4!i!n(SX^E zv$fdOYM(z194w0=)K+;E@XGuPEx&Aea^~5w_{Zbo1OLM-sQ@8H?id2cJ=pPZVAL;x z;dxQ=ju8ta0#~@?6K=wYR0)sP+K(bwatsR z4Az{R25#)30J?H)`#V<406U<@lS}Zh*C%hB6#91U-l4VJ)5^38VeWrWAQd3E{SyCV zgAP5=ZjMiK#{S2hpd#_Ta=J5|yP3jVw<63jZKyUYwHs8+W}%|DQmMzsD06yYb2;-i)nkh6 zLa}-PeN4h_%sAitRmLT#X;ltKbimn=wBNi~Qt-WVBg@b+@37H_y0?s*#&e+9UFGC% z{xUeI8`6a+5;Upl-0X+sXdtTzPJ-`OuLfLoREUnQw>d9`7&ny*Adl9$a|dKyDTX45 zRputqYb#Q17Iz(&m~CZ|*XER*dGm5^Gw*i3q-MlF$*@+TT5%X#ulwLGz?P)$tgUKQ zhcgRt5p^96p0~j;xDDTta?qkF8y3!6>?|e!W3EPZ6@@#U;{Lp2>$#q!e$!Z~aSQ6OXLwi18v zt-~5GP{Q3UZL(QSI||jGH*yvs5k2a<2w8*zH5rcLQR1^ocWq?>&N@(Sj*NR(3ST$W zMX#%=vOqr1iv^fRz5{OCF=yhr&{>PY@$V1eN)tGK8DdXp=@+>rW8Kh|oFG93DDLW0e9uYt*1}Sj5g4YR&r^K9{5U&CVVrRt1F7wT2 zHoxOVl;+X!9&^W9p)7@(Z<)LwR*QT&95@0M^CPg_HKs^au)dC-yM~&1ly6)y?ant? zBJ^W?Z<=rFXm0dDCmw~8={=57ksNGWH88f6QETY4<(iu5gUjhFkATdZ!`<*C!rlYi zme+nz__%$9 zW#P@KgRsGp{w%cE^Nm+J_jr-t`WgVM%}g+Zw>n(^_1F`4Q7kp!)Fmng7qLdEG-uG{ zE|4#iDprp0$Ovu@hmQAtF~&~fm|U&H8z*B|{yYJ{L>wGqch*&kFqGqFF+>rN?pUP&VE;ht5^ z6bj~K-JG+mwUMst2-Is<1RqkHHPqyc=8j?$b{k{l#5Hsr9qbhC7_B>%vbYoUGX@8} zzSv2iQ&95^)qUm2O_xfeC}rI#r%?2ij_Uh9@kAgfa$!4CPl23F8TA)Ne77(&)%<87 z_HOm9x@{+3dYwH6?lh3t^i?E<#=^CVz~-}gJuwcVaTi6PNcv1|t(wjTm)Gu{5ez&{81y#RDS0%foIXNfyysdoF~A3dmDEU?>dqWaMAQQ52c9?ZEmW zOX0>zHqH@+S7SKH52S_y-}TlpU8)P&ZW)TamZ>REqV>{=r*Za%rMYftB&5u4Y$s-tzV5k-GQax+BW}K&Q14N@oOe1nHx>@ z=v72nf2s5(Y+R?6GylqS~aK z50To`j)P|UPZR5j#cQ^C%pW>h3q^@+97E&@{G#@$7V#UZbCZGaN;3#N43gL!oP5ha z4VpwsO&-z8s(6YI(s?OR>-R?r=f0k9C}3%!_^Iw>rKWA-DkPESwFI3wY0xG*f+U;V zff6+G3e)z`YyH7Js*jisSFybdO$v9U#Eu_rdyNiN2;Clq{v>bqSSJhEB}>+!tFi2C z9PM)!zzy2GL_O1d@@RgY01487A#xX;z{1<>aIu|pa(dcc#S!7-SGADm^GVNW z#N08t0L0;YPjwXg#^VrFf)QXFxk4ENSF>++H@q`4SoWD)oO$fc>EmE}Hy$jHeU`^( zz+Jr&MvM18vV&g?QPab@^|Nj+AK~tcFCHeLcvpZ<*MjEW?siT1(W(}^d4F2)9VV$0 z>7N-Hk-BSV8$6~DP`MoMbu}7NDN=E_g*=_L0jb~W)6|ES8dl#Lw${ET`WiPgC@Qsr z?aCwPe|438xvlLMJj3)4Iv!}5#z3z=E~`nyk=v!MU z@%_#_8_~5~Z-Tv`tHmLiG^ zmq|8B&y$RcyJ76B(O5?cPq>So%8Nyqo4bzZgPT|Qqm}7rRecP%IoMz~U@vYsFZ=oi zM9ltXnP0l0=a(kd*9)JUU~3(aMzzog<0f6k>PZ7}qsk_3an1rTH` zmKMP1TO5;S=4`MSd7h;Qi4N6e_1av}X$#t2L&u!!IF6~6!xclTA&4yEQaex*nk|x` z8h6-vH9xnXoq#M8(06GIQJ&*+e)XHqEKX&&hb}_Csjajsbj@V!q*!+#TSK%P^Ds3N z^$K$L`=N{Rd<{Ym?&_}a=8q%4ZgWJwEx|0AOZ=g7Pz6HqF!$WrAkQ2B%Y?7+n3i?{ z)u!)+`&+CsmD^CDL?|R!Ttflcv^;$qot~p&u=E=D;1-NwS)z7;RKQg|Ur1fAX56%i zpkGM8z94`^II&aohr!Q%osy{E98{6dO*)W`*_vzV8oN&RMe&+E4v7>#e$V0O2oz)S zB_<{!Z)!SrQcB47)4|F|$<+GDEM_*Bp>vsU-_di{5?iOj%8wg6mDt|Q)b>$oIai12 za>S-wlT|Kq&(v*f>=KH+O%bunORL9b=JHCgHb^1STp0OgI4Py^PII#FbvwrXkOc9b zS5SM_@huH4=^w`+rf`;v&Yc?K7oEEG2~X*TpA&~;WeJ?M2{nB~rBAgi74op#_-nEl zU4jsV*GQrIQS|BSt>|-~721aJ>yamN9IToAz zMUGC-$x*H=tiOun7U+~U9NX70QuTY|iuOEF)nMz1@uC=?`&k%M4IwYkiZjJhUt5%| zk8|oNCZAw(8~h!!>r>@^kfvUW+Y&D`C_C&MW{mb_dwFyc%#xnC;STRE#u2K+x_MPPhZ8M zycgJvY1!z^eEvm?-Ikx7czzbNUQ1Qo33sF3?-5|w+~(TBrJmn_op}@}ZnnVJzaJog zfwOfAZ_D7P1Y?rA?dP3EBKFqE15d|FH?lAHhqrWFDc-J;3v}5Vb}EdBt}0tab=dXUP)O_3@4KDy1`UoC~B>>ljsRp z<|ZK`cmqoMcO9Dd+HkG!2QpYX8Ef!6^Zs58Z zVlGKE%^U)&vbK=&cw^4AvB!k$BI`nXXgB}`>iYC{hYY*vd?j*G zazElxdsdDMnQ8*G<**wANo2yA%b19f$!?}1Q*IQbD@zUDb)U%k7;TN|;wGr`+1Rq6 zNHxbU0z$8i~08PwgLT%g?7Ee&py ztz-in`+UszYkE_gGAh?LafRF;ZMI|f5_3L(`NL0?U^IW;!`$MpUIzpF@3XnXTQgr1I-XpTay z=-8Y08|GO(4yy%&mK%G4I;ifyMza;YHRafGSWgUp1~1L6S3#W&LxM(Q1pL;A8jpA! zHQR^`9_)0MHC;)a!4E39rs&x}HF#sic2E^zvKa%s>o{=dDcB0Di*RG4Uy$0U;tHP*64zb{P;oh}P+bA)q$pDt!v;OiRzwuB7I z0bT^fK_>%{$`1kqT5jG^NYu_&X8!e=6dX*8vWJ9K0uz9C4b3cQN#94|&7!;jg)&?&I#p)Da zGy}%ek}cU@unQwm$4c9AZ<>AZ1aU2&NNtXemTsON#GyK+yx!#Q1}Rfkn3a{a;*GDI zukaK|qC6v@uZ`pb7*Kpxt;mgVHKX~pz8Es7xhr+O96Pt@gp6-z`!|A42Wlgk7fR|# z|HkpZ65gqTH0<#u59nBN#%OSv9`6=%t84rH=Ay=Kd|%SFicOrDrk!ahoMvk7n6)40 zJFp|>qmkihi$QhYe;C=Qc~rb*El|-66zlWpLQIEK1&nqnL!u{wFV*j7d}VUfKpHxZ zHn(aAAa@cu(j^R>=L)a**JNrP*oEV$$^^0Bd>ByPyPey$MwuWL`wKiDV1oNRx|fA3h9evE9)ja)W7k{tcc?j9^(&5Re0-HD>!ps%nlV&OLFu;b=+=(u0|*FJ4`i)w`3vU4Ae6)D`Bq4x`a_^1_h4vs}fN zi{@r^#f1^hR6Dnb6njk%Sr@$AOef60J28;Km1GfXK_gflw-o53dVBOUK^XS^=VasR zCJ@vQ2Q{_RSOblA1-swv z(xQv9_3h#AnbR=@ooDgA$K7=&V)G$13~jaDOA`irU-Zlci$MYqm+h%|toMj5OWXIG z)F_O~1^#wh=#rP`#OTfjNmB`)I6o(oME;-l-ZQGHwQC#Q6a}ROMCnaXKw1P*dfPNn zq)L+x0wNuxLr_5wkS0}HXadqgC)CheDAJJ@ka!a zFLc-3s;-4j_W4&;-?;4XP<9|1YQ7u%c*3sVptX2?=Z#d-7xa0B{y2W^@t)*Yt7HPD zY7vX?32nz#vbAbdj>Q@@uzGR-cc%l3QEZQ)^A0Ij)yok$dW|I|ze=+H@}>Wl3RkAn z3-Fqmg_Hr! zOVq|)|7~QuM_3~Y{~4XMhNS5hA#9h$q85k>nMKd0!NEFFX1*qTeXbr=ev5;5ja@CA zW&ir}nyK@u7sSNaq+B8Ml#z*?r%=1njQw2F^8kG>)+|R*9Cj7BO_>I1#zp7?GRl1S z=pMf#1AB2R>oR7$i5?vvT~dv*Btbo`hI&c%B?f1#2dD(El&q9PAn{5G@Tl{-LbLE? zK(p~;w1Ou|N7B^?ZOXXec}ip_z1c#w3%B$38%3|JDAdX9i|&0t@+|@FoJOq2UTe1# zNFv&BIx|@XzVg>bcHVG1SyeWMA(dXy^&z9SE_+(p4?HE(WzZFWPa+Xx8 zZFuHkMjb9MW1Ot&(liH)Y_NBbPe)%3cBftZe9O8dF@h6>ai(|2uUZNEKHMp@m+sL) z&yM~*^{!~Kg?VPGkR{S*ihsbat_Ha!21~MHJR`qXFz$qX%85x&%xZ=RUoG!aGOkiBNYoagFdZLq^sWu+KX2j`eo+U5!^WN722$}&)N`my+(YZ?);lu z%Ees)4X&C;9MUCGJ8HPOQkMHWW)i;Ml0&kUSLuf}d3HQ&t_>oJ{&~6q45|P)L5cRE zO)?N14>Jpz#c{fK8?Rz~_02;X(+uqIxiOi^bU!Q%#Jsx1&b{N#ySviy7=joTSy^E3 zamj*5*&rHgf$GBf-d^Ej??}PXAjbNs=Y}zBD*=Np@-^6_YTQC_0_ys~$4DaLGdoL$ z+z%ESvrs;63fz+FG{fmF*&*Nc7p-n?o5UEk921$T1kmf+%Ll=e6C=2&u6<$%gY7z7 z;o;pm&t_!DeB&hSqGiqPGy=w|vlq~gb4%}M_}X!8+oYBv|3d`AEPXin*LCa8C!+0# zPo{FOyqK?APm?;2g`)kVJh)0U7Kl$;v0FzyU|;6%+_Jhr8HRV~Fbw@L_-j`Dz^Y1` z!>Cp8&TGj*DQmd;=|~8ATeRF(-dJWUaDd=0^ZDS#npXARX%WTqEe9V-_e}@b^tkF_ zNuzTm2(m8lyq3)_fM>E7Fla#v>MeHXa~T>m)1;Ol8IYMzg9g3RW?OEaCii%fL0WlL z)tsp-nKF}j=4MH;lD;KzKTe*IFZwWr?z@zz zM+RRz+T5}@T)1O;jRu$ynNB#k(aLnI6o`3Cfq%aZ0H9# z$nG*SWJuPt#6*OXg4p!sb5ZD`OmceW+CeqKx$$WXbPQ_1-AnV4f8&~uI@37c;RpA} z({vxzoW(@;x+7oeO7;T1?OObNeOF}FJGn9|D@4=dy}V-sMlcu{`r}t~uQ=six&Mf! z3V2=PUtK-fGGsjqTwN{?RhV+dUNpTkB$56$S_3x;D3D09T5_(DW|8Q-?Z>+o zf6Z=1Y;rSARK-{38<4Rnl`RzELz+$>>Wy56KQIL;@fU3-Pi#(Qj7BXsIH@L{^%vBE)unAU-9gWN%lJrsv@|B`8^3gSLE5dTjxI+F2DlD{ z`PEIT$Zjf(Lt0x!1al12i`#nVjiL+j17Uzox4A=^|%S$sy18Up~Q!2VXNw9?~W6ta0#d{dwP89P?U z?>1eq1uLF}x-Cf3`ONK3q4+80%;#6bHu;0X$oAm#9j6=tH?M&de zDS#kZz-KgDG#yaw;I?duIo1ZPpXfTZb52jwFD%1buS_HSw$^hd9AvTb^{V$?;4Y&WyttVn-8IN=6>0OqZ#j&e=?cTcr~yMc&+gpGLl4 zq=|d{eU#=VWB%0rlrS?1%(X(O7*)PWktDudb_Gb+-d%v zsJRooGrYbTeCXA{-uZOPdft(HfV+=N5E^Edj1>D8eiCtr)<<~@kJ&R#^g`OfjSUE= z4If?XF8j=pbWs&=MB$U0#o#$-iB5@W zmYHw(b%hgPGAG3s7pKl^q8?z=_%5p zJNLvuSzh|&1tX(z%P)$ffl5tjKu;^E)D=Tcl9yyGxXEm{OY2kFS9pTf1d%ciha9Dx zjRxG8cDBM!sn>Yj;~$b>7(!1?$eRYntmR}042kERxJADFZD1CW0od`)$?w=q|W6f5lj-TiCfIx0KZoo@RdK!PP)uCV$L0nTl4G*1#&Rl z*N-y{?3*sack|fv+d!jFi#J+dr?L4h7!RgI+xR; zes)N#7I!McakNZs>;jd~WOSyYI#cJ9laZouk1rkNO~uTl-}P^`vPR_-KRzcY0A%Z^ zdJo<%(nN~BEfC$KC#$e@z||HJvA`(sPG?@?AeNzuSTb@PYRXLi97lv3{QuAPnoy(y4 z^84X6l2*=Lv*EDA8z`^lv8zdOPdUhNRN)8}*v-;P&8k=W@dbwLuSi+x!=)QyblkJf z9CVRP1b{L%-@NU*0k`zog%<6lV$RSfbH4no?*x``J?LjhdC=+(YZj1)!eU0?IfEuYCsu@+yWD|f1qeA4ayV~Xs7u7^XkHMJkE z-1%&}DAC`h0F1S4q*@IOk%wwFm^UwM@Aipv%!lYvE)E(oI*++D?jAQg1nCWiLeh@3 zyEZ^zG#LiiI6^%Kk{P1YIdxy2#L&fCncG#|w2owJc4I^#S%SFdB@}+))X3vL zA2F!!A5M-1UVdKMublcWAydHVHAPKw`=jlFpYsf7Fj3StKO4Q^^$`^bO01?WLi;p_ zzwq!w$hS$?r^?23?T=Hkl4#D#7AEK6~TyAL3}{ z>CG)!tyx2LV?td`&=I;5bX(L=f&6m1%PFs6LFkgE=3x?Mwga0yz2<&WNnu|--x1e! zxF1o)UwAr~F;g~u){~#?$<<*N4@7LbGB0-;bUnVlbCFGZ=gmu3cfe`_^yCt~{<)--M=L%CBcTOrwzg9Zy z^*SPvCwWj0Vcq7Qo&2h17k{;_=lN@N123z!ii@Ng(;m!$do*_EIy>K_0lmo4^Y@d7 zu*5AJx-+Wj_Y3}Jmri_y*XizS>Jrbm<-ge0km{zsb9#0{!mhOK$J|c(^ZN_~P)2{k zdxpz?hGRuOSR?Y8+Y$#iAuSER>lA}@F+V}XV>cE$B%Z$)YPw!{YbJ9_eS{L47H>^S z7$9{oh%KO3zqB3hp@kF52Y3LV3kT6lHMu*A{adj-WHq9B>DILpYmOfMg@2<49mZ_A zrZ>C;o5T=MM<3BXYdO<*zG_4>BZVvjTH`>Csszlu1}C|X9+dV}x#csqRlQ{J(86^9 zhdFA`R*Go*`BO9biQ}u}|7Yss$eY$1Y}{L%KA9}eV*74xjLuI=SG%-j>gEe{jEP;^ zBnvJa)0w5=aQwEP!uh%WCf#esCU{vMofsV+{XVqNwRLdx<;Fqsb$juQ=yy~qRuSFB zcgV0(viwx)S0`CwQT2_R60jjX5k`}y#=aK1P$ zhlGIE_W@#26I|Fu7}DzseH0Wn7p5SI>{E#O9{>BA=w1-%u{N_J%wK%PaD;~@G(_n5 zd)#8vi1#W4n8ZG;s6p<#=yo^*Fd zJxA<*R`%P6$<<3)wj97!ALVRV2=Fn6N{NcC82+Jx@(G7Z{mTkvbiIE2{-1Q2^`lIl zKmU7>O7MprdQbHi5aNy`(1p5mpq|TOVi7*kK9{$lWt}?T3ilZ@g1c!BE`G#`ynCx@ zx7(T7=N6;PF)*+h@aQ1yOAxRArkcO--IK2u-=0B9d&l@$4jv6Ovvr=l)7jHF@87>z z?(oY|LTo*+Z$e9qlwLkXOzvH1my&GUMh4tFO@&{gMc(Pa5|fgXnsUYSFX>+g^e9Of z%Hs0_e?Pk}Ik4Ob${goHw@9D8W8!BQb8jF2C! zmuGsKT5cJ0l0{?Wz|{8EUJzRgWHHC0fY^}tz_MyIVhF-WVfS;2nn)Y~%o<~zIn56n zXHCvZ@qsfGC-@t*raoGvetTwt18b&%Pf6F(O`$3eSAh)0`4Z^wDF@HXN7e|5oU3$E z=4o#Q$2kup(wV&xiO+AaS>?eCi;P?R|J?6o=lg75T0b!pH`7bJSa6Y)F+XKKP{+jH zJ5{znG3hwz81i3P==!4Ako8%&UX@5kRC;~z0=0iO>M!ThW9|b{X9S?IK!nL#x>!1V zwh*U|IBdkD<2YeU!AYjmy89hV#n!&?ROuKeS;*+HgP1e;r{$#2$xPfkJPusuX-7Kra0C7Ft$B6uK#i<)3_hDC~VG~q=3N! z(f>5$U0jl`wN^ESF6n!yvAr!u_R^`nJx8wa$UA=Y%l;$?M%t z_Fl+^e_oXe9RVnWQuwtyzIJl{x$B2x42T@G<5VttmW`h=we!~ts@ZjaQ>yA9mf2j z=<-?km5opO1WDg!$E$j`K8{2MpPqX=9Jz;*fL8`pJvG2vg`X zbj*}1E8d8{j+HY>Qwa#)0E&ehO4a_YT$P*np!ya_hsI{}=wHJgx2X|Hp@9|myHQgF-ie8#$8oR#ReTyEL-8GzJJTVC zGZS0=i1EbMt9H#p<1ltJ|#$cptl%-(?JLjJ1EX&1*#fTq=`#&LzS9VRt#_qAWiJZ+q zn&1VFSh*Wdu~#bO&O}EHrVMKUNQ;RB5p%=o%xdLJ;AwDU5#&~tOg}`6G{T;)0jSA` z0&Kv2&uv_vZ_8fqbf*_$lZas8>{2Cwp`_0;mr9ELsYbwEfd_;SW{nPJ5T$5L>B(6} zgVrTJ_UrXuBXUNHP57RJlg8I?(81HT1)w_Xgk90&p4@;id7Zr5+42%MAKco`d>vu^E}S)32uh#w0yN57XV?EA z!Zf-FIA_{mV6W{T>DdPm%x`~;j9?2Xp>{B*=W8EWis?3uje1dI?7Oa?HnP}qNflZr zOir;u zu;2K;f}tGy$ACvHw9+XjImHHD?7l5gqE;3NyOU+5N;ZjC8{Hsw+Gz#? zU%O^2=vQ2Ifd_os{XUzwvqiBnkO>YN<1M0;CC@JY)r8VE=Jz-h>4m3>jYUM%9cS?$ zdr!YB!ue&N5D~}`erQ@~i^e($t$>VOO6#1Y1LfYA&ngJ%sw?Qq>|^nw-Zwq=a>v8bT5PZG_V}KBKe523bL;^1DQUJPm-*XRHjs7LOmD}$ zgQU+x+T)z!K1}BBmrs{mH5RjvVo%Aca&T1bF_x=IME%U*5l<1ppuKlY{>!16B4RyF zx-%!5_eyfVom5=$&c!PgEx+A9QICEG9JU{3zy{o+don8}3&7E`U*57+pZ_vT(`eb` zlVzZMOGO`XluX~{@p^|4j6(1ZMz?n@RV-bjLi%(gC}j_l&`=!mqVY4zhO+m;vn>h;xB)aNm*SXj_2;S)-|3|fwXWFPKVD0w+?2Fzif(^^Jb~Ohex--@|BPgh5!No8 zj-I`!XgqmEJLb6QU93?)uv^7Hy(3DVui=bsv4wM6IjD%2x`2nzO+E(Bf`mGS;h~l| zavkp4vIPjx*%*cCkQhO&5TDWZGpTdp-N_?r344BkbgikkjMJtPkKw$)f>MkGcRoH^ z8v;ep3fxpsP_US;va{%me_%0^t7@^-aeB~I=e`y)AUfZ8@YW$!%ExUP>=91(Fr!6n zDB>_+^iT0rMB@LhQRkj228eh7qXd5XY~-}0m#?h5)7D*Vf4}fG_aJl4kLU2$oz^cN zqV~9iy_BNTH@G`(WVJKp2TA{4x4yWtk9aTZ-yqL!g+Vj^&pYu0?=3%#2Kv7>@apPt zS!jmc0A|gaFPr>x>3eqmjE@L9v3m&FG>-|x#V?NrdAP1to8)Kq1V}#lL`ySyPGhVW z1J$p5|L0!-zs$W23~jUkRHp^58;zmBy$=|ZfGoX{Ny%D=Bz-r3*=RQFB z+_UG1x2X752G9e)-~VVx1Qq-5qrb6wlIgwIbQS_MVub+G&!YeB9o|fD>`pDXE|jB* z#tTqn?MiDk3W$8%o*vjNJ?nm!9_jVxBDn{)YS(UyqP&;ypJ~p%j(gEox0WHv0kUbe z0Z(!GuaU^!;11Y9v<>gcj`%(Jv($FRjFk!*Kp*C%CH&~=wcE~hn6CYaKz|*vC6hgn z**T1+t;%kc(fvPnu7BTq8(R2AFa_j-c* z{gnayba4}f-#PU|%3GkUhCr>Z zMape1bq6-*G)XU~DStq03)WTB8^|FM&M@HNjXDl5vhv?Ajs4JRZ~H{X1p9NW??o#ACZJLyw?Z=r!-0lvUvEJEh=TXu zvz#+Fsv*n58gM+!kvIwZZ#}K+r(%xNRS&KE;vd?LdQceg86xjMIOSbc1? z&hwE7HYXgCDAMci1B~;wi}|u{K)N&HP-W4~W~XVa;^{ILb~RtNST){O>nS1DpEfHa z>)s(1xbR`|I5$rN%6hfCcO{5h6-C^D0R#Hmxl*f8HL*W=on^e*!R=>zjg99G#vxk$ zSRyDw=REXe>xA#pv~XNlxv20m1|y68HKg1~o{APPJT0m+t}*c0Njzz4OyjXN+wS^@ zV>mwW?GXS^{yAysZ)kHrf1n^_0HTJ;0uawFHRJsivqWNk($~gUKcNwm?DQ3*n?vA_ zEJEG~8FbsG#44ow0o(PJZGlcr8q{!h`1!o3*-v4rJ47EPi)&i72^2?M+O5vO7}Ls3 zL)5iCztZm z+@2W#YZZb1xMvE)q!wExwUi)PoQv2-Zd@Cn?SgnM-UuSJIxd_6lzWnH5GoRLsyFX^ z-PcInzU7%*Cx3tnQ7HNZo%MS$<(A;l{y2J$NiaFkUCgFvGFX>egD(#Y_2)M}=t*BZ z*>a@0S`Kkhyw2I*#ubVVy~fCQ&nQyXrgrsO96MP5f-8+|vygk7gRn z51d$#^~YH=?Vre;1g;=er@t!q8U(j%R&A7gN90~(8ZMRD!&{vCRrXE!Ne_9v;4_+PWfZS9%wIZDx8&kx?iL)^ zF%6Pc>KSrN9n{*kW!O7wtx#Yt*e0P&rsWf4ZT6Ez`Qic!S6uMpt0E1Mz4|xP{&}Cs z$ixTG^>zC|#Dclc5XD@y2h}n$nj-jx)0Tu_bS1U$eo1?$^ZlyU=KKta?## z#WMq7b0XLXngJmb@R5w$DPI-xsB&$Z zHo_EvhMCo|(;t(QiCS0c;LkL9yTHKme}RuSH{fqeIQ|0W6pKDV{m4-nlf@s&hSDL< zJ3Gssf23Doc2xw@8}vX=4eq}G0udWPygl!Zzz`Q3TyLVs@bBrK6mrljfr^1yC4~l* zNUJ(xDXP(*rTX`zlOPRPY|>_l=VY5o8%SXaxJq@JTkrZn3rR zV?m9TNAik?=^0;$i`MU|Ky)a{kG=%<9F`+G;}LD*Wp}U9aK+OS`UG*@5#`k z%6pMadt=h4{n=%iiLm(Riar!C(wGH}U7jEK&i#1QHsmEO%#4_WbZ+U9&R+e{t6`h< zk4|jwrJLC7!ko?156R?}qLm9jL zW~w(^wS|{uji7xQYie%a#})I`#9YZwHO~R9BxCL7MjN)s`I2eaPr;#?9sT&V4X~vD z4^-B+Mx{-$&Ni%$2djTuzN-~v$d*9R3B}{q7J+l>)cC6Wa@PxCG_p|O&a7rvfTZ~R z@{`%iLEud9ujfQR`3C|XK1_4VPxs_4HTmr_X=$3q;4*ff{!(I$@dn(48F8lXxT;Gb z%SU;mK?B>~eO1C>I~TjA1e@TjH8s1&LXy9=?cNJ{%ymMLC{lT)tm+SaZ`0wm zL}f-8m2<5&l+)nL)J#l^AYO+u{y`Jv4Mr5;6BZL-{^+lVd4t83gAy!ec!d4v+^g#t z9#G%?@DFqAWs#;|?-=kV1@O&+Vm!*!2u+Bom%UD3*&;by&etDl(84%n%qZheo{M5F z6#qH^WWYe!9eof^OAzMW$roNh+^XDn3h1{497yQvX6Wzev!Bj$hg#V{-uTbp1^pZ36(L#~m3i~>mdspN8EvU zul1~vS<9O^J&t^7NZk{G)lC}|UrXE1m%X(6WG4%JXH_jd_miad&&(e?=w?IY=9}~N zbML#h-Qd2hkS(e7KHN{h6oNssT+^Js%cFItk^TX(s`u1$asw8xQCNhjbIzTnl|E9Q zkTKj(AfZ=oIVM?x!>xkO+J%+mhxs75G@*KGMz4d5)$onR_Hm=yC4n@EPXVn-Uw z-#Ih{ZE;QwaC+Xd-s8vZ)zK&>$Vp4&qLoo2FV12pryb_$=VjpjJ)vD|@~R3hN~qB< z;oVLbx`)GzxNMoNiY5vR17O-@%sLNH`^bau5#hVflIQtYcaOKs@bwjdXV@+u6m49j z=)}(^eZ+S14=wmOO#|h;Tw!0fTR+Wv4uR1&X2kJ*mh7<@@}k$9HK82Rl?H5E)+WT7 zq^2I6*J+R-*UVZ&M$+s__SWXli>W{KnzGkFDAj(bBC+IchMt<|PBMMCMVLlja!Go2 z#$*Lw4LjjT_uWxV$(G_t`h1u@D{+7g-Q&LsJb24Qi$5cp>?W?|X_usvX7;=sa8;6K zs!F?zIivR-lYTR z43ENl1PQ``p6eVTTL+GUmPjX{)4|YT^kNIf1`KK%FY98o4|c4btJ#2of^G!~f&(_5 zGwr>p!VD0Je&U7(a5cUKq|>&NipyQkhXsZ<~xkA*Zm#La3f>L~IB68?ekjbnf=oL4azb}JJyyKHHuSfg5rJvig%E&LboJd zGyn$N#qCQp!dGSp;wg>PqI|v2vYW5cvJ|lAH~-Zlp($HsB2*T)Xj%78*^XAu?o;OV zrfyP~v^wNW(oHVmv~O~(XC4ux>?8IrTMR=2A&z+j9rQhKCy*t)JZ&yUti05d8n7a< z{%>dAgn~^a-q{BR)X1dswoDf`nceQB>z)r_pQ^V;_0EbM@=~$K=%wkiL+L0%-vR0> z!FldVy1DJp1q)SUzuo$+QXqbHHR<;|S_9RLYBXHlguxdO7kWd;+I#fD&GQNe;zK^_ z%P>tT@eAOIEyT9V+QYMk_ka%)A(*pKrtC{JTzLS@lM>{*iuyFzc?sYXqj!=oq_57G zm2%H3kb?G&qq2bDlG*vp{1vUuKuYykP5i-_V2F2jRw{1D9u@5-6USkeJhZQ|+wlG{ z#C26+pfI{k&palrl-i+s}K+IS2ecVUMlCU06?%4Sl61x{^5y<0tAJUBAXGaL zq%uNB?sm_H3UtaLMQk(tSnY6GiYt>|^NNlrOmom2!Q6T7zbBZJeC- z_Q_dEI;H6<0Dj##3{HZ&N>WIP|A~zW6bKzv~#5X`X_X_s>1E_i9yP3mPP93Bl0^!X++DsY&P)fxYsd`!z!D*h9@ zQxrX^lLsE@vWfa@9Z0A&1eDKn1r&y;yrscek=~<;4$51jl1@&!+oPZvz1YGo z*VQRT&>V33E8n~7iM;s7FfWvk?fJTjEF-1#@z1hhWu{MTxCIg=XT+M!S)Ec#jLMvj zX7%gf+D5d164l=Ctn#XRr4BG3A&AMbOT~S(;85&TwD}-1U_&<{JM@0*$AKp^#XC7I zKr|*xdq)UG98W6NDhT;t{zk+n>4*XH-BP;ICY2tg*4&j5<0^xZ³nU|tXH#H%a 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 J{%!v8e*wU#>-+!! diff --git a/_examples/database/mongodb/2_get_all_movies.png b/_examples/database/mongodb/2_get_all_movies.png deleted file mode 100644 index 1360c0a813a67eac79806f5644521f721aa10f7a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104362 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

{{.MyMessage}}

- - - \ No newline at end of file diff --git a/_examples/dependency-injection/overview/web/views/hello/name.html b/_examples/dependency-injection/overview/web/views/hello/name.html deleted file mode 100644 index d6dd5ac6..00000000 --- a/_examples/dependency-injection/overview/web/views/hello/name.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - {{.}}' Portfolio - My App - - - -

Hello {{.}}

- - - \ No newline at end of file diff --git a/_examples/dependency-injection/sessions/main.go b/_examples/dependency-injection/sessions/main.go deleted file mode 100644 index 2172c34c..00000000 --- a/_examples/dependency-injection/sessions/main.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12/_examples/dependency-injection/sessions/routes" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/sessions" -) - -func main() { - app := iris.New() - sessionManager := sessions.New(sessions.Config{ - Cookie: "site_session_id", - Expires: 60 * time.Minute, - AllowReclaim: true, - }) - - // Session is automatically binded through `sessions.Get(ctx)` - // if a *sessions.Session input argument is present on the handler's function, - // which `routes.Index` does. - app.Use(sessionManager.Handler()) - - // Method: GET - // Path: http://localhost:8080 - app.ConfigureContainer(registerRoutes) - - app.Listen(":8080") -} - -func registerRoutes(api *iris.APIContainer) { - api.Get("/", routes.Index) -} diff --git a/_examples/dependency-injection/sessions/routes/index.go b/_examples/dependency-injection/sessions/routes/index.go deleted file mode 100644 index d1660563..00000000 --- a/_examples/dependency-injection/sessions/routes/index.go +++ /dev/null @@ -1,17 +0,0 @@ -package routes - -import ( - "fmt" - - "github.com/kataras/iris/v12/sessions" -) - -// Index will increment a simple int version based on the visits that this user/session did. -func Index(session *sessions.Session) string { - // it increments a "visits" value of integer by one, - // if the entry with key 'visits' doesn't exist it will create it for you. - visits := session.Increment("visits", 1) - - // write the current, updated visits. - return fmt.Sprintf("%d visit(s) from my current session", visits) -} diff --git a/_examples/dependency-injection/smart-contract/main.go b/_examples/dependency-injection/smart-contract/main.go deleted file mode 100644 index f3c93f33..00000000 --- a/_examples/dependency-injection/smart-contract/main.go +++ /dev/null @@ -1,156 +0,0 @@ -package main - -import ( - "fmt" - "strings" - - "github.com/kataras/iris/v12" - - // External package to optionally filter JSON responses before sent, - // see `sendJSON` for more. - "github.com/jmespath/go-jmespath" -) - -/* - $ go get github.com/jmespath/go-jmespath -*/ - -func main() { - app := newApp() - app.Logger().SetLevel("debug") - - // http://localhost:8080/users?query=[?Name == 'John Doe'].Age - // <- client will receive the age of a user which his name is "John Doe". - // You can also test query=[0].Name to retrieve the first user's name. - // Or even query=[0:3].Age to print the first three ages. - // Learn more about jmespath and how to filter: - // http://jmespath.readthedocs.io/en/latest/ and - // https://github.com/jmespath/go-jmespath/tree/master/fuzz/testdata - // - // http://localhost:8080/users - // http://localhost:8080/users/William%20Woe - // http://localhost:8080/users/William%20Woe/age - app.Listen(":8080") -} - -func newApp() *iris.Application { - app := iris.New() - - // PartyFunc is the same as usersRouter := app.Party("/users") - // but it gives us an easy way to call router's registration functions, - // i.e functions from another package that can handle this group of routes. - app.PartyFunc("/users", registerUsersRoutes) - - return app -} - -/* - START OF USERS ROUTER -*/ - -func registerUsersRoutes(usersRouter iris.Party) { - // GET: /users - usersRouter.Get("/", getAllUsersHandler) - usersRouter.Party("/{name}").ConfigureContainer(registerUserRoutes) -} - -type user struct { - Name string `json:"name"` - Age int `json:"age"` -} - -var usersSample = []*user{ - {"William Woe", 25}, - {"Mary Moe", 15}, - {"John Doe", 17}, -} - -func getAllUsersHandler(ctx iris.Context) { - err := sendJSON(ctx, usersSample) - if err != nil { - fail(ctx, iris.StatusInternalServerError, "unable to send a list of all users: %v", err) - return - } -} - -/* - START OF USERS.USER SUB ROUTER -*/ - -func registerUserRoutes(userRouter *iris.APIContainer) { - userRouter.RegisterDependency(userDependency) - // GET: /users/{name:string} - userRouter.Get("/", getUserHandler) - // GET: /users/{name:string}/age - userRouter.Get("/age", getUserAgeHandler) -} - -var userDependency = func(ctx iris.Context) *user { - name := strings.Title(ctx.Params().Get("name")) - for _, u := range usersSample { - if u.Name == name { - return u - } - } - - // you may want or no to handle the error here, either way the main route handler - // is going to be executed, always. A dynamic dependency(per-request) is not a middleware, so things like `ctx.Next()` or `ctx.StopExecution()` - // do not apply here, look the `getUserHandler`'s first lines; we stop/exit the handler manually - // if the received user is nil but depending on your app's needs, it is possible to do other things too. - // A dynamic dependency like this can return more output values, i.e (*user, bool). - fail(ctx, iris.StatusNotFound, "user with name '%s' not found", name) - return nil -} - -func getUserHandler(ctx iris.Context, u *user) { - sendJSON(ctx, u) -} - -func getUserAgeHandler(u *user) string { - return fmt.Sprintf("%d", u.Age) -} - -/* END OF USERS.USER SUB ROUTER */ - -/* END OF USERS ROUTER */ - -// common JSON response for manual HTTP errors, optionally. -type httpError struct { - Code int `json:"code"` - Reason string `json:"reason"` -} - -func (h httpError) Error() string { - return fmt.Sprintf("Status Code: %d\nReason: %s", h.Code, h.Reason) -} - -func fail(ctx iris.Context, statusCode int, format string, a ...interface{}) { - err := httpError{ - Code: statusCode, - Reason: fmt.Sprintf(format, a...), - } - - // log all the >= 500 internal errors. - if statusCode >= 500 { - ctx.Application().Logger().Error(err) - } - - // no next handlers will run. - ctx.StopWithJSON(statusCode, err) -} - -// JSON helper to give end-user the ability to put indention chars or filtering the response, you can do that, optionally. -// If you'd like to see that function inside the Iris' Context itself raise a [Feature Request] issue and link this example. -func sendJSON(ctx iris.Context, resp interface{}) (err error) { - indent := ctx.URLParamDefault("indent", " ") - // i.e [?Name == 'John Doe'].Age # to output the [age] of a user which his name is "John Doe". - if query := ctx.URLParam("query"); query != "" && query != "[]" { - resp, err = jmespath.Search(query, resp) - if err != nil { - return - } - } - - _, err = ctx.JSON(resp, iris.JSON{Indent: indent, UnescapeHTML: true}) - return err -} diff --git a/_examples/desktop/blink/main.go b/_examples/desktop/blink/main.go deleted file mode 100644 index a771727f..00000000 --- a/_examples/desktop/blink/main.go +++ /dev/null @@ -1,42 +0,0 @@ -// +build windows - -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/raintean/blink" -) - -const addr = "127.0.0.1:8080" - -/* - $ go build -ldflags -H=windowsgui -o myapp.exe - $ ./myapp.exe # run the app -*/ -func main() { - go runServer() - showAndWaitWindow() -} - -func runServer() { - app := iris.New() - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

Hello Desktop

") - }) - app.Listen(addr) -} - -func showAndWaitWindow() { - blink.SetDebugMode(true) - if err := blink.InitBlink(); err != nil { - panic(err) - } - - view := blink.NewWebView(false, 800, 600) - view.LoadURL(addr) - view.SetWindowTitle("My App") - view.MoveToCenter() - view.ShowWindow() - - <-view.Destroy -} diff --git a/_examples/desktop/lorca/main.go b/_examples/desktop/lorca/main.go deleted file mode 100644 index eb5fe18f..00000000 --- a/_examples/desktop/lorca/main.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/zserge/lorca" -) - -const addr = "127.0.0.1:8080" - -/* - $ go build -ldflags="-H windowsgui" -o myapp.exe # build for windows - $ ./myapp.exe # run -*/ -func main() { - go runServer() - showAndWaitWindow() -} - -func runServer() { - app := iris.New() - app.Get("/", func(ctx iris.Context) { - ctx.HTML("My App

Hello Desktop

") - }) - app.Listen(addr) -} - -func showAndWaitWindow() { - webview, err := lorca.New("http://"+addr, "", 800, 600) - if err != nil { - panic(err) - } - defer webview.Close() - - // webview.SetBounds(lorca.Bounds{ - // WindowState: lorca.WindowStateFullscreen, - // }) - - // Wait for the browser window to be closed - <-webview.Done() -} diff --git a/_examples/desktop/webview/main.go b/_examples/desktop/webview/main.go deleted file mode 100644 index e354a953..00000000 --- a/_examples/desktop/webview/main.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/webview/webview" -) - -const addr = "127.0.0.1:8080" - -/* - # Windows requires special linker flags for GUI apps. - # It's also recommended to use TDM-GCC-64 compiler for CGo. - # http://tdm-gcc.tdragon.net/download - # - # - $ go build -ldflags="-H windowsgui" -o myapp.exe # build for windows - $ ./myapp.exe # run - # - # - # Note: if you see "use option -std=c99 or -std=gnu99 to compile your code" - # please refer to: https://github.com/webview/webview/issues/188 -*/ -func main() { - go runServer() - showAndWaitWindow() -} - -func runServer() { - app := iris.New() - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

Hello Desktop

") - }) - app.Listen(addr) -} - -func showAndWaitWindow() { - debug := true - w := webview.New(debug) - defer w.Destroy() - w.SetTitle("Minimal webview example") - w.SetSize(800, 600, webview.HintNone) - w.Navigate("https://iris-go.com") - w.Run() -} diff --git a/_examples/dropzonejs/README.md b/_examples/dropzonejs/README.md deleted file mode 100644 index d2ec00fc..00000000 --- a/_examples/dropzonejs/README.md +++ /dev/null @@ -1,168 +0,0 @@ -# Articles - -* [How to build a file upload form using DropzoneJS and Go](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) -* [How to display existing files on server using DropzoneJS and Go](https://hackernoon.com/how-to-display-existing-files-on-server-using-dropzonejs-and-go-53e24b57ba19) - -# Content - -This is the part 1 of 2 in DropzoneJS + Go series. - -- [Part 1: How to build a file upload form](README.md) -- [Part 2: How to display existing files on server](README_PART2.md) - -# DropzoneJS + Go: How to build a file upload form - -[DropzoneJS](https://github.com/enyo/dropzone) is an open source library that provides drag'n'drop file uploads with image previews. It is a great JavaScript library which actually does not even rely on JQuery. -In this tutorial, we are building a multiple file upload form using DropzoneJS, and the backend will be handled by Go and [Iris](https://iris-go.com). - -## Table Of Content - -- [Preparation](#preparation) -- [Work with DropzoneJS](#work-with-dropzonejs) -- [Work with Go](#work-with-go) - -## Preparation - -1. Download [Go(Golang)](https://golang.org/dl), setup your computer as shown there and continue to 2. -2. Install [Iris](https://github.com/kataras/iris); open a terminal and execute `go get -u github.com/kataras/iris` -3. Download DropzoneJS from [this URL](https://raw.githubusercontent.com/enyo/dropzone/master/dist/dropzone.js). DropzoneJS does not rely on JQuery, you will not have to worry that, upgrading JQuery version breaks your application. -4. Download dropzone.css from [this URL](https://raw.githubusercontent.com/enyo/dropzone/master/dist/dropzone.css), if you want some already made css. -5. Create a folder "./public/uploads", this is for storing uploaded files. -6. Create a file "./views/upload.html", this is for the front form page. -7. Create a file "./main.go", this is for handling backend file upload process. - -Your folder&file structure should look like this after the preparation: - -![folder&file structure](folder_structure.png) - -## Work with DropzoneJS - -Open file "./views/upload.html" and let us create a DropzoneJs form. - -Copy the content below to "./views/upload.html" and we will go through each line of code individually. - -```html - - - - - DropzoneJS Uploader - - - - - - - - - - - -
-
- - -
-
- - - -``` - -1. Include the CSS Stylesheet. -2. Include DropzoneJS JavaScript library. -3. Create an upload form with css class "dropzone" and "action" is the route path "/upload". Note that we did create an input filed for fallback mode. This is all handled by DropzoneJS library itself. All we need to do is assign css class "dropzone" to the form. By default, DropzoneJS will find all forms with class "dropzone" and automatically attach itself to it. - -## Work with Go - -Now you have come to Last part of the tutorial. In this section, we will store files sent from DropzoneJS to the "./public/uploads" folder. - -Open "main.go" and copy the code below: - -```go -// main.go - -package main - -import ( - "os" - "io" - "strings" - - "github.com/kataras/iris/v12" -) - -const uploadsDir = "./public/uploads/" - -func main() { - app := iris.New() - - // Register templates - app.RegisterView(iris.HTML("./views", ".html")) - - // Make the /public route path to statically serve the ./public/... contents - app.HandleDir("/public", iris.Dir("./public")) - - // Render the actual form - // GET: http://localhost:8080 - app.Get("/", func(ctx iris.Context) { - ctx.View("upload.html") - }) - - // Upload the file to the server - // POST: http://localhost:8080/upload - app.Post("/upload", iris.LimitRequestBodySize(10<<20), func(ctx iris.Context) { - // Get the file from the dropzone request - file, info, err := ctx.FormFile("file") - if err != nil { - ctx.StatusCode(iris.StatusInternalServerError) - ctx.Application().Logger().Warnf("Error while uploading: %v", err.Error()) - return - } - - defer file.Close() - fname := info.Filename - - // Create a file with the same name - // assuming that you have a folder named 'uploads' - out, err := os.OpenFile(uploadsDir+fname, - os.O_WRONLY|os.O_CREATE, 0666) - - if err != nil { - ctx.StatusCode(iris.StatusInternalServerError) - ctx.Application().Logger().Warnf("Error while preparing the new file: %v", err.Error()) - return - } - defer out.Close() - - io.Copy(out, file) - }) - - // Start the server at http://localhost:8080 - app.Listen(":8080") -} -``` - -1. Create a new Iris app. -2. Register and load templates from the "views" folder. -3. Make the "/public" route path to statically serve the ./public/... folder's contents -4. Create a route to serve the upload form. -5. Create a route to handle the POST form data from the DropzoneJS' form -6. Declare a variable for destination folder. -7. If file is sent to the page, store the file object to a temporary "file" variable. -8. Move uploaded file to destination based on the uploadsDir+uploaded file's name. - -### Running the server - -Open the terminal at the current project's folder and execute: - -```bash -$ go run main.go -Now listening on: http://localhost:8080 -Application started. Press CTRL+C to shut down. -``` - -Now go to browser, and navigate to http://localhost:8080, you should be able to see a page as below: - -![no files screenshot](no_files.png) -![with uploaded files screenshot](with_files.png) \ No newline at end of file diff --git a/_examples/dropzonejs/README_PART2.md b/_examples/dropzonejs/README_PART2.md deleted file mode 100644 index e120e32a..00000000 --- a/_examples/dropzonejs/README_PART2.md +++ /dev/null @@ -1,310 +0,0 @@ -# Articles - -* [How to build a file upload form using DropzoneJS and Go](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) -* [How to display existing files on server using DropzoneJS and Go](https://hackernoon.com/how-to-display-existing-files-on-server-using-dropzonejs-and-go-53e24b57ba19) - -# Content - -This is the part 2 of 2 in DropzoneJS + Go series. - -- [Part 1: How to build a file upload form](README.md) -- [Part 2: How to display existing files on server](README_PART2.md) - -# DropzoneJS + Go: How to display existing files on server - -In this tutorial, we will show you how to display existing files on the server when using DropzoneJS and Go. This tutorial is based on [How to build a file upload form using DropzoneJS and Go](README.md). Make sure you have read it before proceeding to content in this tutorial. - -## Table Of Content - -- [Preparation](#preparation) -- [Modify the Server side](#modify-the-server-side) -- [Modify the Client side](#modify-the-client-side) -- [References](#references) -- [The End](#the-end) - -## Preparation - -Install the go package "github.com/nfnt/resize" with `go get github.com/nfnt/resize`, we need it to create thumbnails. - -In previous [tutorial](README.md). We have already set up a proper working DropzoneJs upload form. There is no additional file needed for this tutorial. What we need to do is to make some modifications to file below: - -1. main.go -2. views/upload.html - -Let us get started! - -## Modify the Server side - -In previous tutorial. All "/upload" does is to store uploaded files to the server directory "./public/uploads". So we need to add a piece of code to retrieve stored files' information (name and size), and return it in JSON format. - -Copy the content below to "main.go". Read comments for details. - -```go -// main.go - -package main - -import ( - "image/jpeg" - "image/png" - "io" - "os" - "path" - "path/filepath" - "strings" - "sync" - - "github.com/kataras/iris/v12" - - "github.com/nfnt/resize" // $ go get -u github.com/nfnt/resize -) - -const uploadsDir = "./public/uploads/" - -type uploadedFile struct { - // {name: "", size: } are the dropzone's only requirements. - Name string `json:"name"` - Size int64 `json:"size"` -} - -type uploadedFiles struct { - dir string - items []uploadedFile - mu sync.RWMutex // slices are safe but RWMutex is a good practise for you. -} - -// scan the ./public/uploads folder for any files -// add them to a new uploadedFiles list. -func scanUploads(dir string) *uploadedFiles { - f := new(uploadedFiles) - - lindex := dir[len(dir)-1] - if lindex != os.PathSeparator && lindex != '/' { - dir += string(os.PathSeparator) - } - - // create directories if necessary - // and if, then return empty uploaded files; skipping the scan. - if err := os.MkdirAll(dir, os.FileMode(0666)); err != nil { - return f - } - - // otherwise scan the given "dir" for files. - f.scan(dir) - return f -} - -func (f *uploadedFiles) scan(dir string) { - f.dir = dir - filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { - - // if it's directory or a thumbnail we saved earlier, skip it. - if info.IsDir() || strings.HasPrefix(info.Name(), "thumbnail_") { - return nil - } - - f.add(info.Name(), info.Size()) - return nil - }) -} - -// add the file's Name and Size to the uploadedFiles memory list -func (f *uploadedFiles) add(name string, size int64) uploadedFile { - uf := uploadedFile{ - Name: name, - Size: size, - } - f.mu.Lock() - f.items = append(f.items, uf) - f.mu.Unlock() - - return uf -} - -// create thumbnail 100x100 -// and save that to the ./public/uploads/thumbnail_$FILENAME -func (f *uploadedFiles) createThumbnail(uf uploadedFile) { - file, err := os.Open(path.Join(f.dir, uf.Name)) - if err != nil { - return - } - defer file.Close() - - name := strings.ToLower(uf.Name) - - out, err := os.OpenFile(f.dir+"thumbnail_"+uf.Name, - os.O_WRONLY|os.O_CREATE, 0666) - if err != nil { - return - } - defer out.Close() - - if strings.HasSuffix(name, ".jpg") { - // decode jpeg into image.Image - img, err := jpeg.Decode(file) - if err != nil { - return - } - - // write new image to file - resized := resize.Thumbnail(180, 180, img, resize.Lanczos3) - jpeg.Encode(out, resized, - &jpeg.Options{Quality: jpeg.DefaultQuality}) - - } else if strings.HasSuffix(name, ".png") { - img, err := png.Decode(file) - if err != nil { - return - } - - // write new image to file - resized := resize.Thumbnail(180, 180, img, resize.Lanczos3) // slower but better res - png.Encode(out, resized) - } - // and so on... you got the point, this code can be simplify, as a practise. -} - -func main() { - app := iris.New() - app.RegisterView(iris.HTML("./views", ".html")) - - app.HandleDir("/public", iris.Dir("./public")) - - app.Get("/", func(ctx iris.Context) { - ctx.View("upload.html") - }) - - files := scanUploads(uploadsDir) - - app.Get("/uploads", func(ctx iris.Context) { - ctx.JSON(files.items) - }) - - app.Post("/upload", iris.LimitRequestBodySize(10<<20), func(ctx iris.Context) { - // Get the file from the dropzone request - file, info, err := ctx.FormFile("file") - if err != nil { - ctx.StatusCode(iris.StatusInternalServerError) - ctx.Application().Logger().Warnf("Error while uploading: %v", err.Error()) - return - } - - defer file.Close() - fname := info.Filename - - // Create a file with the same name - // assuming that you have a folder named 'uploads' - out, err := os.OpenFile(uploadsDir+fname, - os.O_WRONLY|os.O_CREATE, 0666) - - if err != nil { - ctx.StatusCode(iris.StatusInternalServerError) - ctx.Application().Logger().Warnf("Error while preparing the new file: %v", err.Error()) - return - } - defer out.Close() - - io.Copy(out, file) - - // optionally, add that file to the list in order to be visible when refresh. - uploadedFile := files.add(fname, info.Size) - go files.createThumbnail(uploadedFile) - }) - - // start the server at http://localhost:8080 - app.Listen(":8080") -} -``` - -## Modify the Client side - -Copy content below to "./views/upload.html". We will go through modifications individually. - -```html - - - - - DropzoneJS Uploader - - - - - - - - - - - - - - - -
-
- - -
-
- - - -``` - -1. We added Jquery library into our page. This actually not for DropzoneJs directly. We are using Jquery's ajax function **$.get** only. You will see below -2. We added an ID element (my-dropzone) to the form. This is needed because we need to pass configuration values to Dropzone. And to do it, we must have an ID reference of it. So that we can configure it by assigning values to Dropzone.options.myDropzone. A lot of people face confusion when configuring Dropzone. To put it in a simple way. Do not take Dropzone as a Jquery plugin, it has its own syntax and you need to follow it. -3. This starts the main part of modification. What we did here is to pass a function to listen to Dropzone's init event. This event is called when Dropzone is initialized. -4. Retrieve files details from the new "/uploads" via ajax. -5. Create mockFile using values from server. mockFile is simply JavaScript objects with properties of name and size. Then we call Dropzone's **addedfile** and **thumbnail** functions explicitly to put existing files to Dropzone upload area and generate its thumbnail. - -### Running the server - -Open the terminal at the current project's folder and execute: - -```bash -$ go run main.go -Now listening on: http://localhost:8080 -Application started. Press CTRL+C to shut down. -``` - -If you have done it successfully. Now go and upload some images and reload the upload page. Already uploaded files should auto display in Dropzone area. - -![with uploaded files screenshot](with_files.png) - -## References - -- http://www.dropzonejs.com/#server-side-implementation -- https://www.startutorial.com/articles/view/how-to-build-a-file-upload-form-using-dropzonejs-and-php -- https://docs.iris-go.com -- https://github.com/kataras/iris/tree/master/_examples/dropzonejs - -## The end - -Hopefully this simple tutorial helped you with your development. -If you like my post, please follow me on [Twitter](https://twitter.com/makismaropoulos) and help spread the word. I need your support to continue. \ No newline at end of file diff --git a/_examples/dropzonejs/folder_structure.png b/_examples/dropzonejs/folder_structure.png deleted file mode 100644 index 2c81637c3411c4d3f5bf2069dc000715917703e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10628 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 S5A2*IP<{IRNwuQ&>;DCtU)Hh! diff --git a/_examples/dropzonejs/meta.yml b/_examples/dropzonejs/meta.yml deleted file mode 100644 index 8b23e948..00000000 --- a/_examples/dropzonejs/meta.yml +++ /dev/null @@ -1,8 +0,0 @@ -Name: DropzoneJS -Articles: - - Title: How to build a file upload form using DropzoneJS and Go - Source: https://medium.com/hackernoon/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991 - Author: https://twitter.com/@kataras - - Title: How to display existing files on server using DropzoneJS and Go - Source: https://medium.com/@kataras/how-to-display-existing-files-on-server-using-dropzonejs-and-go-53e24b57ba19 - Author: https://twitter.com/@kataras \ No newline at end of file diff --git a/_examples/dropzonejs/no_files.png b/_examples/dropzonejs/no_files.png deleted file mode 100644 index 6e4afacb52e81714cc0ea27e2f349d0c264f0e28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31987 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 - */ -@-webkit-keyframes passing-through { - 0% { - opacity: 0; - -webkit-transform: translateY(40px); - -moz-transform: translateY(40px); - -ms-transform: translateY(40px); - -o-transform: translateY(40px); - transform: translateY(40px); } - 30%, 70% { - opacity: 1; - -webkit-transform: translateY(0px); - -moz-transform: translateY(0px); - -ms-transform: translateY(0px); - -o-transform: translateY(0px); - transform: translateY(0px); } - 100% { - opacity: 0; - -webkit-transform: translateY(-40px); - -moz-transform: translateY(-40px); - -ms-transform: translateY(-40px); - -o-transform: translateY(-40px); - transform: translateY(-40px); } } -@-moz-keyframes passing-through { - 0% { - opacity: 0; - -webkit-transform: translateY(40px); - -moz-transform: translateY(40px); - -ms-transform: translateY(40px); - -o-transform: translateY(40px); - transform: translateY(40px); } - 30%, 70% { - opacity: 1; - -webkit-transform: translateY(0px); - -moz-transform: translateY(0px); - -ms-transform: translateY(0px); - -o-transform: translateY(0px); - transform: translateY(0px); } - 100% { - opacity: 0; - -webkit-transform: translateY(-40px); - -moz-transform: translateY(-40px); - -ms-transform: translateY(-40px); - -o-transform: translateY(-40px); - transform: translateY(-40px); } } -@keyframes passing-through { - 0% { - opacity: 0; - -webkit-transform: translateY(40px); - -moz-transform: translateY(40px); - -ms-transform: translateY(40px); - -o-transform: translateY(40px); - transform: translateY(40px); } - 30%, 70% { - opacity: 1; - -webkit-transform: translateY(0px); - -moz-transform: translateY(0px); - -ms-transform: translateY(0px); - -o-transform: translateY(0px); - transform: translateY(0px); } - 100% { - opacity: 0; - -webkit-transform: translateY(-40px); - -moz-transform: translateY(-40px); - -ms-transform: translateY(-40px); - -o-transform: translateY(-40px); - transform: translateY(-40px); } } -@-webkit-keyframes slide-in { - 0% { - opacity: 0; - -webkit-transform: translateY(40px); - -moz-transform: translateY(40px); - -ms-transform: translateY(40px); - -o-transform: translateY(40px); - transform: translateY(40px); } - 30% { - opacity: 1; - -webkit-transform: translateY(0px); - -moz-transform: translateY(0px); - -ms-transform: translateY(0px); - -o-transform: translateY(0px); - transform: translateY(0px); } } -@-moz-keyframes slide-in { - 0% { - opacity: 0; - -webkit-transform: translateY(40px); - -moz-transform: translateY(40px); - -ms-transform: translateY(40px); - -o-transform: translateY(40px); - transform: translateY(40px); } - 30% { - opacity: 1; - -webkit-transform: translateY(0px); - -moz-transform: translateY(0px); - -ms-transform: translateY(0px); - -o-transform: translateY(0px); - transform: translateY(0px); } } -@keyframes slide-in { - 0% { - opacity: 0; - -webkit-transform: translateY(40px); - -moz-transform: translateY(40px); - -ms-transform: translateY(40px); - -o-transform: translateY(40px); - transform: translateY(40px); } - 30% { - opacity: 1; - -webkit-transform: translateY(0px); - -moz-transform: translateY(0px); - -ms-transform: translateY(0px); - -o-transform: translateY(0px); - transform: translateY(0px); } } -@-webkit-keyframes pulse { - 0% { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -ms-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); } - 10% { - -webkit-transform: scale(1.1); - -moz-transform: scale(1.1); - -ms-transform: scale(1.1); - -o-transform: scale(1.1); - transform: scale(1.1); } - 20% { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -ms-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); } } -@-moz-keyframes pulse { - 0% { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -ms-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); } - 10% { - -webkit-transform: scale(1.1); - -moz-transform: scale(1.1); - -ms-transform: scale(1.1); - -o-transform: scale(1.1); - transform: scale(1.1); } - 20% { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -ms-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); } } -@keyframes pulse { - 0% { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -ms-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); } - 10% { - -webkit-transform: scale(1.1); - -moz-transform: scale(1.1); - -ms-transform: scale(1.1); - -o-transform: scale(1.1); - transform: scale(1.1); } - 20% { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -ms-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); } } -.dropzone, .dropzone * { - box-sizing: border-box; } - -.dropzone { - min-height: 150px; - border: 2px solid rgba(0, 0, 0, 0.3); - background: white; - padding: 20px 20px; } - .dropzone.dz-clickable { - cursor: pointer; } - .dropzone.dz-clickable * { - cursor: default; } - .dropzone.dz-clickable .dz-message, .dropzone.dz-clickable .dz-message * { - cursor: pointer; } - .dropzone.dz-started .dz-message { - display: none; } - .dropzone.dz-drag-hover { - border-style: solid; } - .dropzone.dz-drag-hover .dz-message { - opacity: 0.5; } - .dropzone .dz-message { - text-align: center; - margin: 2em 0; } - .dropzone .dz-preview { - position: relative; - display: inline-block; - vertical-align: top; - margin: 16px; - min-height: 100px; } - .dropzone .dz-preview:hover { - z-index: 1000; } - .dropzone .dz-preview:hover .dz-details { - opacity: 1; } - .dropzone .dz-preview.dz-file-preview .dz-image { - border-radius: 20px; - background: #999; - background: linear-gradient(to bottom, #eee, #ddd); } - .dropzone .dz-preview.dz-file-preview .dz-details { - opacity: 1; } - .dropzone .dz-preview.dz-image-preview { - background: white; } - .dropzone .dz-preview.dz-image-preview .dz-details { - -webkit-transition: opacity 0.2s linear; - -moz-transition: opacity 0.2s linear; - -ms-transition: opacity 0.2s linear; - -o-transition: opacity 0.2s linear; - transition: opacity 0.2s linear; } - .dropzone .dz-preview .dz-remove { - font-size: 14px; - text-align: center; - display: block; - cursor: pointer; - border: none; } - .dropzone .dz-preview .dz-remove:hover { - text-decoration: underline; } - .dropzone .dz-preview:hover .dz-details { - opacity: 1; } - .dropzone .dz-preview .dz-details { - z-index: 20; - position: absolute; - top: 0; - left: 0; - opacity: 0; - font-size: 13px; - min-width: 100%; - max-width: 100%; - padding: 2em 1em; - text-align: center; - color: rgba(0, 0, 0, 0.9); - line-height: 150%; } - .dropzone .dz-preview .dz-details .dz-size { - margin-bottom: 1em; - font-size: 16px; } - .dropzone .dz-preview .dz-details .dz-filename { - white-space: nowrap; } - .dropzone .dz-preview .dz-details .dz-filename:hover span { - border: 1px solid rgba(200, 200, 200, 0.8); - background-color: rgba(255, 255, 255, 0.8); } - .dropzone .dz-preview .dz-details .dz-filename:not(:hover) { - overflow: hidden; - text-overflow: ellipsis; } - .dropzone .dz-preview .dz-details .dz-filename:not(:hover) span { - border: 1px solid transparent; } - .dropzone .dz-preview .dz-details .dz-filename span, .dropzone .dz-preview .dz-details .dz-size span { - background-color: rgba(255, 255, 255, 0.4); - padding: 0 0.4em; - border-radius: 3px; } - .dropzone .dz-preview:hover .dz-image img { - -webkit-transform: scale(1.05, 1.05); - -moz-transform: scale(1.05, 1.05); - -ms-transform: scale(1.05, 1.05); - -o-transform: scale(1.05, 1.05); - transform: scale(1.05, 1.05); - -webkit-filter: blur(8px); - filter: blur(8px); } - .dropzone .dz-preview .dz-image { - border-radius: 20px; - overflow: hidden; - width: 120px; - height: 120px; - position: relative; - display: block; - z-index: 10; } - .dropzone .dz-preview .dz-image img { - display: block; } - .dropzone .dz-preview.dz-success .dz-success-mark { - -webkit-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); - -moz-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); - -ms-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); - -o-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); - animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); } - .dropzone .dz-preview.dz-error .dz-error-mark { - opacity: 1; - -webkit-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); - -moz-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); - -ms-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); - -o-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); - animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); } - .dropzone .dz-preview .dz-success-mark, .dropzone .dz-preview .dz-error-mark { - pointer-events: none; - opacity: 0; - z-index: 500; - position: absolute; - display: block; - top: 50%; - left: 50%; - margin-left: -27px; - margin-top: -27px; } - .dropzone .dz-preview .dz-success-mark svg, .dropzone .dz-preview .dz-error-mark svg { - display: block; - width: 54px; - height: 54px; } - .dropzone .dz-preview.dz-processing .dz-progress { - opacity: 1; - -webkit-transition: all 0.2s linear; - -moz-transition: all 0.2s linear; - -ms-transition: all 0.2s linear; - -o-transition: all 0.2s linear; - transition: all 0.2s linear; } - .dropzone .dz-preview.dz-complete .dz-progress { - opacity: 0; - -webkit-transition: opacity 0.4s ease-in; - -moz-transition: opacity 0.4s ease-in; - -ms-transition: opacity 0.4s ease-in; - -o-transition: opacity 0.4s ease-in; - transition: opacity 0.4s ease-in; } - .dropzone .dz-preview:not(.dz-processing) .dz-progress { - -webkit-animation: pulse 6s ease infinite; - -moz-animation: pulse 6s ease infinite; - -ms-animation: pulse 6s ease infinite; - -o-animation: pulse 6s ease infinite; - animation: pulse 6s ease infinite; } - .dropzone .dz-preview .dz-progress { - opacity: 1; - z-index: 1000; - pointer-events: none; - position: absolute; - height: 16px; - left: 50%; - top: 50%; - margin-top: -8px; - width: 80px; - margin-left: -40px; - background: rgba(255, 255, 255, 0.9); - -webkit-transform: scale(1); - border-radius: 8px; - overflow: hidden; } - .dropzone .dz-preview .dz-progress .dz-upload { - background: #333; - background: linear-gradient(to bottom, #666, #444); - position: absolute; - top: 0; - left: 0; - bottom: 0; - width: 0; - -webkit-transition: width 300ms ease-in-out; - -moz-transition: width 300ms ease-in-out; - -ms-transition: width 300ms ease-in-out; - -o-transition: width 300ms ease-in-out; - transition: width 300ms ease-in-out; } - .dropzone .dz-preview.dz-error .dz-error-message { - display: block; } - .dropzone .dz-preview.dz-error:hover .dz-error-message { - opacity: 1; - pointer-events: auto; } - .dropzone .dz-preview .dz-error-message { - pointer-events: none; - z-index: 1000; - position: absolute; - display: block; - display: none; - opacity: 0; - -webkit-transition: opacity 0.3s ease; - -moz-transition: opacity 0.3s ease; - -ms-transition: opacity 0.3s ease; - -o-transition: opacity 0.3s ease; - transition: opacity 0.3s ease; - border-radius: 8px; - font-size: 13px; - top: 130px; - left: -10px; - width: 140px; - background: #be2626; - background: linear-gradient(to bottom, #be2626, #a92222); - padding: 0.5em 1.2em; - color: white; } - .dropzone .dz-preview .dz-error-message:after { - content: ''; - position: absolute; - top: -6px; - left: 64px; - width: 0; - height: 0; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-bottom: 6px solid #be2626; } diff --git a/_examples/dropzonejs/src/public/js/dropzone.js b/_examples/dropzonejs/src/public/js/dropzone.js deleted file mode 100644 index 1bf9a7fe..00000000 --- a/_examples/dropzonejs/src/public/js/dropzone.js +++ /dev/null @@ -1,2052 +0,0 @@ - -/* - * - * More info at [www.dropzonejs.com](http://www.dropzonejs.com) - * - * Copyright (c) 2012, Matias Meno - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -(function() { - var Dropzone, Emitter, ExifRestore, camelize, contentLoaded, detectVerticalSquash, drawImageIOSFix, noop, without, - slice = [].slice, - extend1 = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, - hasProp = {}.hasOwnProperty; - - noop = function() {}; - - Emitter = (function() { - function Emitter() {} - - Emitter.prototype.addEventListener = Emitter.prototype.on; - - Emitter.prototype.on = function(event, fn) { - this._callbacks = this._callbacks || {}; - if (!this._callbacks[event]) { - this._callbacks[event] = []; - } - this._callbacks[event].push(fn); - return this; - }; - - Emitter.prototype.emit = function() { - var args, callback, callbacks, event, j, len; - event = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; - this._callbacks = this._callbacks || {}; - callbacks = this._callbacks[event]; - if (callbacks) { - for (j = 0, len = callbacks.length; j < len; j++) { - callback = callbacks[j]; - callback.apply(this, args); - } - } - return this; - }; - - Emitter.prototype.removeListener = Emitter.prototype.off; - - Emitter.prototype.removeAllListeners = Emitter.prototype.off; - - Emitter.prototype.removeEventListener = Emitter.prototype.off; - - Emitter.prototype.off = function(event, fn) { - var callback, callbacks, i, j, len; - if (!this._callbacks || arguments.length === 0) { - this._callbacks = {}; - return this; - } - callbacks = this._callbacks[event]; - if (!callbacks) { - return this; - } - if (arguments.length === 1) { - delete this._callbacks[event]; - return this; - } - for (i = j = 0, len = callbacks.length; j < len; i = ++j) { - callback = callbacks[i]; - if (callback === fn) { - callbacks.splice(i, 1); - break; - } - } - return this; - }; - - return Emitter; - - })(); - - Dropzone = (function(superClass) { - var extend, resolveOption; - - extend1(Dropzone, superClass); - - Dropzone.prototype.Emitter = Emitter; - - - /* - This is a list of all available events you can register on a dropzone object. - - You can register an event handler like this: - - dropzone.on("dragEnter", function() { }); - */ - - Dropzone.prototype.events = ["drop", "dragstart", "dragend", "dragenter", "dragover", "dragleave", "addedfile", "addedfiles", "removedfile", "thumbnail", "error", "errormultiple", "processing", "processingmultiple", "uploadprogress", "totaluploadprogress", "sending", "sendingmultiple", "success", "successmultiple", "canceled", "canceledmultiple", "complete", "completemultiple", "reset", "maxfilesexceeded", "maxfilesreached", "queuecomplete"]; - - Dropzone.prototype.defaultOptions = { - url: null, - method: "post", - withCredentials: false, - timeout: 30000, - parallelUploads: 2, - uploadMultiple: false, - maxFilesize: 256, - paramName: "file", - createImageThumbnails: true, - maxThumbnailFilesize: 10, - thumbnailWidth: 120, - thumbnailHeight: 120, - thumbnailMethod: 'crop', - resizeWidth: null, - resizeHeight: null, - resizeMimeType: null, - resizeQuality: 0.8, - resizeMethod: 'contain', - filesizeBase: 1000, - maxFiles: null, - params: {}, - headers: null, - clickable: true, - ignoreHiddenFiles: true, - acceptedFiles: null, - acceptedMimeTypes: null, - autoProcessQueue: true, - autoQueue: true, - addRemoveLinks: false, - previewsContainer: null, - hiddenInputContainer: "body", - capture: null, - renameFilename: null, - renameFile: null, - forceFallback: false, - dictDefaultMessage: "Drop files here to upload", - dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.", - dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.", - dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.", - dictInvalidFileType: "You can't upload files of this type.", - dictResponseError: "Server responded with {{statusCode}} code.", - dictCancelUpload: "Cancel upload", - dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?", - dictRemoveFile: "Remove file", - dictRemoveFileConfirmation: null, - dictMaxFilesExceeded: "You can not upload any more files.", - dictFileSizeUnits: { - tb: "TB", - gb: "GB", - mb: "MB", - kb: "KB", - b: "b" - }, - init: function() { - return noop; - }, - accept: function(file, done) { - return done(); - }, - fallback: function() { - var child, j, len, messageElement, ref, span; - this.element.className = this.element.className + " dz-browser-not-supported"; - ref = this.element.getElementsByTagName("div"); - for (j = 0, len = ref.length; j < len; j++) { - child = ref[j]; - if (/(^| )dz-message($| )/.test(child.className)) { - messageElement = child; - child.className = "dz-message"; - continue; - } - } - if (!messageElement) { - messageElement = Dropzone.createElement("
"); - this.element.appendChild(messageElement); - } - span = messageElement.getElementsByTagName("span")[0]; - if (span) { - if (span.textContent != null) { - span.textContent = this.options.dictFallbackMessage; - } else if (span.innerText != null) { - span.innerText = this.options.dictFallbackMessage; - } - } - return this.element.appendChild(this.getFallbackForm()); - }, - resize: function(file, width, height, resizeMethod) { - var info, srcRatio, trgRatio; - info = { - srcX: 0, - srcY: 0, - srcWidth: file.width, - srcHeight: file.height - }; - srcRatio = file.width / file.height; - if ((width == null) && (height == null)) { - width = info.srcWidth; - height = info.srcHeight; - } else if (width == null) { - width = height * srcRatio; - } else if (height == null) { - height = width / srcRatio; - } - width = Math.min(width, info.srcWidth); - height = Math.min(height, info.srcHeight); - trgRatio = width / height; - if (info.srcWidth > width || info.srcHeight > height) { - if (resizeMethod === 'crop') { - if (srcRatio > trgRatio) { - info.srcHeight = file.height; - info.srcWidth = info.srcHeight * trgRatio; - } else { - info.srcWidth = file.width; - info.srcHeight = info.srcWidth / trgRatio; - } - } else if (resizeMethod === 'contain') { - if (srcRatio > trgRatio) { - height = width / srcRatio; - } else { - width = height * srcRatio; - } - } else { - throw new Error("Unknown resizeMethod '" + resizeMethod + "'"); - } - } - info.srcX = (file.width - info.srcWidth) / 2; - info.srcY = (file.height - info.srcHeight) / 2; - info.trgWidth = width; - info.trgHeight = height; - return info; - }, - transformFile: function(file, done) { - if ((this.options.resizeWidth || this.options.resizeHeight) && file.type.match(/image.*/)) { - return this.resizeImage(file, this.options.resizeWidth, this.options.resizeHeight, this.options.resizeMethod, done); - } else { - return done(file); - } - }, - previewTemplate: "
\n
\n
\n
\n
\n
\n
\n
\n
\n \n Check\n \n \n \n \n \n
\n
\n \n Error\n \n \n \n \n \n \n \n
\n
", - - /* - Those functions register themselves to the events on init and handle all - the user interface specific stuff. Overwriting them won't break the upload - but can break the way it's displayed. - You can overwrite them if you don't like the default behavior. If you just - want to add an additional event handler, register it on the dropzone object - and don't overwrite those options. - */ - drop: function(e) { - return this.element.classList.remove("dz-drag-hover"); - }, - dragstart: noop, - dragend: function(e) { - return this.element.classList.remove("dz-drag-hover"); - }, - dragenter: function(e) { - return this.element.classList.add("dz-drag-hover"); - }, - dragover: function(e) { - return this.element.classList.add("dz-drag-hover"); - }, - dragleave: function(e) { - return this.element.classList.remove("dz-drag-hover"); - }, - paste: noop, - reset: function() { - return this.element.classList.remove("dz-started"); - }, - addedfile: function(file) { - var j, k, l, len, len1, len2, node, ref, ref1, ref2, removeFileEvent, removeLink, results; - if (this.element === this.previewsContainer) { - this.element.classList.add("dz-started"); - } - if (this.previewsContainer) { - file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim()); - file.previewTemplate = file.previewElement; - this.previewsContainer.appendChild(file.previewElement); - ref = file.previewElement.querySelectorAll("[data-dz-name]"); - for (j = 0, len = ref.length; j < len; j++) { - node = ref[j]; - node.textContent = file.name; - } - ref1 = file.previewElement.querySelectorAll("[data-dz-size]"); - for (k = 0, len1 = ref1.length; k < len1; k++) { - node = ref1[k]; - node.innerHTML = this.filesize(file.size); - } - if (this.options.addRemoveLinks) { - file._removeLink = Dropzone.createElement("
" + this.options.dictRemoveFile + ""); - file.previewElement.appendChild(file._removeLink); - } - removeFileEvent = (function(_this) { - return function(e) { - e.preventDefault(); - e.stopPropagation(); - if (file.status === Dropzone.UPLOADING) { - return Dropzone.confirm(_this.options.dictCancelUploadConfirmation, function() { - return _this.removeFile(file); - }); - } else { - if (_this.options.dictRemoveFileConfirmation) { - return Dropzone.confirm(_this.options.dictRemoveFileConfirmation, function() { - return _this.removeFile(file); - }); - } else { - return _this.removeFile(file); - } - } - }; - })(this); - ref2 = file.previewElement.querySelectorAll("[data-dz-remove]"); - results = []; - for (l = 0, len2 = ref2.length; l < len2; l++) { - removeLink = ref2[l]; - results.push(removeLink.addEventListener("click", removeFileEvent)); - } - return results; - } - }, - removedfile: function(file) { - var ref; - if (file.previewElement) { - if ((ref = file.previewElement) != null) { - ref.parentNode.removeChild(file.previewElement); - } - } - return this._updateMaxFilesReachedClass(); - }, - thumbnail: function(file, dataUrl) { - var j, len, ref, thumbnailElement; - if (file.previewElement) { - file.previewElement.classList.remove("dz-file-preview"); - ref = file.previewElement.querySelectorAll("[data-dz-thumbnail]"); - for (j = 0, len = ref.length; j < len; j++) { - thumbnailElement = ref[j]; - thumbnailElement.alt = file.name; - thumbnailElement.src = dataUrl; - } - return setTimeout(((function(_this) { - return function() { - return file.previewElement.classList.add("dz-image-preview"); - }; - })(this)), 1); - } - }, - error: function(file, message) { - var j, len, node, ref, results; - if (file.previewElement) { - file.previewElement.classList.add("dz-error"); - if (typeof message !== "String" && message.error) { - message = message.error; - } - ref = file.previewElement.querySelectorAll("[data-dz-errormessage]"); - results = []; - for (j = 0, len = ref.length; j < len; j++) { - node = ref[j]; - results.push(node.textContent = message); - } - return results; - } - }, - errormultiple: noop, - processing: function(file) { - if (file.previewElement) { - file.previewElement.classList.add("dz-processing"); - if (file._removeLink) { - return file._removeLink.textContent = this.options.dictCancelUpload; - } - } - }, - processingmultiple: noop, - uploadprogress: function(file, progress, bytesSent) { - var j, len, node, ref, results; - if (file.previewElement) { - ref = file.previewElement.querySelectorAll("[data-dz-uploadprogress]"); - results = []; - for (j = 0, len = ref.length; j < len; j++) { - node = ref[j]; - if (node.nodeName === 'PROGRESS') { - results.push(node.value = progress); - } else { - results.push(node.style.width = progress + "%"); - } - } - return results; - } - }, - totaluploadprogress: noop, - sending: noop, - sendingmultiple: noop, - success: function(file) { - if (file.previewElement) { - return file.previewElement.classList.add("dz-success"); - } - }, - successmultiple: noop, - canceled: function(file) { - return this.emit("error", file, "Upload canceled."); - }, - canceledmultiple: noop, - complete: function(file) { - if (file._removeLink) { - file._removeLink.textContent = this.options.dictRemoveFile; - } - if (file.previewElement) { - return file.previewElement.classList.add("dz-complete"); - } - }, - completemultiple: noop, - maxfilesexceeded: noop, - maxfilesreached: noop, - queuecomplete: noop, - addedfiles: noop - }; - - extend = function() { - var j, key, len, object, objects, target, val; - target = arguments[0], objects = 2 <= arguments.length ? slice.call(arguments, 1) : []; - for (j = 0, len = objects.length; j < len; j++) { - object = objects[j]; - for (key in object) { - val = object[key]; - target[key] = val; - } - } - return target; - }; - - function Dropzone(element1, options) { - var elementOptions, fallback, ref; - this.element = element1; - this.version = Dropzone.version; - this.defaultOptions.previewTemplate = this.defaultOptions.previewTemplate.replace(/\n*/g, ""); - this.clickableElements = []; - this.listeners = []; - this.files = []; - if (typeof this.element === "string") { - this.element = document.querySelector(this.element); - } - if (!(this.element && (this.element.nodeType != null))) { - throw new Error("Invalid dropzone element."); - } - if (this.element.dropzone) { - throw new Error("Dropzone already attached."); - } - Dropzone.instances.push(this); - this.element.dropzone = this; - elementOptions = (ref = Dropzone.optionsForElement(this.element)) != null ? ref : {}; - this.options = extend({}, this.defaultOptions, elementOptions, options != null ? options : {}); - if (this.options.forceFallback || !Dropzone.isBrowserSupported()) { - return this.options.fallback.call(this); - } - if (this.options.url == null) { - this.options.url = this.element.getAttribute("action"); - } - if (!this.options.url) { - throw new Error("No URL provided."); - } - if (this.options.acceptedFiles && this.options.acceptedMimeTypes) { - throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated."); - } - if (this.options.acceptedMimeTypes) { - this.options.acceptedFiles = this.options.acceptedMimeTypes; - delete this.options.acceptedMimeTypes; - } - if (this.options.renameFilename != null) { - this.options.renameFile = (function(_this) { - return function(file) { - return _this.options.renameFilename.call(_this, file.name, file); - }; - })(this); - } - this.options.method = this.options.method.toUpperCase(); - if ((fallback = this.getExistingFallback()) && fallback.parentNode) { - fallback.parentNode.removeChild(fallback); - } - if (this.options.previewsContainer !== false) { - if (this.options.previewsContainer) { - this.previewsContainer = Dropzone.getElement(this.options.previewsContainer, "previewsContainer"); - } else { - this.previewsContainer = this.element; - } - } - if (this.options.clickable) { - if (this.options.clickable === true) { - this.clickableElements = [this.element]; - } else { - this.clickableElements = Dropzone.getElements(this.options.clickable, "clickable"); - } - } - this.init(); - } - - Dropzone.prototype.getAcceptedFiles = function() { - var file, j, len, ref, results; - ref = this.files; - results = []; - for (j = 0, len = ref.length; j < len; j++) { - file = ref[j]; - if (file.accepted) { - results.push(file); - } - } - return results; - }; - - Dropzone.prototype.getRejectedFiles = function() { - var file, j, len, ref, results; - ref = this.files; - results = []; - for (j = 0, len = ref.length; j < len; j++) { - file = ref[j]; - if (!file.accepted) { - results.push(file); - } - } - return results; - }; - - Dropzone.prototype.getFilesWithStatus = function(status) { - var file, j, len, ref, results; - ref = this.files; - results = []; - for (j = 0, len = ref.length; j < len; j++) { - file = ref[j]; - if (file.status === status) { - results.push(file); - } - } - return results; - }; - - Dropzone.prototype.getQueuedFiles = function() { - return this.getFilesWithStatus(Dropzone.QUEUED); - }; - - Dropzone.prototype.getUploadingFiles = function() { - return this.getFilesWithStatus(Dropzone.UPLOADING); - }; - - Dropzone.prototype.getAddedFiles = function() { - return this.getFilesWithStatus(Dropzone.ADDED); - }; - - Dropzone.prototype.getActiveFiles = function() { - var file, j, len, ref, results; - ref = this.files; - results = []; - for (j = 0, len = ref.length; j < len; j++) { - file = ref[j]; - if (file.status === Dropzone.UPLOADING || file.status === Dropzone.QUEUED) { - results.push(file); - } - } - return results; - }; - - Dropzone.prototype.init = function() { - var eventName, j, len, noPropagation, ref, ref1, setupHiddenFileInput; - if (this.element.tagName === "form") { - this.element.setAttribute("enctype", "multipart/form-data"); - } - if (this.element.classList.contains("dropzone") && !this.element.querySelector(".dz-message")) { - this.element.appendChild(Dropzone.createElement("
" + this.options.dictDefaultMessage + "
")); - } - if (this.clickableElements.length) { - setupHiddenFileInput = (function(_this) { - return function() { - if (_this.hiddenFileInput) { - _this.hiddenFileInput.parentNode.removeChild(_this.hiddenFileInput); - } - _this.hiddenFileInput = document.createElement("input"); - _this.hiddenFileInput.setAttribute("type", "file"); - if ((_this.options.maxFiles == null) || _this.options.maxFiles > 1) { - _this.hiddenFileInput.setAttribute("multiple", "multiple"); - } - _this.hiddenFileInput.className = "dz-hidden-input"; - if (_this.options.acceptedFiles != null) { - _this.hiddenFileInput.setAttribute("accept", _this.options.acceptedFiles); - } - if (_this.options.capture != null) { - _this.hiddenFileInput.setAttribute("capture", _this.options.capture); - } - _this.hiddenFileInput.style.visibility = "hidden"; - _this.hiddenFileInput.style.position = "absolute"; - _this.hiddenFileInput.style.top = "0"; - _this.hiddenFileInput.style.left = "0"; - _this.hiddenFileInput.style.height = "0"; - _this.hiddenFileInput.style.width = "0"; - document.querySelector(_this.options.hiddenInputContainer).appendChild(_this.hiddenFileInput); - return _this.hiddenFileInput.addEventListener("change", function() { - var file, files, j, len; - files = _this.hiddenFileInput.files; - if (files.length) { - for (j = 0, len = files.length; j < len; j++) { - file = files[j]; - _this.addFile(file); - } - } - _this.emit("addedfiles", files); - return setupHiddenFileInput(); - }); - }; - })(this); - setupHiddenFileInput(); - } - this.URL = (ref = window.URL) != null ? ref : window.webkitURL; - ref1 = this.events; - for (j = 0, len = ref1.length; j < len; j++) { - eventName = ref1[j]; - this.on(eventName, this.options[eventName]); - } - this.on("uploadprogress", (function(_this) { - return function() { - return _this.updateTotalUploadProgress(); - }; - })(this)); - this.on("removedfile", (function(_this) { - return function() { - return _this.updateTotalUploadProgress(); - }; - })(this)); - this.on("canceled", (function(_this) { - return function(file) { - return _this.emit("complete", file); - }; - })(this)); - this.on("complete", (function(_this) { - return function(file) { - if (_this.getAddedFiles().length === 0 && _this.getUploadingFiles().length === 0 && _this.getQueuedFiles().length === 0) { - return setTimeout((function() { - return _this.emit("queuecomplete"); - }), 0); - } - }; - })(this)); - noPropagation = function(e) { - e.stopPropagation(); - if (e.preventDefault) { - return e.preventDefault(); - } else { - return e.returnValue = false; - } - }; - this.listeners = [ - { - element: this.element, - events: { - "dragstart": (function(_this) { - return function(e) { - return _this.emit("dragstart", e); - }; - })(this), - "dragenter": (function(_this) { - return function(e) { - noPropagation(e); - return _this.emit("dragenter", e); - }; - })(this), - "dragover": (function(_this) { - return function(e) { - var efct; - try { - efct = e.dataTransfer.effectAllowed; - } catch (undefined) {} - e.dataTransfer.dropEffect = 'move' === efct || 'linkMove' === efct ? 'move' : 'copy'; - noPropagation(e); - return _this.emit("dragover", e); - }; - })(this), - "dragleave": (function(_this) { - return function(e) { - return _this.emit("dragleave", e); - }; - })(this), - "drop": (function(_this) { - return function(e) { - noPropagation(e); - return _this.drop(e); - }; - })(this), - "dragend": (function(_this) { - return function(e) { - return _this.emit("dragend", e); - }; - })(this) - } - } - ]; - this.clickableElements.forEach((function(_this) { - return function(clickableElement) { - return _this.listeners.push({ - element: clickableElement, - events: { - "click": function(evt) { - if ((clickableElement !== _this.element) || (evt.target === _this.element || Dropzone.elementInside(evt.target, _this.element.querySelector(".dz-message")))) { - _this.hiddenFileInput.click(); - } - return true; - } - } - }); - }; - })(this)); - this.enable(); - return this.options.init.call(this); - }; - - Dropzone.prototype.destroy = function() { - var ref; - this.disable(); - this.removeAllFiles(true); - if ((ref = this.hiddenFileInput) != null ? ref.parentNode : void 0) { - this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput); - this.hiddenFileInput = null; - } - delete this.element.dropzone; - return Dropzone.instances.splice(Dropzone.instances.indexOf(this), 1); - }; - - Dropzone.prototype.updateTotalUploadProgress = function() { - var activeFiles, file, j, len, ref, totalBytes, totalBytesSent, totalUploadProgress; - totalBytesSent = 0; - totalBytes = 0; - activeFiles = this.getActiveFiles(); - if (activeFiles.length) { - ref = this.getActiveFiles(); - for (j = 0, len = ref.length; j < len; j++) { - file = ref[j]; - totalBytesSent += file.upload.bytesSent; - totalBytes += file.upload.total; - } - totalUploadProgress = 100 * totalBytesSent / totalBytes; - } else { - totalUploadProgress = 100; - } - return this.emit("totaluploadprogress", totalUploadProgress, totalBytes, totalBytesSent); - }; - - Dropzone.prototype._getParamName = function(n) { - if (typeof this.options.paramName === "function") { - return this.options.paramName(n); - } else { - return "" + this.options.paramName + (this.options.uploadMultiple ? "[" + n + "]" : ""); - } - }; - - Dropzone.prototype._renameFile = function(file) { - if (typeof this.options.renameFile !== "function") { - return file.name; - } - return this.options.renameFile(file); - }; - - Dropzone.prototype.getFallbackForm = function() { - var existingFallback, fields, fieldsString, form; - if (existingFallback = this.getExistingFallback()) { - return existingFallback; - } - fieldsString = "
"; - if (this.options.dictFallbackText) { - fieldsString += "

" + this.options.dictFallbackText + "

"; - } - fieldsString += "
"; - fields = Dropzone.createElement(fieldsString); - if (this.element.tagName !== "FORM") { - form = Dropzone.createElement("
"); - form.appendChild(fields); - } else { - this.element.setAttribute("enctype", "multipart/form-data"); - this.element.setAttribute("method", this.options.method); - } - return form != null ? form : fields; - }; - - Dropzone.prototype.getExistingFallback = function() { - var fallback, getFallback, j, len, ref, tagName; - getFallback = function(elements) { - var el, j, len; - for (j = 0, len = elements.length; j < len; j++) { - el = elements[j]; - if (/(^| )fallback($| )/.test(el.className)) { - return el; - } - } - }; - ref = ["div", "form"]; - for (j = 0, len = ref.length; j < len; j++) { - tagName = ref[j]; - if (fallback = getFallback(this.element.getElementsByTagName(tagName))) { - return fallback; - } - } - }; - - Dropzone.prototype.setupEventListeners = function() { - var elementListeners, event, j, len, listener, ref, results; - ref = this.listeners; - results = []; - for (j = 0, len = ref.length; j < len; j++) { - elementListeners = ref[j]; - results.push((function() { - var ref1, results1; - ref1 = elementListeners.events; - results1 = []; - for (event in ref1) { - listener = ref1[event]; - results1.push(elementListeners.element.addEventListener(event, listener, false)); - } - return results1; - })()); - } - return results; - }; - - Dropzone.prototype.removeEventListeners = function() { - var elementListeners, event, j, len, listener, ref, results; - ref = this.listeners; - results = []; - for (j = 0, len = ref.length; j < len; j++) { - elementListeners = ref[j]; - results.push((function() { - var ref1, results1; - ref1 = elementListeners.events; - results1 = []; - for (event in ref1) { - listener = ref1[event]; - results1.push(elementListeners.element.removeEventListener(event, listener, false)); - } - return results1; - })()); - } - return results; - }; - - Dropzone.prototype.disable = function() { - var file, j, len, ref, results; - this.clickableElements.forEach(function(element) { - return element.classList.remove("dz-clickable"); - }); - this.removeEventListeners(); - ref = this.files; - results = []; - for (j = 0, len = ref.length; j < len; j++) { - file = ref[j]; - results.push(this.cancelUpload(file)); - } - return results; - }; - - Dropzone.prototype.enable = function() { - this.clickableElements.forEach(function(element) { - return element.classList.add("dz-clickable"); - }); - return this.setupEventListeners(); - }; - - Dropzone.prototype.filesize = function(size) { - var cutoff, i, j, len, selectedSize, selectedUnit, unit, units; - selectedSize = 0; - selectedUnit = "b"; - if (size > 0) { - units = ['tb', 'gb', 'mb', 'kb', 'b']; - for (i = j = 0, len = units.length; j < len; i = ++j) { - unit = units[i]; - cutoff = Math.pow(this.options.filesizeBase, 4 - i) / 10; - if (size >= cutoff) { - selectedSize = size / Math.pow(this.options.filesizeBase, 4 - i); - selectedUnit = unit; - break; - } - } - selectedSize = Math.round(10 * selectedSize) / 10; - } - return "" + selectedSize + " " + this.options.dictFileSizeUnits[selectedUnit]; - }; - - Dropzone.prototype._updateMaxFilesReachedClass = function() { - if ((this.options.maxFiles != null) && this.getAcceptedFiles().length >= this.options.maxFiles) { - if (this.getAcceptedFiles().length === this.options.maxFiles) { - this.emit('maxfilesreached', this.files); - } - return this.element.classList.add("dz-max-files-reached"); - } else { - return this.element.classList.remove("dz-max-files-reached"); - } - }; - - Dropzone.prototype.drop = function(e) { - var files, items; - if (!e.dataTransfer) { - return; - } - this.emit("drop", e); - files = e.dataTransfer.files; - this.emit("addedfiles", files); - if (files.length) { - items = e.dataTransfer.items; - if (items && items.length && (items[0].webkitGetAsEntry != null)) { - this._addFilesFromItems(items); - } else { - this.handleFiles(files); - } - } - }; - - Dropzone.prototype.paste = function(e) { - var items, ref; - if ((e != null ? (ref = e.clipboardData) != null ? ref.items : void 0 : void 0) == null) { - return; - } - this.emit("paste", e); - items = e.clipboardData.items; - if (items.length) { - return this._addFilesFromItems(items); - } - }; - - Dropzone.prototype.handleFiles = function(files) { - var file, j, len, results; - results = []; - for (j = 0, len = files.length; j < len; j++) { - file = files[j]; - results.push(this.addFile(file)); - } - return results; - }; - - Dropzone.prototype._addFilesFromItems = function(items) { - var entry, item, j, len, results; - results = []; - for (j = 0, len = items.length; j < len; j++) { - item = items[j]; - if ((item.webkitGetAsEntry != null) && (entry = item.webkitGetAsEntry())) { - if (entry.isFile) { - results.push(this.addFile(item.getAsFile())); - } else if (entry.isDirectory) { - results.push(this._addFilesFromDirectory(entry, entry.name)); - } else { - results.push(void 0); - } - } else if (item.getAsFile != null) { - if ((item.kind == null) || item.kind === "file") { - results.push(this.addFile(item.getAsFile())); - } else { - results.push(void 0); - } - } else { - results.push(void 0); - } - } - return results; - }; - - Dropzone.prototype._addFilesFromDirectory = function(directory, path) { - var dirReader, errorHandler, readEntries; - dirReader = directory.createReader(); - errorHandler = function(error) { - return typeof console !== "undefined" && console !== null ? typeof console.log === "function" ? console.log(error) : void 0 : void 0; - }; - readEntries = (function(_this) { - return function() { - return dirReader.readEntries(function(entries) { - var entry, j, len; - if (entries.length > 0) { - for (j = 0, len = entries.length; j < len; j++) { - entry = entries[j]; - if (entry.isFile) { - entry.file(function(file) { - if (_this.options.ignoreHiddenFiles && file.name.substring(0, 1) === '.') { - return; - } - file.fullPath = path + "/" + file.name; - return _this.addFile(file); - }); - } else if (entry.isDirectory) { - _this._addFilesFromDirectory(entry, path + "/" + entry.name); - } - } - readEntries(); - } - return null; - }, errorHandler); - }; - })(this); - return readEntries(); - }; - - Dropzone.prototype.accept = function(file, done) { - if (file.size > this.options.maxFilesize * 1024 * 1024) { - return done(this.options.dictFileTooBig.replace("{{filesize}}", Math.round(file.size / 1024 / 10.24) / 100).replace("{{maxFilesize}}", this.options.maxFilesize)); - } else if (!Dropzone.isValidFile(file, this.options.acceptedFiles)) { - return done(this.options.dictInvalidFileType); - } else if ((this.options.maxFiles != null) && this.getAcceptedFiles().length >= this.options.maxFiles) { - done(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}", this.options.maxFiles)); - return this.emit("maxfilesexceeded", file); - } else { - return this.options.accept.call(this, file, done); - } - }; - - Dropzone.prototype.addFile = function(file) { - file.upload = { - progress: 0, - total: file.size, - bytesSent: 0, - filename: this._renameFile(file) - }; - this.files.push(file); - file.status = Dropzone.ADDED; - this.emit("addedfile", file); - this._enqueueThumbnail(file); - return this.accept(file, (function(_this) { - return function(error) { - if (error) { - file.accepted = false; - _this._errorProcessing([file], error); - } else { - file.accepted = true; - if (_this.options.autoQueue) { - _this.enqueueFile(file); - } - } - return _this._updateMaxFilesReachedClass(); - }; - })(this)); - }; - - Dropzone.prototype.enqueueFiles = function(files) { - var file, j, len; - for (j = 0, len = files.length; j < len; j++) { - file = files[j]; - this.enqueueFile(file); - } - return null; - }; - - Dropzone.prototype.enqueueFile = function(file) { - if (file.status === Dropzone.ADDED && file.accepted === true) { - file.status = Dropzone.QUEUED; - if (this.options.autoProcessQueue) { - return setTimeout(((function(_this) { - return function() { - return _this.processQueue(); - }; - })(this)), 0); - } - } else { - throw new Error("This file can't be queued because it has already been processed or was rejected."); - } - }; - - Dropzone.prototype._thumbnailQueue = []; - - Dropzone.prototype._processingThumbnail = false; - - Dropzone.prototype._enqueueThumbnail = function(file) { - if (this.options.createImageThumbnails && file.type.match(/image.*/) && file.size <= this.options.maxThumbnailFilesize * 1024 * 1024) { - this._thumbnailQueue.push(file); - return setTimeout(((function(_this) { - return function() { - return _this._processThumbnailQueue(); - }; - })(this)), 0); - } - }; - - Dropzone.prototype._processThumbnailQueue = function() { - var file; - if (this._processingThumbnail || this._thumbnailQueue.length === 0) { - return; - } - this._processingThumbnail = true; - file = this._thumbnailQueue.shift(); - return this.createThumbnail(file, this.options.thumbnailWidth, this.options.thumbnailHeight, this.options.thumbnailMethod, true, (function(_this) { - return function(dataUrl) { - _this.emit("thumbnail", file, dataUrl); - _this._processingThumbnail = false; - return _this._processThumbnailQueue(); - }; - })(this)); - }; - - Dropzone.prototype.removeFile = function(file) { - if (file.status === Dropzone.UPLOADING) { - this.cancelUpload(file); - } - this.files = without(this.files, file); - this.emit("removedfile", file); - if (this.files.length === 0) { - return this.emit("reset"); - } - }; - - Dropzone.prototype.removeAllFiles = function(cancelIfNecessary) { - var file, j, len, ref; - if (cancelIfNecessary == null) { - cancelIfNecessary = false; - } - ref = this.files.slice(); - for (j = 0, len = ref.length; j < len; j++) { - file = ref[j]; - if (file.status !== Dropzone.UPLOADING || cancelIfNecessary) { - this.removeFile(file); - } - } - return null; - }; - - Dropzone.prototype.resizeImage = function(file, width, height, resizeMethod, callback) { - return this.createThumbnail(file, width, height, resizeMethod, false, (function(_this) { - return function(dataUrl, canvas) { - var resizeMimeType, resizedDataURL; - if (canvas === null) { - return callback(file); - } else { - resizeMimeType = _this.options.resizeMimeType; - if (resizeMimeType == null) { - resizeMimeType = file.type; - } - resizedDataURL = canvas.toDataURL(resizeMimeType, _this.options.resizeQuality); - if (resizeMimeType === 'image/jpeg' || resizeMimeType === 'image/jpg') { - resizedDataURL = ExifRestore.restore(file.dataURL, resizedDataURL); - } - return callback(Dropzone.dataURItoBlob(resizedDataURL)); - } - }; - })(this)); - }; - - Dropzone.prototype.createThumbnail = function(file, width, height, resizeMethod, fixOrientation, callback) { - var fileReader; - fileReader = new FileReader; - fileReader.onload = (function(_this) { - return function() { - file.dataURL = fileReader.result; - if (file.type === "image/svg+xml") { - if (callback != null) { - callback(fileReader.result); - } - return; - } - return _this.createThumbnailFromUrl(file, width, height, resizeMethod, fixOrientation, callback); - }; - })(this); - return fileReader.readAsDataURL(file); - }; - - Dropzone.prototype.createThumbnailFromUrl = function(file, width, height, resizeMethod, fixOrientation, callback, crossOrigin) { - var img; - img = document.createElement("img"); - if (crossOrigin) { - img.crossOrigin = crossOrigin; - } - img.onload = (function(_this) { - return function() { - var loadExif; - loadExif = function(callback) { - return callback(1); - }; - if ((typeof EXIF !== "undefined" && EXIF !== null) && fixOrientation) { - loadExif = function(callback) { - return EXIF.getData(img, function() { - return callback(EXIF.getTag(this, 'Orientation')); - }); - }; - } - return loadExif(function(orientation) { - var canvas, ctx, ref, ref1, ref2, ref3, resizeInfo, thumbnail; - file.width = img.width; - file.height = img.height; - resizeInfo = _this.options.resize.call(_this, file, width, height, resizeMethod); - canvas = document.createElement("canvas"); - ctx = canvas.getContext("2d"); - canvas.width = resizeInfo.trgWidth; - canvas.height = resizeInfo.trgHeight; - if (orientation > 4) { - canvas.width = resizeInfo.trgHeight; - canvas.height = resizeInfo.trgWidth; - } - switch (orientation) { - case 2: - ctx.translate(canvas.width, 0); - ctx.scale(-1, 1); - break; - case 3: - ctx.translate(canvas.width, canvas.height); - ctx.rotate(Math.PI); - break; - case 4: - ctx.translate(0, canvas.height); - ctx.scale(1, -1); - break; - case 5: - ctx.rotate(0.5 * Math.PI); - ctx.scale(1, -1); - break; - case 6: - ctx.rotate(0.5 * Math.PI); - ctx.translate(0, -canvas.height); - break; - case 7: - ctx.rotate(0.5 * Math.PI); - ctx.translate(canvas.width, -canvas.height); - ctx.scale(-1, 1); - break; - case 8: - ctx.rotate(-0.5 * Math.PI); - ctx.translate(-canvas.width, 0); - } - drawImageIOSFix(ctx, img, (ref = resizeInfo.srcX) != null ? ref : 0, (ref1 = resizeInfo.srcY) != null ? ref1 : 0, resizeInfo.srcWidth, resizeInfo.srcHeight, (ref2 = resizeInfo.trgX) != null ? ref2 : 0, (ref3 = resizeInfo.trgY) != null ? ref3 : 0, resizeInfo.trgWidth, resizeInfo.trgHeight); - thumbnail = canvas.toDataURL("image/png"); - if (callback != null) { - return callback(thumbnail, canvas); - } - }); - }; - })(this); - if (callback != null) { - img.onerror = callback; - } - return img.src = file.dataURL; - }; - - Dropzone.prototype.processQueue = function() { - var i, parallelUploads, processingLength, queuedFiles; - parallelUploads = this.options.parallelUploads; - processingLength = this.getUploadingFiles().length; - i = processingLength; - if (processingLength >= parallelUploads) { - return; - } - queuedFiles = this.getQueuedFiles(); - if (!(queuedFiles.length > 0)) { - return; - } - if (this.options.uploadMultiple) { - return this.processFiles(queuedFiles.slice(0, parallelUploads - processingLength)); - } else { - while (i < parallelUploads) { - if (!queuedFiles.length) { - return; - } - this.processFile(queuedFiles.shift()); - i++; - } - } - }; - - Dropzone.prototype.processFile = function(file) { - return this.processFiles([file]); - }; - - Dropzone.prototype.processFiles = function(files) { - var file, j, len; - for (j = 0, len = files.length; j < len; j++) { - file = files[j]; - file.processing = true; - file.status = Dropzone.UPLOADING; - this.emit("processing", file); - } - if (this.options.uploadMultiple) { - this.emit("processingmultiple", files); - } - return this.uploadFiles(files); - }; - - Dropzone.prototype._getFilesWithXhr = function(xhr) { - var file, files; - return files = (function() { - var j, len, ref, results; - ref = this.files; - results = []; - for (j = 0, len = ref.length; j < len; j++) { - file = ref[j]; - if (file.xhr === xhr) { - results.push(file); - } - } - return results; - }).call(this); - }; - - Dropzone.prototype.cancelUpload = function(file) { - var groupedFile, groupedFiles, j, k, len, len1, ref; - if (file.status === Dropzone.UPLOADING) { - groupedFiles = this._getFilesWithXhr(file.xhr); - for (j = 0, len = groupedFiles.length; j < len; j++) { - groupedFile = groupedFiles[j]; - groupedFile.status = Dropzone.CANCELED; - } - file.xhr.abort(); - for (k = 0, len1 = groupedFiles.length; k < len1; k++) { - groupedFile = groupedFiles[k]; - this.emit("canceled", groupedFile); - } - if (this.options.uploadMultiple) { - this.emit("canceledmultiple", groupedFiles); - } - } else if ((ref = file.status) === Dropzone.ADDED || ref === Dropzone.QUEUED) { - file.status = Dropzone.CANCELED; - this.emit("canceled", file); - if (this.options.uploadMultiple) { - this.emit("canceledmultiple", [file]); - } - } - if (this.options.autoProcessQueue) { - return this.processQueue(); - } - }; - - resolveOption = function() { - var args, option; - option = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; - if (typeof option === 'function') { - return option.apply(this, args); - } - return option; - }; - - Dropzone.prototype.uploadFile = function(file) { - return this.uploadFiles([file]); - }; - - Dropzone.prototype.uploadFiles = function(files) { - var doneCounter, doneFunction, file, formData, handleError, headerName, headerValue, headers, i, input, inputName, inputType, j, k, key, l, len, len1, len2, len3, m, method, o, option, progressObj, ref, ref1, ref2, ref3, ref4, ref5, response, results, updateProgress, url, value, xhr; - xhr = new XMLHttpRequest(); - for (j = 0, len = files.length; j < len; j++) { - file = files[j]; - file.xhr = xhr; - } - method = resolveOption(this.options.method, files); - url = resolveOption(this.options.url, files); - xhr.open(method, url, true); - xhr.timeout = resolveOption(this.options.timeout, files); - xhr.withCredentials = !!this.options.withCredentials; - response = null; - handleError = (function(_this) { - return function() { - var k, len1, results; - results = []; - for (k = 0, len1 = files.length; k < len1; k++) { - file = files[k]; - results.push(_this._errorProcessing(files, response || _this.options.dictResponseError.replace("{{statusCode}}", xhr.status), xhr)); - } - return results; - }; - })(this); - updateProgress = (function(_this) { - return function(e) { - var allFilesFinished, k, l, len1, len2, len3, m, progress, results; - if (e != null) { - progress = 100 * e.loaded / e.total; - for (k = 0, len1 = files.length; k < len1; k++) { - file = files[k]; - file.upload.progress = progress; - file.upload.total = e.total; - file.upload.bytesSent = e.loaded; - } - } else { - allFilesFinished = true; - progress = 100; - for (l = 0, len2 = files.length; l < len2; l++) { - file = files[l]; - if (!(file.upload.progress === 100 && file.upload.bytesSent === file.upload.total)) { - allFilesFinished = false; - } - file.upload.progress = progress; - file.upload.bytesSent = file.upload.total; - } - if (allFilesFinished) { - return; - } - } - results = []; - for (m = 0, len3 = files.length; m < len3; m++) { - file = files[m]; - results.push(_this.emit("uploadprogress", file, progress, file.upload.bytesSent)); - } - return results; - }; - })(this); - xhr.onload = (function(_this) { - return function(e) { - var error1, ref; - if (files[0].status === Dropzone.CANCELED) { - return; - } - if (xhr.readyState !== 4) { - return; - } - if (xhr.responseType !== 'arraybuffer' && xhr.responseType !== 'blob') { - response = xhr.responseText; - if (xhr.getResponseHeader("content-type") && ~xhr.getResponseHeader("content-type").indexOf("application/json")) { - try { - response = JSON.parse(response); - } catch (error1) { - e = error1; - response = "Invalid JSON response from server."; - } - } - } - updateProgress(); - if (!((200 <= (ref = xhr.status) && ref < 300))) { - return handleError(); - } else { - return _this._finished(files, response, e); - } - }; - })(this); - xhr.onerror = (function(_this) { - return function() { - if (files[0].status === Dropzone.CANCELED) { - return; - } - return handleError(); - }; - })(this); - progressObj = (ref = xhr.upload) != null ? ref : xhr; - progressObj.onprogress = updateProgress; - headers = { - "Accept": "application/json", - "Cache-Control": "no-cache", - "X-Requested-With": "XMLHttpRequest" - }; - if (this.options.headers) { - extend(headers, this.options.headers); - } - for (headerName in headers) { - headerValue = headers[headerName]; - if (headerValue) { - xhr.setRequestHeader(headerName, headerValue); - } - } - formData = new FormData(); - if (this.options.params) { - ref1 = this.options.params; - for (key in ref1) { - value = ref1[key]; - formData.append(key, value); - } - } - for (k = 0, len1 = files.length; k < len1; k++) { - file = files[k]; - this.emit("sending", file, xhr, formData); - } - if (this.options.uploadMultiple) { - this.emit("sendingmultiple", files, xhr, formData); - } - if (this.element.tagName === "FORM") { - ref2 = this.element.querySelectorAll("input, textarea, select, button"); - for (l = 0, len2 = ref2.length; l < len2; l++) { - input = ref2[l]; - inputName = input.getAttribute("name"); - inputType = input.getAttribute("type"); - if (input.tagName === "SELECT" && input.hasAttribute("multiple")) { - ref3 = input.options; - for (m = 0, len3 = ref3.length; m < len3; m++) { - option = ref3[m]; - if (option.selected) { - formData.append(inputName, option.value); - } - } - } else if (!inputType || ((ref4 = inputType.toLowerCase()) !== "checkbox" && ref4 !== "radio") || input.checked) { - formData.append(inputName, input.value); - } - } - } - doneCounter = 0; - results = []; - for (i = o = 0, ref5 = files.length - 1; 0 <= ref5 ? o <= ref5 : o >= ref5; i = 0 <= ref5 ? ++o : --o) { - doneFunction = (function(_this) { - return function(file, paramName, fileName) { - return function(transformedFile) { - formData.append(paramName, transformedFile, fileName); - if (++doneCounter === files.length) { - return _this.submitRequest(xhr, formData, files); - } - }; - }; - })(this); - results.push(this.options.transformFile.call(this, files[i], doneFunction(files[i], this._getParamName(i), files[i].upload.filename))); - } - return results; - }; - - Dropzone.prototype.submitRequest = function(xhr, formData, files) { - return xhr.send(formData); - }; - - Dropzone.prototype._finished = function(files, responseText, e) { - var file, j, len; - for (j = 0, len = files.length; j < len; j++) { - file = files[j]; - file.status = Dropzone.SUCCESS; - this.emit("success", file, responseText, e); - this.emit("complete", file); - } - if (this.options.uploadMultiple) { - this.emit("successmultiple", files, responseText, e); - this.emit("completemultiple", files); - } - if (this.options.autoProcessQueue) { - return this.processQueue(); - } - }; - - Dropzone.prototype._errorProcessing = function(files, message, xhr) { - var file, j, len; - for (j = 0, len = files.length; j < len; j++) { - file = files[j]; - file.status = Dropzone.ERROR; - this.emit("error", file, message, xhr); - this.emit("complete", file); - } - if (this.options.uploadMultiple) { - this.emit("errormultiple", files, message, xhr); - this.emit("completemultiple", files); - } - if (this.options.autoProcessQueue) { - return this.processQueue(); - } - }; - - return Dropzone; - - })(Emitter); - - Dropzone.version = "5.1.1"; - - Dropzone.options = {}; - - Dropzone.optionsForElement = function(element) { - if (element.getAttribute("id")) { - return Dropzone.options[camelize(element.getAttribute("id"))]; - } else { - return void 0; - } - }; - - Dropzone.instances = []; - - Dropzone.forElement = function(element) { - if (typeof element === "string") { - element = document.querySelector(element); - } - if ((element != null ? element.dropzone : void 0) == null) { - throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone."); - } - return element.dropzone; - }; - - Dropzone.autoDiscover = true; - - Dropzone.discover = function() { - var checkElements, dropzone, dropzones, j, len, results; - if (document.querySelectorAll) { - dropzones = document.querySelectorAll(".dropzone"); - } else { - dropzones = []; - checkElements = function(elements) { - var el, j, len, results; - results = []; - for (j = 0, len = elements.length; j < len; j++) { - el = elements[j]; - if (/(^| )dropzone($| )/.test(el.className)) { - results.push(dropzones.push(el)); - } else { - results.push(void 0); - } - } - return results; - }; - checkElements(document.getElementsByTagName("div")); - checkElements(document.getElementsByTagName("form")); - } - results = []; - for (j = 0, len = dropzones.length; j < len; j++) { - dropzone = dropzones[j]; - if (Dropzone.optionsForElement(dropzone) !== false) { - results.push(new Dropzone(dropzone)); - } else { - results.push(void 0); - } - } - return results; - }; - - Dropzone.blacklistedBrowsers = [/opera.*Macintosh.*version\/12/i]; - - Dropzone.isBrowserSupported = function() { - var capableBrowser, j, len, ref, regex; - capableBrowser = true; - if (window.File && window.FileReader && window.FileList && window.Blob && window.FormData && document.querySelector) { - if (!("classList" in document.createElement("a"))) { - capableBrowser = false; - } else { - ref = Dropzone.blacklistedBrowsers; - for (j = 0, len = ref.length; j < len; j++) { - regex = ref[j]; - if (regex.test(navigator.userAgent)) { - capableBrowser = false; - continue; - } - } - } - } else { - capableBrowser = false; - } - return capableBrowser; - }; - - Dropzone.dataURItoBlob = function(dataURI) { - var ab, byteString, i, ia, j, mimeString, ref; - byteString = atob(dataURI.split(',')[1]); - mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; - ab = new ArrayBuffer(byteString.length); - ia = new Uint8Array(ab); - for (i = j = 0, ref = byteString.length; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) { - ia[i] = byteString.charCodeAt(i); - } - return new Blob([ab], { - type: mimeString - }); - }; - - without = function(list, rejectedItem) { - var item, j, len, results; - results = []; - for (j = 0, len = list.length; j < len; j++) { - item = list[j]; - if (item !== rejectedItem) { - results.push(item); - } - } - return results; - }; - - camelize = function(str) { - return str.replace(/[\-_](\w)/g, function(match) { - return match.charAt(1).toUpperCase(); - }); - }; - - Dropzone.createElement = function(string) { - var div; - div = document.createElement("div"); - div.innerHTML = string; - return div.childNodes[0]; - }; - - Dropzone.elementInside = function(element, container) { - if (element === container) { - return true; - } - while (element = element.parentNode) { - if (element === container) { - return true; - } - } - return false; - }; - - Dropzone.getElement = function(el, name) { - var element; - if (typeof el === "string") { - element = document.querySelector(el); - } else if (el.nodeType != null) { - element = el; - } - if (element == null) { - throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector or a plain HTML element."); - } - return element; - }; - - Dropzone.getElements = function(els, name) { - var e, el, elements, error1, j, k, len, len1, ref; - if (els instanceof Array) { - elements = []; - try { - for (j = 0, len = els.length; j < len; j++) { - el = els[j]; - elements.push(this.getElement(el, name)); - } - } catch (error1) { - e = error1; - elements = null; - } - } else if (typeof els === "string") { - elements = []; - ref = document.querySelectorAll(els); - for (k = 0, len1 = ref.length; k < len1; k++) { - el = ref[k]; - elements.push(el); - } - } else if (els.nodeType != null) { - elements = [els]; - } - if (!((elements != null) && elements.length)) { - throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector, a plain HTML element or a list of those."); - } - return elements; - }; - - Dropzone.confirm = function(question, accepted, rejected) { - if (window.confirm(question)) { - return accepted(); - } else if (rejected != null) { - return rejected(); - } - }; - - Dropzone.isValidFile = function(file, acceptedFiles) { - var baseMimeType, j, len, mimeType, validType; - if (!acceptedFiles) { - return true; - } - acceptedFiles = acceptedFiles.split(","); - mimeType = file.type; - baseMimeType = mimeType.replace(/\/.*$/, ""); - for (j = 0, len = acceptedFiles.length; j < len; j++) { - validType = acceptedFiles[j]; - validType = validType.trim(); - if (validType.charAt(0) === ".") { - if (file.name.toLowerCase().indexOf(validType.toLowerCase(), file.name.length - validType.length) !== -1) { - return true; - } - } else if (/\/\*$/.test(validType)) { - if (baseMimeType === validType.replace(/\/.*$/, "")) { - return true; - } - } else { - if (mimeType === validType) { - return true; - } - } - } - return false; - }; - - if (typeof jQuery !== "undefined" && jQuery !== null) { - jQuery.fn.dropzone = function(options) { - return this.each(function() { - return new Dropzone(this, options); - }); - }; - } - - if (typeof module !== "undefined" && module !== null) { - module.exports = Dropzone; - } else { - window.Dropzone = Dropzone; - } - - Dropzone.ADDED = "added"; - - Dropzone.QUEUED = "queued"; - - Dropzone.ACCEPTED = Dropzone.QUEUED; - - Dropzone.UPLOADING = "uploading"; - - Dropzone.PROCESSING = Dropzone.UPLOADING; - - Dropzone.CANCELED = "canceled"; - - Dropzone.ERROR = "error"; - - Dropzone.SUCCESS = "success"; - - - /* - - Bugfix for iOS 6 and 7 - Source: http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios - based on the work of https://github.com/stomita/ios-imagefile-megapixel - */ - - detectVerticalSquash = function(img) { - var alpha, canvas, ctx, data, ey, ih, iw, py, ratio, sy; - iw = img.naturalWidth; - ih = img.naturalHeight; - canvas = document.createElement("canvas"); - canvas.width = 1; - canvas.height = ih; - ctx = canvas.getContext("2d"); - ctx.drawImage(img, 0, 0); - data = ctx.getImageData(1, 0, 1, ih).data; - sy = 0; - ey = ih; - py = ih; - while (py > sy) { - alpha = data[(py - 1) * 4 + 3]; - if (alpha === 0) { - ey = py; - } else { - sy = py; - } - py = (ey + sy) >> 1; - } - ratio = py / ih; - if (ratio === 0) { - return 1; - } else { - return ratio; - } - }; - - drawImageIOSFix = function(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) { - var vertSquashRatio; - vertSquashRatio = detectVerticalSquash(img); - return ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio); - }; - - ExifRestore = (function() { - function ExifRestore() {} - - ExifRestore.KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; - - ExifRestore.encode64 = function(input) { - var chr1, chr2, chr3, enc1, enc2, enc3, enc4, i, output; - output = ''; - chr1 = void 0; - chr2 = void 0; - chr3 = ''; - enc1 = void 0; - enc2 = void 0; - enc3 = void 0; - enc4 = ''; - i = 0; - while (true) { - chr1 = input[i++]; - chr2 = input[i++]; - chr3 = input[i++]; - enc1 = chr1 >> 2; - enc2 = (chr1 & 3) << 4 | chr2 >> 4; - enc3 = (chr2 & 15) << 2 | chr3 >> 6; - enc4 = chr3 & 63; - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } - output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4); - chr1 = chr2 = chr3 = ''; - enc1 = enc2 = enc3 = enc4 = ''; - if (!(i < input.length)) { - break; - } - } - return output; - }; - - ExifRestore.restore = function(origFileBase64, resizedFileBase64) { - var image, rawImage, segments; - if (!origFileBase64.match('data:image/jpeg;base64,')) { - return resizedFileBase64; - } - rawImage = this.decode64(origFileBase64.replace('data:image/jpeg;base64,', '')); - segments = this.slice2Segments(rawImage); - image = this.exifManipulation(resizedFileBase64, segments); - return 'data:image/jpeg;base64,' + this.encode64(image); - }; - - ExifRestore.exifManipulation = function(resizedFileBase64, segments) { - var aBuffer, exifArray, newImageArray; - exifArray = this.getExifArray(segments); - newImageArray = this.insertExif(resizedFileBase64, exifArray); - aBuffer = new Uint8Array(newImageArray); - return aBuffer; - }; - - ExifRestore.getExifArray = function(segments) { - var seg, x; - seg = void 0; - x = 0; - while (x < segments.length) { - seg = segments[x]; - if (seg[0] === 255 & seg[1] === 225) { - return seg; - } - x++; - } - return []; - }; - - ExifRestore.insertExif = function(resizedFileBase64, exifArray) { - var array, ato, buf, imageData, mae, separatePoint; - imageData = resizedFileBase64.replace('data:image/jpeg;base64,', ''); - buf = this.decode64(imageData); - separatePoint = buf.indexOf(255, 3); - mae = buf.slice(0, separatePoint); - ato = buf.slice(separatePoint); - array = mae; - array = array.concat(exifArray); - array = array.concat(ato); - return array; - }; - - ExifRestore.slice2Segments = function(rawImageArray) { - var endPoint, head, length, seg, segments; - head = 0; - segments = []; - while (true) { - if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 218) { - break; - } - if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 216) { - head += 2; - } else { - length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3]; - endPoint = head + length + 2; - seg = rawImageArray.slice(head, endPoint); - segments.push(seg); - head = endPoint; - } - if (head > rawImageArray.length) { - break; - } - } - return segments; - }; - - ExifRestore.decode64 = function(input) { - var base64test, buf, chr1, chr2, chr3, enc1, enc2, enc3, enc4, i, output; - output = ''; - chr1 = void 0; - chr2 = void 0; - chr3 = ''; - enc1 = void 0; - enc2 = void 0; - enc3 = void 0; - enc4 = ''; - i = 0; - buf = []; - base64test = /[^A-Za-z0-9\+\/\=]/g; - if (base64test.exec(input)) { - console.warning('There were invalid base64 characters in the input text.\n' + 'Valid base64 characters are A-Z, a-z, 0-9, \'+\', \'/\',and \'=\'\n' + 'Expect errors in decoding.'); - } - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); - while (true) { - enc1 = this.KEY_STR.indexOf(input.charAt(i++)); - enc2 = this.KEY_STR.indexOf(input.charAt(i++)); - enc3 = this.KEY_STR.indexOf(input.charAt(i++)); - enc4 = this.KEY_STR.indexOf(input.charAt(i++)); - chr1 = enc1 << 2 | enc2 >> 4; - chr2 = (enc2 & 15) << 4 | enc3 >> 2; - chr3 = (enc3 & 3) << 6 | enc4; - buf.push(chr1); - if (enc3 !== 64) { - buf.push(chr2); - } - if (enc4 !== 64) { - buf.push(chr3); - } - chr1 = chr2 = chr3 = ''; - enc1 = enc2 = enc3 = enc4 = ''; - if (!(i < input.length)) { - break; - } - } - return buf; - }; - - return ExifRestore; - - })(); - - - /* - * contentloaded.js - * - * Author: Diego Perini (diego.perini at gmail.com) - * Summary: cross-browser wrapper for DOMContentLoaded - * Updated: 20101020 - * License: MIT - * Version: 1.2 - * - * URL: - * http://javascript.nwbox.com/ContentLoaded/ - * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE - */ - - contentLoaded = function(win, fn) { - var add, doc, done, init, poll, pre, rem, root, top; - done = false; - top = true; - doc = win.document; - root = doc.documentElement; - add = (doc.addEventListener ? "addEventListener" : "attachEvent"); - rem = (doc.addEventListener ? "removeEventListener" : "detachEvent"); - pre = (doc.addEventListener ? "" : "on"); - init = function(e) { - if (e.type === "readystatechange" && doc.readyState !== "complete") { - return; - } - (e.type === "load" ? win : doc)[rem](pre + e.type, init, false); - if (!done && (done = true)) { - return fn.call(win, e.type || e); - } - }; - poll = function() { - var e, error1; - try { - root.doScroll("left"); - } catch (error1) { - e = error1; - setTimeout(poll, 50); - return; - } - return init("poll"); - }; - if (doc.readyState !== "complete") { - if (doc.createEventObject && root.doScroll) { - try { - top = !win.frameElement; - } catch (undefined) {} - if (top) { - poll(); - } - } - doc[add](pre + "DOMContentLoaded", init, false); - doc[add](pre + "readystatechange", init, false); - return win[add](pre + "load", init, false); - } - }; - - Dropzone._autoDiscoverFunction = function() { - if (Dropzone.autoDiscover) { - return Dropzone.discover(); - } - }; - - contentLoaded(window, Dropzone._autoDiscoverFunction); - -}).call(this); diff --git a/_examples/dropzonejs/src/views/upload.html b/_examples/dropzonejs/src/views/upload.html deleted file mode 100644 index d7f00987..00000000 --- a/_examples/dropzonejs/src/views/upload.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - DropzoneJS Uploader - - - - - - - - - - - - - - - -
-
- - -
-
- - - \ No newline at end of file diff --git a/_examples/dropzonejs/with_files.png b/_examples/dropzonejs/with_files.png deleted file mode 100644 index 2b6f3cdc7b9b4c24b6675d7f50433d4954c9e3c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42036 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 App2App3 index \ No newline at end of file diff --git a/_examples/file-server/basic/assets/app2/index.html b/_examples/file-server/basic/assets/app2/index.html deleted file mode 100644 index 8193d822..00000000 --- a/_examples/file-server/basic/assets/app2/index.html +++ /dev/null @@ -1 +0,0 @@ -

Hello App2 index

\ No newline at end of file diff --git a/_examples/file-server/basic/assets/css/main.css b/_examples/file-server/basic/assets/css/main.css deleted file mode 100644 index fb72e54a..00000000 --- a/_examples/file-server/basic/assets/css/main.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - background-color: black; -} diff --git a/_examples/file-server/basic/assets/favicon.ico b/_examples/file-server/basic/assets/favicon.ico deleted file mode 100644 index c370da518ec542579b7cc0d5d30f4778b4a96318..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 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 index \ No newline at end of file diff --git a/_examples/file-server/basic/assets/js/main.js b/_examples/file-server/basic/assets/js/main.js deleted file mode 100644 index 07f93514..00000000 --- a/_examples/file-server/basic/assets/js/main.js +++ /dev/null @@ -1 +0,0 @@ -console.log("example"); \ No newline at end of file diff --git a/_examples/file-server/basic/main.go b/_examples/file-server/basic/main.go deleted file mode 100644 index dc5fc10e..00000000 --- a/_examples/file-server/basic/main.go +++ /dev/null @@ -1,66 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func newApp() *iris.Application { - app := iris.New() - - app.Favicon("./assets/favicon.ico") - - // first parameter is the request path - // second is the system directory - // - // app.HandleDir("/css", iris.Dir("./assets/css")) - // app.HandleDir("/js", iris.Dir("./assets/js")) - - v1 := app.Party("/v1") - v1.HandleDir("/static", iris.Dir("./assets"), iris.DirOptions{ - // Defaults to "/index.html", if request path is ending with **/*/$IndexName - // then it redirects to **/*(/) which another handler is handling it, - // that another handler, called index handler, is auto-registered by the framework - // if end developer does not managed to handle it by hand. - IndexName: "/index.html", - // When files should served under compression. - Compress: false, - // List the files inside the current requested directory if `IndexName` not found. - ShowList: false, - Cache: iris.DirCacheOptions{ - // enable in-memory cache and pre-compress the files. - Enable: true, - // ignore image types (and pdf). - CompressIgnore: iris.MatchImagesAssets, - // do not compress files smaller than size. - CompressMinSize: 300, - // available encodings that will be negotiated with client's needs. - Encodings: []string{"gzip", "br" /* you can also add: deflate, snappy */}, - }, - DirList: iris.DirListRich(), - // If `ShowList` is true then this function will be used instead of the default - // one to show the list of files of a current requested directory(dir). - // DirList: func(ctx iris.Context, dirName string, dir http.File) error { ... } - // - // Optional validator that loops through each requested resource. - // AssetValidator: func(ctx iris.Context, name string) bool { ... } - }) - - // You can also register any index handler manually, order of registration does not matter: - // v1.Get("/static", [...custom middleware...], func(ctx iris.Context) { - // [...custom code...] - // ctx.ServeFile("./assets/index.html") - // }) - - // http://localhost:8080/v1/static - // http://localhost:8080/v1/static/css/main.css - // http://localhost:8080/v1/static/js/jquery-2.1.1.js - // http://localhost:8080/v1/static/favicon.ico - return app -} - -func main() { - app := newApp() - app.Logger().SetLevel("debug") - - app.Listen(":8080") -} diff --git a/_examples/file-server/basic/main_test.go b/_examples/file-server/basic/main_test.go deleted file mode 100644 index 23db8229..00000000 --- a/_examples/file-server/basic/main_test.go +++ /dev/null @@ -1,114 +0,0 @@ -package main - -import ( - "io/ioutil" - "path/filepath" - "strings" - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/httptest" -) - -type resource string - -func (r resource) contentType() string { - switch filepath.Ext(r.String()) { - case ".js": - return "text/javascript" - case ".css": - return "text/css" - case ".ico": - return "image/x-icon" - case ".html", "": - return "text/html" - default: - return "text/plain" - } -} - -func (r resource) String() string { - return string(r) -} - -func (r resource) strip(strip string) string { - s := r.String() - return strings.TrimPrefix(s, strip) -} - -func (r resource) loadFromBase(dir string, strip string) string { - filename := r.String() - - filename = r.strip(strip) - if filepath.Ext(filename) == "" { - // root /. - filename = filename + "/index.html" - } - - fullpath := filepath.Join(dir, filename) - - b, err := ioutil.ReadFile(fullpath) - if err != nil { - panic(fullpath + " failed with error: " + err.Error()) - } - - result := string(b) - - return result -} - -func TestFileServerBasic(t *testing.T) { - urls := []resource{ - "/v1/static/css/main.css", - "/v1/static/js/main.js", - "/v1/static/favicon.ico", - "/v1/static/app2", - "/v1/static/app2/app2app3", - "/v1/static", - } - - app := newApp() - // route := app.GetRouteReadOnly("GET/{file:path}") - // if route == nil { - // app.Logger().Fatalf("expected a route to serve files") - // } - - // if expected, got := "./assets", route.StaticDir(); expected != got { - // app.Logger().Fatalf("expected route's static directory to be: '%s' but got: '%s'", expected, got) - // } - - // if !route.StaticDirContainsIndex() { - // app.Logger().Fatalf("epxected ./assets to contain an %s file", "/index.html") - // } - - e := httptest.New(t, app) - for _, u := range urls { - url := u.String() - contents := u.loadFromBase("./assets", "/v1/static") - - e.GET(url).Expect(). - Status(httptest.StatusOK). - ContentType(u.contentType(), app.ConfigurationReadOnly().GetCharset()). - Body().Equal(contents) - } -} - -// Tests subdomain + request path and system directory with a name that contains a dot(.) -func TestHandleDirDot(t *testing.T) { - urls := []resource{ - "/v1/assets.system/css/main.css", - } - app := newApp() - app.Subdomain("test").Party("/v1").HandleDir("/assets.system", iris.Dir("./assets.system")) - - e := httptest.New(t, app, httptest.URL("http://test.example.com")) - for _, u := range urls { - url := u.String() - contents := u.loadFromBase("./assets.system", "/v1/assets.system") - - e.GET(url).Expect(). - Status(httptest.StatusOK). - ContentType(u.contentType(), app.ConfigurationReadOnly().GetCharset()). - Body().Equal(contents) - } -} diff --git a/_examples/file-server/embedding-files-into-app/assets/css/bootstrap.min.css b/_examples/file-server/embedding-files-into-app/assets/css/bootstrap.min.css deleted file mode 100644 index c2522313..00000000 --- a/_examples/file-server/embedding-files-into-app/assets/css/bootstrap.min.css +++ /dev/null @@ -1,7225 +0,0 @@ -/*! - * Bootstrap v3.3.4 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ -html { - font-family: sans-serif; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100% -} - -body { - margin: 0 -} - -article, aside, details, figcaption, figure, footer, header, hgroup, - main, menu, nav, section, summary { - display: block -} - -audio, canvas, progress, video { - display: inline-block; - vertical-align: baseline -} - -audio:not ([controls] ){ - display: none; - height: 0 -} - -[hidden], template { - display: none -} - -a { - background-color: transparent -} - -a:active, a:hover { - outline: 0 -} - -abbr[title] { - border-bottom: 1px dotted -} - -b, strong { - font-weight: 700 -} - -dfn { - font-style: italic -} - -h1 { - margin: .67em 0; - font-size: 2em -} - -mark { - color: #000; - background: #ff0 -} - -small { - font-size: 80% -} - -sub, sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline -} - -sup { - top: -.5em -} - -sub { - bottom: -.25em -} - -img { - border: 0 -} - -svg:not (:root ){ - overflow: hidden -} - -figure { - margin: 1em 40px -} - -hr { - height: 0; - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box -} - -pre { - overflow: auto -} - -code, kbd, pre, samp { - font-family: monospace, monospace; - font-size: 1em -} - -button, input, optgroup, select, textarea { - margin: 0; - font: inherit; - color: inherit -} - -button { - overflow: visible -} - -button, select { - text-transform: none -} - -button, html input[type=button], input[type=reset], input[type=submit] { - -webkit-appearance: button; - cursor: pointer -} - -button[disabled], html input[disabled] { - cursor: default -} - -button::-moz-focus-inner, input::-moz-focus-inner { - padding: 0; - border: 0 -} - -input { - line-height: normal -} - -input[type=checkbox], input[type=radio] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - padding: 0 -} - -input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button - { - height: auto -} - -input[type=search] { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - -webkit-appearance: textfield -} - -input[type=search]::-webkit-search-cancel-button, input[type=search]::-webkit-search-decoration - { - -webkit-appearance: none -} - -fieldset { - padding: .35em .625em .75em; - margin: 0 2px; - border: 1px solid silver -} - -legend { - padding: 0; - border: 0 -} - -textarea { - overflow: auto -} - -optgroup { - font-weight: 700 -} - -table { - border-spacing: 0; - border-collapse: collapse -} - -td, th { - padding: 0 -} - /*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ -@media print { - *, :after, :before { - color: #000 !important; - text-shadow: none !important; - background: 0 0 !important; - -webkit-box-shadow: none !important; - box-shadow: none !important - } - a, a:visited { - text-decoration: underline - } - a[href]:after { - content: " (" attr(href) ")" - } - abbr[title]:after { - content: " (" attr(title) ")" - } - a[href^="javascript:"]:after, a[href^="#"]:after { - content: "" - } - blockquote, pre { - border: 1px solid #999; - page-break-inside: avoid - } - thead { - display: table-header-group - } - img, tr { - page-break-inside: avoid - } - img { - max-width: 100% !important - } - h2, h3, p { - orphans: 3; - widows: 3 - } - h2, h3 { - page-break-after: avoid - } - select { - background: #fff !important - } - .navbar { - display: none - } - .btn>.caret, .dropup>.btn>.caret { - border-top-color: #000 !important - } - .label { - border: 1px solid #000 - } - .table { - border-collapse: collapse !important - } - .table td, .table th { - background-color: #fff !important - } - .table-bordered td, .table-bordered th { - border: 1px solid #ddd !important - } -} - -@font-face { - font-family: 'Glyphicons Halflings'; - src: url(../fonts/glyphicons-halflings-regular.eot); - src: url(../fonts/glyphicons-halflings-regular.eot?#iefix) - format('embedded-opentype'), - url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'), - url(../fonts/glyphicons-halflings-regular.woff) format('woff'), - url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'), - url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) - format('svg') -} - -.glyphicon { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: 400; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale -} - -.glyphicon-asterisk:before { - content: "\2a" -} - -.glyphicon-plus:before { - content: "\2b" -} - -.glyphicon-eur:before, .glyphicon-euro:before { - content: "\20ac" -} - -.glyphicon-minus:before { - content: "\2212" -} - -.glyphicon-cloud:before { - content: "\2601" -} - -.glyphicon-envelope:before { - content: "\2709" -} - -.glyphicon-pencil:before { - content: "\270f" -} - -.glyphicon-glass:before { - content: "\e001" -} - -.glyphicon-music:before { - content: "\e002" -} - -.glyphicon-search:before { - content: "\e003" -} - -.glyphicon-heart:before { - content: "\e005" -} - -.glyphicon-star:before { - content: "\e006" -} - -.glyphicon-star-empty:before { - content: "\e007" -} - -.glyphicon-user:before { - content: "\e008" -} - -.glyphicon-film:before { - content: "\e009" -} - -.glyphicon-th-large:before { - content: "\e010" -} - -.glyphicon-th:before { - content: "\e011" -} - -.glyphicon-th-list:before { - content: "\e012" -} - -.glyphicon-ok:before { - content: "\e013" -} - -.glyphicon-remove:before { - content: "\e014" -} - -.glyphicon-zoom-in:before { - content: "\e015" -} - -.glyphicon-zoom-out:before { - content: "\e016" -} - -.glyphicon-off:before { - content: "\e017" -} - -.glyphicon-signal:before { - content: "\e018" -} - -.glyphicon-cog:before { - content: "\e019" -} - -.glyphicon-trash:before { - content: "\e020" -} - -.glyphicon-home:before { - content: "\e021" -} - -.glyphicon-file:before { - content: "\e022" -} - -.glyphicon-time:before { - content: "\e023" -} - -.glyphicon-road:before { - content: "\e024" -} - -.glyphicon-download-alt:before { - content: "\e025" -} - -.glyphicon-download:before { - content: "\e026" -} - -.glyphicon-upload:before { - content: "\e027" -} - -.glyphicon-inbox:before { - content: "\e028" -} - -.glyphicon-play-circle:before { - content: "\e029" -} - -.glyphicon-repeat:before { - content: "\e030" -} - -.glyphicon-refresh:before { - content: "\e031" -} - -.glyphicon-list-alt:before { - content: "\e032" -} - -.glyphicon-lock:before { - content: "\e033" -} - -.glyphicon-flag:before { - content: "\e034" -} - -.glyphicon-headphones:before { - content: "\e035" -} - -.glyphicon-volume-off:before { - content: "\e036" -} - -.glyphicon-volume-down:before { - content: "\e037" -} - -.glyphicon-volume-up:before { - content: "\e038" -} - -.glyphicon-qrcode:before { - content: "\e039" -} - -.glyphicon-barcode:before { - content: "\e040" -} - -.glyphicon-tag:before { - content: "\e041" -} - -.glyphicon-tags:before { - content: "\e042" -} - -.glyphicon-book:before { - content: "\e043" -} - -.glyphicon-bookmark:before { - content: "\e044" -} - -.glyphicon-print:before { - content: "\e045" -} - -.glyphicon-camera:before { - content: "\e046" -} - -.glyphicon-font:before { - content: "\e047" -} - -.glyphicon-bold:before { - content: "\e048" -} - -.glyphicon-italic:before { - content: "\e049" -} - -.glyphicon-text-height:before { - content: "\e050" -} - -.glyphicon-text-width:before { - content: "\e051" -} - -.glyphicon-align-left:before { - content: "\e052" -} - -.glyphicon-align-center:before { - content: "\e053" -} - -.glyphicon-align-right:before { - content: "\e054" -} - -.glyphicon-align-justify:before { - content: "\e055" -} - -.glyphicon-list:before { - content: "\e056" -} - -.glyphicon-indent-left:before { - content: "\e057" -} - -.glyphicon-indent-right:before { - content: "\e058" -} - -.glyphicon-facetime-video:before { - content: "\e059" -} - -.glyphicon-picture:before { - content: "\e060" -} - -.glyphicon-map-marker:before { - content: "\e062" -} - -.glyphicon-adjust:before { - content: "\e063" -} - -.glyphicon-tint:before { - content: "\e064" -} - -.glyphicon-edit:before { - content: "\e065" -} - -.glyphicon-share:before { - content: "\e066" -} - -.glyphicon-check:before { - content: "\e067" -} - -.glyphicon-move:before { - content: "\e068" -} - -.glyphicon-step-backward:before { - content: "\e069" -} - -.glyphicon-fast-backward:before { - content: "\e070" -} - -.glyphicon-backward:before { - content: "\e071" -} - -.glyphicon-play:before { - content: "\e072" -} - -.glyphicon-pause:before { - content: "\e073" -} - -.glyphicon-stop:before { - content: "\e074" -} - -.glyphicon-forward:before { - content: "\e075" -} - -.glyphicon-fast-forward:before { - content: "\e076" -} - -.glyphicon-step-forward:before { - content: "\e077" -} - -.glyphicon-eject:before { - content: "\e078" -} - -.glyphicon-chevron-left:before { - content: "\e079" -} - -.glyphicon-chevron-right:before { - content: "\e080" -} - -.glyphicon-plus-sign:before { - content: "\e081" -} - -.glyphicon-minus-sign:before { - content: "\e082" -} - -.glyphicon-remove-sign:before { - content: "\e083" -} - -.glyphicon-ok-sign:before { - content: "\e084" -} - -.glyphicon-question-sign:before { - content: "\e085" -} - -.glyphicon-info-sign:before { - content: "\e086" -} - -.glyphicon-screenshot:before { - content: "\e087" -} - -.glyphicon-remove-circle:before { - content: "\e088" -} - -.glyphicon-ok-circle:before { - content: "\e089" -} - -.glyphicon-ban-circle:before { - content: "\e090" -} - -.glyphicon-arrow-left:before { - content: "\e091" -} - -.glyphicon-arrow-right:before { - content: "\e092" -} - -.glyphicon-arrow-up:before { - content: "\e093" -} - -.glyphicon-arrow-down:before { - content: "\e094" -} - -.glyphicon-share-alt:before { - content: "\e095" -} - -.glyphicon-resize-full:before { - content: "\e096" -} - -.glyphicon-resize-small:before { - content: "\e097" -} - -.glyphicon-exclamation-sign:before { - content: "\e101" -} - -.glyphicon-gift:before { - content: "\e102" -} - -.glyphicon-leaf:before { - content: "\e103" -} - -.glyphicon-fire:before { - content: "\e104" -} - -.glyphicon-eye-open:before { - content: "\e105" -} - -.glyphicon-eye-close:before { - content: "\e106" -} - -.glyphicon-warning-sign:before { - content: "\e107" -} - -.glyphicon-plane:before { - content: "\e108" -} - -.glyphicon-calendar:before { - content: "\e109" -} - -.glyphicon-random:before { - content: "\e110" -} - -.glyphicon-comment:before { - content: "\e111" -} - -.glyphicon-magnet:before { - content: "\e112" -} - -.glyphicon-chevron-up:before { - content: "\e113" -} - -.glyphicon-chevron-down:before { - content: "\e114" -} - -.glyphicon-retweet:before { - content: "\e115" -} - -.glyphicon-shopping-cart:before { - content: "\e116" -} - -.glyphicon-folder-close:before { - content: "\e117" -} - -.glyphicon-folder-open:before { - content: "\e118" -} - -.glyphicon-resize-vertical:before { - content: "\e119" -} - -.glyphicon-resize-horizontal:before { - content: "\e120" -} - -.glyphicon-hdd:before { - content: "\e121" -} - -.glyphicon-bullhorn:before { - content: "\e122" -} - -.glyphicon-bell:before { - content: "\e123" -} - -.glyphicon-certificate:before { - content: "\e124" -} - -.glyphicon-thumbs-up:before { - content: "\e125" -} - -.glyphicon-thumbs-down:before { - content: "\e126" -} - -.glyphicon-hand-right:before { - content: "\e127" -} - -.glyphicon-hand-left:before { - content: "\e128" -} - -.glyphicon-hand-up:before { - content: "\e129" -} - -.glyphicon-hand-down:before { - content: "\e130" -} - -.glyphicon-circle-arrow-right:before { - content: "\e131" -} - -.glyphicon-circle-arrow-left:before { - content: "\e132" -} - -.glyphicon-circle-arrow-up:before { - content: "\e133" -} - -.glyphicon-circle-arrow-down:before { - content: "\e134" -} - -.glyphicon-globe:before { - content: "\e135" -} - -.glyphicon-wrench:before { - content: "\e136" -} - -.glyphicon-tasks:before { - content: "\e137" -} - -.glyphicon-filter:before { - content: "\e138" -} - -.glyphicon-briefcase:before { - content: "\e139" -} - -.glyphicon-fullscreen:before { - content: "\e140" -} - -.glyphicon-dashboard:before { - content: "\e141" -} - -.glyphicon-paperclip:before { - content: "\e142" -} - -.glyphicon-heart-empty:before { - content: "\e143" -} - -.glyphicon-link:before { - content: "\e144" -} - -.glyphicon-phone:before { - content: "\e145" -} - -.glyphicon-pushpin:before { - content: "\e146" -} - -.glyphicon-usd:before { - content: "\e148" -} - -.glyphicon-gbp:before { - content: "\e149" -} - -.glyphicon-sort:before { - content: "\e150" -} - -.glyphicon-sort-by-alphabet:before { - content: "\e151" -} - -.glyphicon-sort-by-alphabet-alt:before { - content: "\e152" -} - -.glyphicon-sort-by-order:before { - content: "\e153" -} - -.glyphicon-sort-by-order-alt:before { - content: "\e154" -} - -.glyphicon-sort-by-attributes:before { - content: "\e155" -} - -.glyphicon-sort-by-attributes-alt:before { - content: "\e156" -} - -.glyphicon-unchecked:before { - content: "\e157" -} - -.glyphicon-expand:before { - content: "\e158" -} - -.glyphicon-collapse-down:before { - content: "\e159" -} - -.glyphicon-collapse-up:before { - content: "\e160" -} - -.glyphicon-log-in:before { - content: "\e161" -} - -.glyphicon-flash:before { - content: "\e162" -} - -.glyphicon-log-out:before { - content: "\e163" -} - -.glyphicon-new-window:before { - content: "\e164" -} - -.glyphicon-record:before { - content: "\e165" -} - -.glyphicon-save:before { - content: "\e166" -} - -.glyphicon-open:before { - content: "\e167" -} - -.glyphicon-saved:before { - content: "\e168" -} - -.glyphicon-import:before { - content: "\e169" -} - -.glyphicon-export:before { - content: "\e170" -} - -.glyphicon-send:before { - content: "\e171" -} - -.glyphicon-floppy-disk:before { - content: "\e172" -} - -.glyphicon-floppy-saved:before { - content: "\e173" -} - -.glyphicon-floppy-remove:before { - content: "\e174" -} - -.glyphicon-floppy-save:before { - content: "\e175" -} - -.glyphicon-floppy-open:before { - content: "\e176" -} - -.glyphicon-credit-card:before { - content: "\e177" -} - -.glyphicon-transfer:before { - content: "\e178" -} - -.glyphicon-cutlery:before { - content: "\e179" -} - -.glyphicon-header:before { - content: "\e180" -} - -.glyphicon-compressed:before { - content: "\e181" -} - -.glyphicon-earphone:before { - content: "\e182" -} - -.glyphicon-phone-alt:before { - content: "\e183" -} - -.glyphicon-tower:before { - content: "\e184" -} - -.glyphicon-stats:before { - content: "\e185" -} - -.glyphicon-sd-video:before { - content: "\e186" -} - -.glyphicon-hd-video:before { - content: "\e187" -} - -.glyphicon-subtitles:before { - content: "\e188" -} - -.glyphicon-sound-stereo:before { - content: "\e189" -} - -.glyphicon-sound-dolby:before { - content: "\e190" -} - -.glyphicon-sound-5-1:before { - content: "\e191" -} - -.glyphicon-sound-6-1:before { - content: "\e192" -} - -.glyphicon-sound-7-1:before { - content: "\e193" -} - -.glyphicon-copyright-mark:before { - content: "\e194" -} - -.glyphicon-registration-mark:before { - content: "\e195" -} - -.glyphicon-cloud-download:before { - content: "\e197" -} - -.glyphicon-cloud-upload:before { - content: "\e198" -} - -.glyphicon-tree-conifer:before { - content: "\e199" -} - -.glyphicon-tree-deciduous:before { - content: "\e200" -} - -.glyphicon-cd:before { - content: "\e201" -} - -.glyphicon-save-file:before { - content: "\e202" -} - -.glyphicon-open-file:before { - content: "\e203" -} - -.glyphicon-level-up:before { - content: "\e204" -} - -.glyphicon-copy:before { - content: "\e205" -} - -.glyphicon-paste:before { - content: "\e206" -} - -.glyphicon-alert:before { - content: "\e209" -} - -.glyphicon-equalizer:before { - content: "\e210" -} - -.glyphicon-king:before { - content: "\e211" -} - -.glyphicon-queen:before { - content: "\e212" -} - -.glyphicon-pawn:before { - content: "\e213" -} - -.glyphicon-bishop:before { - content: "\e214" -} - -.glyphicon-knight:before { - content: "\e215" -} - -.glyphicon-baby-formula:before { - content: "\e216" -} - -.glyphicon-tent:before { - content: "\26fa" -} - -.glyphicon-blackboard:before { - content: "\e218" -} - -.glyphicon-bed:before { - content: "\e219" -} - -.glyphicon-apple:before { - content: "\f8ff" -} - -.glyphicon-erase:before { - content: "\e221" -} - -.glyphicon-hourglass:before { - content: "\231b" -} - -.glyphicon-lamp:before { - content: "\e223" -} - -.glyphicon-duplicate:before { - content: "\e224" -} - -.glyphicon-piggy-bank:before { - content: "\e225" -} - -.glyphicon-scissors:before { - content: "\e226" -} - -.glyphicon-bitcoin:before { - content: "\e227" -} - -.glyphicon-btc:before { - content: "\e227" -} - -.glyphicon-xbt:before { - content: "\e227" -} - -.glyphicon-yen:before { - content: "\00a5" -} - -.glyphicon-jpy:before { - content: "\00a5" -} - -.glyphicon-ruble:before { - content: "\20bd" -} - -.glyphicon-rub:before { - content: "\20bd" -} - -.glyphicon-scale:before { - content: "\e230" -} - -.glyphicon-ice-lolly:before { - content: "\e231" -} - -.glyphicon-ice-lolly-tasted:before { - content: "\e232" -} - -.glyphicon-education:before { - content: "\e233" -} - -.glyphicon-option-horizontal:before { - content: "\e234" -} - -.glyphicon-option-vertical:before { - content: "\e235" -} - -.glyphicon-menu-hamburger:before { - content: "\e236" -} - -.glyphicon-modal-window:before { - content: "\e237" -} - -.glyphicon-oil:before { - content: "\e238" -} - -.glyphicon-grain:before { - content: "\e239" -} - -.glyphicon-sunglasses:before { - content: "\e240" -} - -.glyphicon-text-size:before { - content: "\e241" -} - -.glyphicon-text-color:before { - content: "\e242" -} - -.glyphicon-text-background:before { - content: "\e243" -} - -.glyphicon-object-align-top:before { - content: "\e244" -} - -.glyphicon-object-align-bottom:before { - content: "\e245" -} - -.glyphicon-object-align-horizontal:before { - content: "\e246" -} - -.glyphicon-object-align-left:before { - content: "\e247" -} - -.glyphicon-object-align-vertical:before { - content: "\e248" -} - -.glyphicon-object-align-right:before { - content: "\e249" -} - -.glyphicon-triangle-right:before { - content: "\e250" -} - -.glyphicon-triangle-left:before { - content: "\e251" -} - -.glyphicon-triangle-bottom:before { - content: "\e252" -} - -.glyphicon-triangle-top:before { - content: "\e253" -} - -.glyphicon-console:before { - content: "\e254" -} - -.glyphicon-superscript:before { - content: "\e255" -} - -.glyphicon-subscript:before { - content: "\e256" -} - -.glyphicon-menu-left:before { - content: "\e257" -} - -.glyphicon-menu-right:before { - content: "\e258" -} - -.glyphicon-menu-down:before { - content: "\e259" -} - -.glyphicon-menu-up:before { - content: "\e260" -} - -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box -} - -:after, :before { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box -} - -html { - font-size: 10px; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0) -} - -body { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - line-height: 1.42857143; - color: #333; - background-color: #fff -} - -button, input, select, textarea { - font-family: inherit; - font-size: inherit; - line-height: inherit -} - -a { - color: #337ab7; - text-decoration: none -} - -a:focus, a:hover { - color: #23527c; - text-decoration: underline -} - -a:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px -} - -figure { - margin: 0 -} - -img { - vertical-align: middle -} - -.carousel-inner>.item>a>img, .carousel-inner>.item>img, .img-responsive, - .thumbnail a>img, .thumbnail>img { - display: block; - max-width: 100%; - height: auto -} - -.img-rounded { - border-radius: 6px -} - -.img-thumbnail { - display: inline-block; - max-width: 100%; - height: auto; - padding: 4px; - line-height: 1.42857143; - background-color: #fff; - border: 1px solid #ddd; - border-radius: 4px; - -webkit-transition: all .2s ease-in-out; - -o-transition: all .2s ease-in-out; - transition: all .2s ease-in-out -} - -.img-circle { - border-radius: 50% -} - -hr { - margin-top: 20px; - margin-bottom: 20px; - border: 0; - border-top: 1px solid #eee -} - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - border: 0 -} - -.sr-only-focusable:active, .sr-only-focusable:focus { - position: static; - width: auto; - height: auto; - margin: 0; - overflow: visible; - clip: auto -} - -[role=button] { - cursor: pointer -} - -.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { - font-family: inherit; - font-weight: 500; - line-height: 1.1; - color: inherit -} - -.h1 .small, .h1 small, .h2 .small, .h2 small, .h3 .small, .h3 small, .h4 .small, - .h4 small, .h5 .small, .h5 small, .h6 .small, .h6 small, h1 .small, h1 small, - h2 .small, h2 small, h3 .small, h3 small, h4 .small, h4 small, h5 .small, - h5 small, h6 .small, h6 small { - font-weight: 400; - line-height: 1; - color: #777 -} - -.h1, .h2, .h3, h1, h2, h3 { - margin-top: 20px; - margin-bottom: 10px -} - -.h1 .small, .h1 small, .h2 .small, .h2 small, .h3 .small, .h3 small, h1 .small, - h1 small, h2 .small, h2 small, h3 .small, h3 small { - font-size: 65% -} - -.h4, .h5, .h6, h4, h5, h6 { - margin-top: 10px; - margin-bottom: 10px -} - -.h4 .small, .h4 small, .h5 .small, .h5 small, .h6 .small, .h6 small, h4 .small, - h4 small, h5 .small, h5 small, h6 .small, h6 small { - font-size: 75% -} - -.h1, h1 { - font-size: 36px -} - -.h2, h2 { - font-size: 30px -} - -.h3, h3 { - font-size: 24px -} - -.h4, h4 { - font-size: 18px -} - -.h5, h5 { - font-size: 14px -} - -.h6, h6 { - font-size: 12px -} - -p { - margin: 0 0 10px -} - -.lead { - margin-bottom: 20px; - font-size: 16px; - font-weight: 300; - line-height: 1.4 -} - -@media ( min-width :768px) { - .lead { - font-size: 21px - } -} - -.small, small { - font-size: 85% -} - -.mark, mark { - padding: .2em; - background-color: #fcf8e3 -} - -.text-left { - text-align: left -} - -.text-right { - text-align: right -} - -.text-center { - text-align: center -} - -.text-justify { - text-align: justify -} - -.text-nowrap { - white-space: nowrap -} - -.text-lowercase { - text-transform: lowercase -} - -.text-uppercase { - text-transform: uppercase -} - -.text-capitalize { - text-transform: capitalize -} - -.text-muted { - color: #777 -} - -.text-primary { - color: #337ab7 -} - -a.text-primary:hover { - color: #286090 -} - -.text-success { - color: #3c763d -} - -a.text-success:hover { - color: #2b542c -} - -.text-info { - color: #31708f -} - -a.text-info:hover { - color: #245269 -} - -.text-warning { - color: #8a6d3b -} - -a.text-warning:hover { - color: #66512c -} - -.text-danger { - color: #a94442 -} - -a.text-danger:hover { - color: #843534 -} - -.bg-primary { - color: #fff; - background-color: #337ab7 -} - -a.bg-primary:hover { - background-color: #286090 -} - -.bg-success { - background-color: #dff0d8 -} - -a.bg-success:hover { - background-color: #c1e2b3 -} - -.bg-info { - background-color: #d9edf7 -} - -a.bg-info:hover { - background-color: #afd9ee -} - -.bg-warning { - background-color: #fcf8e3 -} - -a.bg-warning:hover { - background-color: #f7ecb5 -} - -.bg-danger { - background-color: #f2dede -} - -a.bg-danger:hover { - background-color: #e4b9b9 -} - -.page-header { - padding-bottom: 9px; - margin: 40px 0 20px; - border-bottom: 1px solid #eee -} - -ol, ul { - margin-top: 0; - margin-bottom: 10px -} - -ol ol, ol ul, ul ol, ul ul { - margin-bottom: 0 -} - -.list-unstyled { - padding-left: 0; - list-style: none -} - -.list-inline { - padding-left: 0; - margin-left: -5px; - list-style: none -} - -.list-inline>li { - display: inline-block; - padding-right: 5px; - padding-left: 5px -} - -dl { - margin-top: 0; - margin-bottom: 20px -} - -dd, dt { - line-height: 1.42857143 -} - -dt { - font-weight: 700 -} - -dd { - margin-left: 0 -} - -@media ( min-width :768px) { - .dl-horizontal dt { - float: left; - width: 160px; - overflow: hidden; - clear: left; - text-align: right; - text-overflow: ellipsis; - white-space: nowrap - } - .dl-horizontal dd { - margin-left: 180px - } -} - -abbr[data-original-title], abbr[title] { - cursor: help; - border-bottom: 1px dotted #777 -} - -.initialism { - font-size: 90%; - text-transform: uppercase -} - -blockquote { - padding: 10px 20px; - margin: 0 0 20px; - font-size: 17.5px; - border-left: 5px solid #eee -} - -blockquote ol:last-child, blockquote p:last-child, blockquote ul:last-child - { - margin-bottom: 0 -} - -blockquote .small, blockquote footer, blockquote small { - display: block; - font-size: 80%; - line-height: 1.42857143; - color: #777 -} - -blockquote .small:before, blockquote footer:before, blockquote small:before - { - content: '\2014 \00A0' -} - -.blockquote-reverse, blockquote.pull-right { - padding-right: 15px; - padding-left: 0; - text-align: right; - border-right: 5px solid #eee; - border-left: 0 -} - -.blockquote-reverse .small:before, .blockquote-reverse footer:before, - .blockquote-reverse small:before, blockquote.pull-right .small:before, - blockquote.pull-right footer:before, blockquote.pull-right small:before - { - content: '' -} - -.blockquote-reverse .small:after, .blockquote-reverse footer:after, - .blockquote-reverse small:after, blockquote.pull-right .small:after, - blockquote.pull-right footer:after, blockquote.pull-right small:after { - content: '\00A0 \2014' -} - -address { - margin-bottom: 20px; - font-style: normal; - line-height: 1.42857143 -} - -code, kbd, pre, samp { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace -} - -code { - padding: 2px 4px; - font-size: 90%; - color: #c7254e; - background-color: #f9f2f4; - border-radius: 4px -} - -kbd { - padding: 2px 4px; - font-size: 90%; - color: #fff; - background-color: #333; - border-radius: 3px; - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25) -} - -kbd kbd { - padding: 0; - font-size: 100%; - font-weight: 700; - -webkit-box-shadow: none; - box-shadow: none -} - -pre { - display: block; - padding: 9.5px; - margin: 0 0 10px; - font-size: 13px; - line-height: 1.42857143; - color: #333; - word-break: break-all; - word-wrap: break-word; - background-color: #f5f5f5; - border: 1px solid #ccc; - border-radius: 4px -} - -pre code { - padding: 0; - font-size: inherit; - color: inherit; - white-space: pre-wrap; - background-color: transparent; - border-radius: 0 -} - -.pre-scrollable { - max-height: 340px; - overflow-y: scroll -} - -.container { - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto -} - -@media ( min-width :768px) { - .container { - width: 750px - } -} - -@media ( min-width :992px) { - .container { - width: 970px - } -} - -@media ( min-width :1200px) { - .container { - width: 1170px - } -} - -.container-fluid { - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto -} - -.row { - margin-right: -15px; - margin-left: -15px -} - -.col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, - .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, - .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, - .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, - .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, - .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, - .col-xs-1, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-2, .col-xs-3, - .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9 { - position: relative; - min-height: 1px; - padding-right: 15px; - padding-left: 15px -} - -.col-xs-1, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-2, .col-xs-3, - .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9 { - float: left -} - -.col-xs-12 { - width: 100% -} - -.col-xs-11 { - width: 91.66666667% -} - -.col-xs-10 { - width: 83.33333333% -} - -.col-xs-9 { - width: 75% -} - -.col-xs-8 { - width: 66.66666667% -} - -.col-xs-7 { - width: 58.33333333% -} - -.col-xs-6 { - width: 50% -} - -.col-xs-5 { - width: 41.66666667% -} - -.col-xs-4 { - width: 33.33333333% -} - -.col-xs-3 { - width: 25% -} - -.col-xs-2 { - width: 16.66666667% -} - -.col-xs-1 { - width: 8.33333333% -} - -.col-xs-pull-12 { - right: 100% -} - -.col-xs-pull-11 { - right: 91.66666667% -} - -.col-xs-pull-10 { - right: 83.33333333% -} - -.col-xs-pull-9 { - right: 75% -} - -.col-xs-pull-8 { - right: 66.66666667% -} - -.col-xs-pull-7 { - right: 58.33333333% -} - -.col-xs-pull-6 { - right: 50% -} - -.col-xs-pull-5 { - right: 41.66666667% -} - -.col-xs-pull-4 { - right: 33.33333333% -} - -.col-xs-pull-3 { - right: 25% -} - -.col-xs-pull-2 { - right: 16.66666667% -} - -.col-xs-pull-1 { - right: 8.33333333% -} - -.col-xs-pull-0 { - right: auto -} - -.col-xs-push-12 { - left: 100% -} - -.col-xs-push-11 { - left: 91.66666667% -} - -.col-xs-push-10 { - left: 83.33333333% -} - -.col-xs-push-9 { - left: 75% -} - -.col-xs-push-8 { - left: 66.66666667% -} - -.col-xs-push-7 { - left: 58.33333333% -} - -.col-xs-push-6 { - left: 50% -} - -.col-xs-push-5 { - left: 41.66666667% -} - -.col-xs-push-4 { - left: 33.33333333% -} - -.col-xs-push-3 { - left: 25% -} - -.col-xs-push-2 { - left: 16.66666667% -} - -.col-xs-push-1 { - left: 8.33333333% -} - -.col-xs-push-0 { - left: auto -} - -.col-xs-offset-12 { - margin-left: 100% -} - -.col-xs-offset-11 { - margin-left: 91.66666667% -} - -.col-xs-offset-10 { - margin-left: 83.33333333% -} - -.col-xs-offset-9 { - margin-left: 75% -} - -.col-xs-offset-8 { - margin-left: 66.66666667% -} - -.col-xs-offset-7 { - margin-left: 58.33333333% -} - -.col-xs-offset-6 { - margin-left: 50% -} - -.col-xs-offset-5 { - margin-left: 41.66666667% -} - -.col-xs-offset-4 { - margin-left: 33.33333333% -} - -.col-xs-offset-3 { - margin-left: 25% -} - -.col-xs-offset-2 { - margin-left: 16.66666667% -} - -.col-xs-offset-1 { - margin-left: 8.33333333% -} - -.col-xs-offset-0 { - margin-left: 0 -} - -@media ( min-width :768px) { - .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, - .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9 { - float: left - } - .col-sm-12 { - width: 100% - } - .col-sm-11 { - width: 91.66666667% - } - .col-sm-10 { - width: 83.33333333% - } - .col-sm-9 { - width: 75% - } - .col-sm-8 { - width: 66.66666667% - } - .col-sm-7 { - width: 58.33333333% - } - .col-sm-6 { - width: 50% - } - .col-sm-5 { - width: 41.66666667% - } - .col-sm-4 { - width: 33.33333333% - } - .col-sm-3 { - width: 25% - } - .col-sm-2 { - width: 16.66666667% - } - .col-sm-1 { - width: 8.33333333% - } - .col-sm-pull-12 { - right: 100% - } - .col-sm-pull-11 { - right: 91.66666667% - } - .col-sm-pull-10 { - right: 83.33333333% - } - .col-sm-pull-9 { - right: 75% - } - .col-sm-pull-8 { - right: 66.66666667% - } - .col-sm-pull-7 { - right: 58.33333333% - } - .col-sm-pull-6 { - right: 50% - } - .col-sm-pull-5 { - right: 41.66666667% - } - .col-sm-pull-4 { - right: 33.33333333% - } - .col-sm-pull-3 { - right: 25% - } - .col-sm-pull-2 { - right: 16.66666667% - } - .col-sm-pull-1 { - right: 8.33333333% - } - .col-sm-pull-0 { - right: auto - } - .col-sm-push-12 { - left: 100% - } - .col-sm-push-11 { - left: 91.66666667% - } - .col-sm-push-10 { - left: 83.33333333% - } - .col-sm-push-9 { - left: 75% - } - .col-sm-push-8 { - left: 66.66666667% - } - .col-sm-push-7 { - left: 58.33333333% - } - .col-sm-push-6 { - left: 50% - } - .col-sm-push-5 { - left: 41.66666667% - } - .col-sm-push-4 { - left: 33.33333333% - } - .col-sm-push-3 { - left: 25% - } - .col-sm-push-2 { - left: 16.66666667% - } - .col-sm-push-1 { - left: 8.33333333% - } - .col-sm-push-0 { - left: auto - } - .col-sm-offset-12 { - margin-left: 100% - } - .col-sm-offset-11 { - margin-left: 91.66666667% - } - .col-sm-offset-10 { - margin-left: 83.33333333% - } - .col-sm-offset-9 { - margin-left: 75% - } - .col-sm-offset-8 { - margin-left: 66.66666667% - } - .col-sm-offset-7 { - margin-left: 58.33333333% - } - .col-sm-offset-6 { - margin-left: 50% - } - .col-sm-offset-5 { - margin-left: 41.66666667% - } - .col-sm-offset-4 { - margin-left: 33.33333333% - } - .col-sm-offset-3 { - margin-left: 25% - } - .col-sm-offset-2 { - margin-left: 16.66666667% - } - .col-sm-offset-1 { - margin-left: 8.33333333% - } - .col-sm-offset-0 { - margin-left: 0 - } -} - -@media ( min-width :992px) { - .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, - .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9 { - float: left - } - .col-md-12 { - width: 100% - } - .col-md-11 { - width: 91.66666667% - } - .col-md-10 { - width: 83.33333333% - } - .col-md-9 { - width: 75% - } - .col-md-8 { - width: 66.66666667% - } - .col-md-7 { - width: 58.33333333% - } - .col-md-6 { - width: 50% - } - .col-md-5 { - width: 41.66666667% - } - .col-md-4 { - width: 33.33333333% - } - .col-md-3 { - width: 25% - } - .col-md-2 { - width: 16.66666667% - } - .col-md-1 { - width: 8.33333333% - } - .col-md-pull-12 { - right: 100% - } - .col-md-pull-11 { - right: 91.66666667% - } - .col-md-pull-10 { - right: 83.33333333% - } - .col-md-pull-9 { - right: 75% - } - .col-md-pull-8 { - right: 66.66666667% - } - .col-md-pull-7 { - right: 58.33333333% - } - .col-md-pull-6 { - right: 50% - } - .col-md-pull-5 { - right: 41.66666667% - } - .col-md-pull-4 { - right: 33.33333333% - } - .col-md-pull-3 { - right: 25% - } - .col-md-pull-2 { - right: 16.66666667% - } - .col-md-pull-1 { - right: 8.33333333% - } - .col-md-pull-0 { - right: auto - } - .col-md-push-12 { - left: 100% - } - .col-md-push-11 { - left: 91.66666667% - } - .col-md-push-10 { - left: 83.33333333% - } - .col-md-push-9 { - left: 75% - } - .col-md-push-8 { - left: 66.66666667% - } - .col-md-push-7 { - left: 58.33333333% - } - .col-md-push-6 { - left: 50% - } - .col-md-push-5 { - left: 41.66666667% - } - .col-md-push-4 { - left: 33.33333333% - } - .col-md-push-3 { - left: 25% - } - .col-md-push-2 { - left: 16.66666667% - } - .col-md-push-1 { - left: 8.33333333% - } - .col-md-push-0 { - left: auto - } - .col-md-offset-12 { - margin-left: 100% - } - .col-md-offset-11 { - margin-left: 91.66666667% - } - .col-md-offset-10 { - margin-left: 83.33333333% - } - .col-md-offset-9 { - margin-left: 75% - } - .col-md-offset-8 { - margin-left: 66.66666667% - } - .col-md-offset-7 { - margin-left: 58.33333333% - } - .col-md-offset-6 { - margin-left: 50% - } - .col-md-offset-5 { - margin-left: 41.66666667% - } - .col-md-offset-4 { - margin-left: 33.33333333% - } - .col-md-offset-3 { - margin-left: 25% - } - .col-md-offset-2 { - margin-left: 16.66666667% - } - .col-md-offset-1 { - margin-left: 8.33333333% - } - .col-md-offset-0 { - margin-left: 0 - } -} - -@media ( min-width :1200px) { - .col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, - .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9 { - float: left - } - .col-lg-12 { - width: 100% - } - .col-lg-11 { - width: 91.66666667% - } - .col-lg-10 { - width: 83.33333333% - } - .col-lg-9 { - width: 75% - } - .col-lg-8 { - width: 66.66666667% - } - .col-lg-7 { - width: 58.33333333% - } - .col-lg-6 { - width: 50% - } - .col-lg-5 { - width: 41.66666667% - } - .col-lg-4 { - width: 33.33333333% - } - .col-lg-3 { - width: 25% - } - .col-lg-2 { - width: 16.66666667% - } - .col-lg-1 { - width: 8.33333333% - } - .col-lg-pull-12 { - right: 100% - } - .col-lg-pull-11 { - right: 91.66666667% - } - .col-lg-pull-10 { - right: 83.33333333% - } - .col-lg-pull-9 { - right: 75% - } - .col-lg-pull-8 { - right: 66.66666667% - } - .col-lg-pull-7 { - right: 58.33333333% - } - .col-lg-pull-6 { - right: 50% - } - .col-lg-pull-5 { - right: 41.66666667% - } - .col-lg-pull-4 { - right: 33.33333333% - } - .col-lg-pull-3 { - right: 25% - } - .col-lg-pull-2 { - right: 16.66666667% - } - .col-lg-pull-1 { - right: 8.33333333% - } - .col-lg-pull-0 { - right: auto - } - .col-lg-push-12 { - left: 100% - } - .col-lg-push-11 { - left: 91.66666667% - } - .col-lg-push-10 { - left: 83.33333333% - } - .col-lg-push-9 { - left: 75% - } - .col-lg-push-8 { - left: 66.66666667% - } - .col-lg-push-7 { - left: 58.33333333% - } - .col-lg-push-6 { - left: 50% - } - .col-lg-push-5 { - left: 41.66666667% - } - .col-lg-push-4 { - left: 33.33333333% - } - .col-lg-push-3 { - left: 25% - } - .col-lg-push-2 { - left: 16.66666667% - } - .col-lg-push-1 { - left: 8.33333333% - } - .col-lg-push-0 { - left: auto - } - .col-lg-offset-12 { - margin-left: 100% - } - .col-lg-offset-11 { - margin-left: 91.66666667% - } - .col-lg-offset-10 { - margin-left: 83.33333333% - } - .col-lg-offset-9 { - margin-left: 75% - } - .col-lg-offset-8 { - margin-left: 66.66666667% - } - .col-lg-offset-7 { - margin-left: 58.33333333% - } - .col-lg-offset-6 { - margin-left: 50% - } - .col-lg-offset-5 { - margin-left: 41.66666667% - } - .col-lg-offset-4 { - margin-left: 33.33333333% - } - .col-lg-offset-3 { - margin-left: 25% - } - .col-lg-offset-2 { - margin-left: 16.66666667% - } - .col-lg-offset-1 { - margin-left: 8.33333333% - } - .col-lg-offset-0 { - margin-left: 0 - } -} - -table { - background-color: transparent -} - -caption { - padding-top: 8px; - padding-bottom: 8px; - color: #777; - text-align: left -} - -th { - text-align: left -} - -.table { - width: 100%; - max-width: 100%; - margin-bottom: 20px -} - -.table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, - .table>thead>tr>td, .table>thead>tr>th { - padding: 8px; - line-height: 1.42857143; - vertical-align: top; - border-top: 1px solid #ddd -} - -.table>thead>tr>th { - vertical-align: bottom; - border-bottom: 2px solid #ddd -} - -.table>caption+thead>tr:first-child>td, .table>caption+thead>tr:first-child>th, - .table>colgroup+thead>tr:first-child>td, .table>colgroup+thead>tr:first-child>th, - .table>thead:first-child>tr:first-child>td, .table>thead:first-child>tr:first-child>th - { - border-top: 0 -} - -.table>tbody+tbody { - border-top: 2px solid #ddd -} - -.table .table { - background-color: #fff -} - -.table-condensed>tbody>tr>td, .table-condensed>tbody>tr>th, - .table-condensed>tfoot>tr>td, .table-condensed>tfoot>tr>th, - .table-condensed>thead>tr>td, .table-condensed>thead>tr>th { - padding: 5px -} - -.table-bordered { - border: 1px solid #ddd -} - -.table-bordered>tbody>tr>td, .table-bordered>tbody>tr>th, - .table-bordered>tfoot>tr>td, .table-bordered>tfoot>tr>th, - .table-bordered>thead>tr>td, .table-bordered>thead>tr>th { - border: 1px solid #ddd -} - -.table-bordered>thead>tr>td, .table-bordered>thead>tr>th { - border-bottom-width: 2px -} - -.table-striped>tbody>tr:nth-of-type(odd) { - background-color: #f9f9f9 -} - -.table-hover>tbody>tr:hover { - background-color: #f5f5f5 -} - -table col[class*=col-] { - position: static; - display: table-column; - float: none -} - -table td[class*=col-], table th[class*=col-] { - position: static; - display: table-cell; - float: none -} - -.table>tbody>tr.active>td, .table>tbody>tr.active>th, .table>tbody>tr>td.active, - .table>tbody>tr>th.active, .table>tfoot>tr.active>td, .table>tfoot>tr.active>th, - .table>tfoot>tr>td.active, .table>tfoot>tr>th.active, .table>thead>tr.active>td, - .table>thead>tr.active>th, .table>thead>tr>td.active, .table>thead>tr>th.active - { - background-color: #f5f5f5 -} - -.table-hover>tbody>tr.active:hover>td, .table-hover>tbody>tr.active:hover>th, - .table-hover>tbody>tr:hover>.active, .table-hover>tbody>tr>td.active:hover, - .table-hover>tbody>tr>th.active:hover { - background-color: #e8e8e8 -} - -.table>tbody>tr.success>td, .table>tbody>tr.success>th, .table>tbody>tr>td.success, - .table>tbody>tr>th.success, .table>tfoot>tr.success>td, .table>tfoot>tr.success>th, - .table>tfoot>tr>td.success, .table>tfoot>tr>th.success, .table>thead>tr.success>td, - .table>thead>tr.success>th, .table>thead>tr>td.success, .table>thead>tr>th.success - { - background-color: #dff0d8 -} - -.table-hover>tbody>tr.success:hover>td, .table-hover>tbody>tr.success:hover>th, - .table-hover>tbody>tr:hover>.success, .table-hover>tbody>tr>td.success:hover, - .table-hover>tbody>tr>th.success:hover { - background-color: #d0e9c6 -} - -.table>tbody>tr.info>td, .table>tbody>tr.info>th, .table>tbody>tr>td.info, - .table>tbody>tr>th.info, .table>tfoot>tr.info>td, .table>tfoot>tr.info>th, - .table>tfoot>tr>td.info, .table>tfoot>tr>th.info, .table>thead>tr.info>td, - .table>thead>tr.info>th, .table>thead>tr>td.info, .table>thead>tr>th.info - { - background-color: #d9edf7 -} - -.table-hover>tbody>tr.info:hover>td, .table-hover>tbody>tr.info:hover>th, - .table-hover>tbody>tr:hover>.info, .table-hover>tbody>tr>td.info:hover, - .table-hover>tbody>tr>th.info:hover { - background-color: #c4e3f3 -} - -.table>tbody>tr.warning>td, .table>tbody>tr.warning>th, .table>tbody>tr>td.warning, - .table>tbody>tr>th.warning, .table>tfoot>tr.warning>td, .table>tfoot>tr.warning>th, - .table>tfoot>tr>td.warning, .table>tfoot>tr>th.warning, .table>thead>tr.warning>td, - .table>thead>tr.warning>th, .table>thead>tr>td.warning, .table>thead>tr>th.warning - { - background-color: #fcf8e3 -} - -.table-hover>tbody>tr.warning:hover>td, .table-hover>tbody>tr.warning:hover>th, - .table-hover>tbody>tr:hover>.warning, .table-hover>tbody>tr>td.warning:hover, - .table-hover>tbody>tr>th.warning:hover { - background-color: #faf2cc -} - -.table>tbody>tr.danger>td, .table>tbody>tr.danger>th, .table>tbody>tr>td.danger, - .table>tbody>tr>th.danger, .table>tfoot>tr.danger>td, .table>tfoot>tr.danger>th, - .table>tfoot>tr>td.danger, .table>tfoot>tr>th.danger, .table>thead>tr.danger>td, - .table>thead>tr.danger>th, .table>thead>tr>td.danger, .table>thead>tr>th.danger - { - background-color: #f2dede -} - -.table-hover>tbody>tr.danger:hover>td, .table-hover>tbody>tr.danger:hover>th, - .table-hover>tbody>tr:hover>.danger, .table-hover>tbody>tr>td.danger:hover, - .table-hover>tbody>tr>th.danger:hover { - background-color: #ebcccc -} - -.table-responsive { - min-height: .01%; - overflow-x: auto -} - -@media screen and (max-width:767px) { - .table-responsive { - width: 100%; - margin-bottom: 15px; - overflow-y: hidden; - -ms-overflow-style: -ms-autohiding-scrollbar; - border: 1px solid #ddd - } - .table-responsive>.table { - margin-bottom: 0 - } - .table-responsive>.table>tbody>tr>td, .table-responsive>.table>tbody>tr>th, - .table-responsive>.table>tfoot>tr>td, .table-responsive>.table>tfoot>tr>th, - .table-responsive>.table>thead>tr>td, .table-responsive>.table>thead>tr>th - { - white-space: nowrap - } - .table-responsive>.table-bordered { - border: 0 - } - .table-responsive>.table-bordered>tbody>tr>td:first-child, - .table-responsive>.table-bordered>tbody>tr>th:first-child, - .table-responsive>.table-bordered>tfoot>tr>td:first-child, - .table-responsive>.table-bordered>tfoot>tr>th:first-child, - .table-responsive>.table-bordered>thead>tr>td:first-child, - .table-responsive>.table-bordered>thead>tr>th:first-child { - border-left: 0 - } - .table-responsive>.table-bordered>tbody>tr>td:last-child, - .table-responsive>.table-bordered>tbody>tr>th:last-child, - .table-responsive>.table-bordered>tfoot>tr>td:last-child, - .table-responsive>.table-bordered>tfoot>tr>th:last-child, - .table-responsive>.table-bordered>thead>tr>td:last-child, - .table-responsive>.table-bordered>thead>tr>th:last-child { - border-right: 0 - } - .table-responsive>.table-bordered>tbody>tr:last-child>td, - .table-responsive>.table-bordered>tbody>tr:last-child>th, - .table-responsive>.table-bordered>tfoot>tr:last-child>td, - .table-responsive>.table-bordered>tfoot>tr:last-child>th { - border-bottom: 0 - } -} - -fieldset { - min-width: 0; - padding: 0; - margin: 0; - border: 0 -} - -legend { - display: block; - width: 100%; - padding: 0; - margin-bottom: 20px; - font-size: 21px; - line-height: inherit; - color: #333; - border: 0; - border-bottom: 1px solid #e5e5e5 -} - -label { - display: inline-block; - max-width: 100%; - margin-bottom: 5px; - font-weight: 700 -} - -input[type=search] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box -} - -input[type=checkbox], input[type=radio] { - margin: 4px 0 0; - margin-top: 1px \9; - line-height: normal -} - -input[type=file] { - display: block -} - -input[type=range] { - display: block; - width: 100% -} - -select[multiple], select[size] { - height: auto -} - -input[type=file]:focus, input[type=checkbox]:focus, input[type=radio]:focus - { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px -} - -output { - display: block; - padding-top: 7px; - font-size: 14px; - line-height: 1.42857143; - color: #555 -} - -.form-control { - display: block; - width: 100%; - height: 34px; - padding: 6px 12px; - font-size: 14px; - line-height: 1.42857143; - color: #555; - background-color: #fff; - background-image: none; - border: 1px solid #ccc; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow - ease-in-out .15s; - -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out - .15s; - transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s -} - -.form-control:focus { - border-color: #66afe9; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px - rgba(102, 175, 233, .6); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px - rgba(102, 175, 233, .6) -} - -.form-control::-moz-placeholder { - color: #999; - opacity: 1 -} - -.form-control:-ms-input-placeholder { - color: #999 -} - -.form-control::-webkit-input-placeholder { - color: #999 -} - -.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control - { - background-color: #eee; - opacity: 1 -} - -.form-control[disabled], fieldset[disabled] .form-control { - cursor: not-allowed -} - -textarea.form-control { - height: auto -} - -input[type=search] { - -webkit-appearance: none -} - -@media screen and (-webkit-min-device-pixel-ratio:0) { - input[type=date], input[type=time], input[type=datetime-local], input[type=month] - { - line-height: 34px - } - .input-group-sm input[type=date], .input-group-sm input[type=time], - .input-group-sm input[type=datetime-local], .input-group-sm input[type=month], - input[type=date].input-sm, input[type=time].input-sm, input[type=datetime-local].input-sm, - input[type=month].input-sm { - line-height: 30px - } - .input-group-lg input[type=date], .input-group-lg input[type=time], - .input-group-lg input[type=datetime-local], .input-group-lg input[type=month], - input[type=date].input-lg, input[type=time].input-lg, input[type=datetime-local].input-lg, - input[type=month].input-lg { - line-height: 46px - } -} - -.form-group { - margin-bottom: 15px -} - -.checkbox, .radio { - position: relative; - display: block; - margin-top: 10px; - margin-bottom: 10px -} - -.checkbox label, .radio label { - min-height: 20px; - padding-left: 20px; - margin-bottom: 0; - font-weight: 400; - cursor: pointer -} - -.checkbox input[type=checkbox], .checkbox-inline input[type=checkbox], - .radio input[type=radio], .radio-inline input[type=radio] { - position: absolute; - margin-top: 4px \9; - margin-left: -20px -} - -.checkbox+.checkbox, .radio+.radio { - margin-top: -5px -} - -.checkbox-inline, .radio-inline { - position: relative; - display: inline-block; - padding-left: 20px; - margin-bottom: 0; - font-weight: 400; - vertical-align: middle; - cursor: pointer -} - -.checkbox-inline+.checkbox-inline, .radio-inline+.radio-inline { - margin-top: 0; - margin-left: 10px -} - -fieldset[disabled] input[type=checkbox], fieldset[disabled] input[type=radio], - input[type=checkbox].disabled, input[type=checkbox][disabled], input[type=radio].disabled, - input[type=radio][disabled] { - cursor: not-allowed -} - -.checkbox-inline.disabled, .radio-inline.disabled, fieldset[disabled] .checkbox-inline, - fieldset[disabled] .radio-inline { - cursor: not-allowed -} - -.checkbox.disabled label, .radio.disabled label, fieldset[disabled] .checkbox label, - fieldset[disabled] .radio label { - cursor: not-allowed -} - -.form-control-static { - min-height: 34px; - padding-top: 7px; - padding-bottom: 7px; - margin-bottom: 0 -} - -.form-control-static.input-lg, .form-control-static.input-sm { - padding-right: 0; - padding-left: 0 -} - -.input-sm { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px -} - -select.input-sm { - height: 30px; - line-height: 30px -} - -select[multiple].input-sm, textarea.input-sm { - height: auto -} - -.form-group-sm .form-control { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px -} - -select.form-group-sm .form-control { - height: 30px; - line-height: 30px -} - -select[multiple].form-group-sm .form-control, textarea.form-group-sm .form-control - { - height: auto -} - -.form-group-sm .form-control-static { - height: 30px; - min-height: 32px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5 -} - -.input-lg { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; - border-radius: 6px -} - -select.input-lg { - height: 46px; - line-height: 46px -} - -select[multiple].input-lg, textarea.input-lg { - height: auto -} - -.form-group-lg .form-control { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; - border-radius: 6px -} - -select.form-group-lg .form-control { - height: 46px; - line-height: 46px -} - -select[multiple].form-group-lg .form-control, textarea.form-group-lg .form-control - { - height: auto -} - -.form-group-lg .form-control-static { - height: 46px; - min-height: 38px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333 -} - -.has-feedback { - position: relative -} - -.has-feedback .form-control { - padding-right: 42.5px -} - -.form-control-feedback { - position: absolute; - top: 0; - right: 0; - z-index: 2; - display: block; - width: 34px; - height: 34px; - line-height: 34px; - text-align: center; - pointer-events: none -} - -.input-lg+.form-control-feedback { - width: 46px; - height: 46px; - line-height: 46px -} - -.input-sm+.form-control-feedback { - width: 30px; - height: 30px; - line-height: 30px -} - -.has-success .checkbox, .has-success .checkbox-inline, .has-success .control-label, - .has-success .help-block, .has-success .radio, .has-success .radio-inline, - .has-success.checkbox label, .has-success.checkbox-inline label, - .has-success.radio label, .has-success.radio-inline label { - color: #3c763d -} - -.has-success .form-control { - border-color: #3c763d; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075) -} - -.has-success .form-control:focus { - border-color: #2b542c; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168 -} - -.has-success .input-group-addon { - color: #3c763d; - background-color: #dff0d8; - border-color: #3c763d -} - -.has-success .form-control-feedback { - color: #3c763d -} - -.has-warning .checkbox, .has-warning .checkbox-inline, .has-warning .control-label, - .has-warning .help-block, .has-warning .radio, .has-warning .radio-inline, - .has-warning.checkbox label, .has-warning.checkbox-inline label, - .has-warning.radio label, .has-warning.radio-inline label { - color: #8a6d3b -} - -.has-warning .form-control { - border-color: #8a6d3b; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075) -} - -.has-warning .form-control:focus { - border-color: #66512c; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b -} - -.has-warning .input-group-addon { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #8a6d3b -} - -.has-warning .form-control-feedback { - color: #8a6d3b -} - -.has-error .checkbox, .has-error .checkbox-inline, .has-error .control-label, - .has-error .help-block, .has-error .radio, .has-error .radio-inline, - .has-error.checkbox label, .has-error.checkbox-inline label, .has-error.radio label, - .has-error.radio-inline label { - color: #a94442 -} - -.has-error .form-control { - border-color: #a94442; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075) -} - -.has-error .form-control:focus { - border-color: #843534; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483 -} - -.has-error .input-group-addon { - color: #a94442; - background-color: #f2dede; - border-color: #a94442 -} - -.has-error .form-control-feedback { - color: #a94442 -} - -.has-feedback label ~.form-control-feedback { - top: 25px -} - -.has-feedback label.sr-only ~.form-control-feedback { - top: 0 -} - -.help-block { - display: block; - margin-top: 5px; - margin-bottom: 10px; - color: #737373 -} - -@media ( min-width :768px) { - .form-inline .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle - } - .form-inline .form-control { - display: inline-block; - width: auto; - vertical-align: middle - } - .form-inline .form-control-static { - display: inline-block - } - .form-inline .input-group { - display: inline-table; - vertical-align: middle - } - .form-inline .input-group .form-control, .form-inline .input-group .input-group-addon, - .form-inline .input-group .input-group-btn { - width: auto - } - .form-inline .input-group>.form-control { - width: 100% - } - .form-inline .control-label { - margin-bottom: 0; - vertical-align: middle - } - .form-inline .checkbox, .form-inline .radio { - display: inline-block; - margin-top: 0; - margin-bottom: 0; - vertical-align: middle - } - .form-inline .checkbox label, .form-inline .radio label { - padding-left: 0 - } - .form-inline .checkbox input[type=checkbox], .form-inline .radio input[type=radio] - { - position: relative; - margin-left: 0 - } - .form-inline .has-feedback .form-control-feedback { - top: 0 - } -} - -.form-horizontal .checkbox, .form-horizontal .checkbox-inline, - .form-horizontal .radio, .form-horizontal .radio-inline { - padding-top: 7px; - margin-top: 0; - margin-bottom: 0 -} - -.form-horizontal .checkbox, .form-horizontal .radio { - min-height: 27px -} - -.form-horizontal .form-group { - margin-right: -15px; - margin-left: -15px -} - -@media ( min-width :768px) { - .form-horizontal .control-label { - padding-top: 7px; - margin-bottom: 0; - text-align: right - } -} - -.form-horizontal .has-feedback .form-control-feedback { - right: 15px -} - -@media ( min-width :768px) { - .form-horizontal .form-group-lg .control-label { - padding-top: 14.33px - } -} - -@media ( min-width :768px) { - .form-horizontal .form-group-sm .control-label { - padding-top: 6px - } -} - -.btn { - display: inline-block; - padding: 6px 12px; - margin-bottom: 0; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - text-align: center; - white-space: nowrap; - vertical-align: middle; - -ms-touch-action: manipulation; - touch-action: manipulation; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - background-image: none; - border: 1px solid transparent; - border-radius: 4px -} - -.btn.active.focus, .btn.active:focus, .btn.focus, .btn:active.focus, - .btn:active:focus, .btn:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px -} - -.btn.focus, .btn:focus, .btn:hover { - color: #333; - text-decoration: none -} - -.btn.active, .btn:active { - background-image: none; - outline: 0; - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125) -} - -.btn.disabled, .btn[disabled], fieldset[disabled] .btn { - pointer-events: none; - cursor: not-allowed; - filter: alpha(opacity = 65); - -webkit-box-shadow: none; - box-shadow: none; - opacity: .65 -} - -.btn-default { - color: #333; - background-color: #fff; - border-color: #ccc -} - -.btn-default.active, .btn-default.focus, .btn-default:active, - .btn-default:focus, .btn-default:hover, .open>.dropdown-toggle.btn-default - { - color: #333; - background-color: #e6e6e6; - border-color: #adadad -} - -.btn-default.active, .btn-default:active, .open>.dropdown-toggle.btn-default - { - background-image: none -} - -.btn-default.disabled, .btn-default.disabled.active, .btn-default.disabled.focus, - .btn-default.disabled:active, .btn-default.disabled:focus, .btn-default.disabled:hover, - .btn-default[disabled], .btn-default[disabled].active, .btn-default[disabled].focus, - .btn-default[disabled]:active, .btn-default[disabled]:focus, - .btn-default[disabled]:hover, fieldset[disabled] .btn-default, fieldset[disabled] .btn-default.active, - fieldset[disabled] .btn-default.focus, fieldset[disabled] .btn-default:active, - fieldset[disabled] .btn-default:focus, fieldset[disabled] .btn-default:hover - { - background-color: #fff; - border-color: #ccc -} - -.btn-default .badge { - color: #fff; - background-color: #333 -} - -.btn-primary { - color: #fff; - background-color: #337ab7; - border-color: #2e6da4 -} - -.btn-primary.active, .btn-primary.focus, .btn-primary:active, - .btn-primary:focus, .btn-primary:hover, .open>.dropdown-toggle.btn-primary - { - color: #fff; - background-color: #286090; - border-color: #204d74 -} - -.btn-primary.active, .btn-primary:active, .open>.dropdown-toggle.btn-primary - { - background-image: none -} - -.btn-primary.disabled, .btn-primary.disabled.active, .btn-primary.disabled.focus, - .btn-primary.disabled:active, .btn-primary.disabled:focus, .btn-primary.disabled:hover, - .btn-primary[disabled], .btn-primary[disabled].active, .btn-primary[disabled].focus, - .btn-primary[disabled]:active, .btn-primary[disabled]:focus, - .btn-primary[disabled]:hover, fieldset[disabled] .btn-primary, fieldset[disabled] .btn-primary.active, - fieldset[disabled] .btn-primary.focus, fieldset[disabled] .btn-primary:active, - fieldset[disabled] .btn-primary:focus, fieldset[disabled] .btn-primary:hover - { - background-color: #337ab7; - border-color: #2e6da4 -} - -.btn-primary .badge { - color: #337ab7; - background-color: #fff -} - -.btn-success { - color: #fff; - background-color: #5cb85c; - border-color: #4cae4c -} - -.btn-success.active, .btn-success.focus, .btn-success:active, - .btn-success:focus, .btn-success:hover, .open>.dropdown-toggle.btn-success - { - color: #fff; - background-color: #449d44; - border-color: #398439 -} - -.btn-success.active, .btn-success:active, .open>.dropdown-toggle.btn-success - { - background-image: none -} - -.btn-success.disabled, .btn-success.disabled.active, .btn-success.disabled.focus, - .btn-success.disabled:active, .btn-success.disabled:focus, .btn-success.disabled:hover, - .btn-success[disabled], .btn-success[disabled].active, .btn-success[disabled].focus, - .btn-success[disabled]:active, .btn-success[disabled]:focus, - .btn-success[disabled]:hover, fieldset[disabled] .btn-success, fieldset[disabled] .btn-success.active, - fieldset[disabled] .btn-success.focus, fieldset[disabled] .btn-success:active, - fieldset[disabled] .btn-success:focus, fieldset[disabled] .btn-success:hover - { - background-color: #5cb85c; - border-color: #4cae4c -} - -.btn-success .badge { - color: #5cb85c; - background-color: #fff -} - -.btn-info { - color: #fff; - background-color: #5bc0de; - border-color: #46b8da -} - -.btn-info.active, .btn-info.focus, .btn-info:active, .btn-info:focus, - .btn-info:hover, .open>.dropdown-toggle.btn-info { - color: #fff; - background-color: #31b0d5; - border-color: #269abc -} - -.btn-info.active, .btn-info:active, .open>.dropdown-toggle.btn-info { - background-image: none -} - -.btn-info.disabled, .btn-info.disabled.active, .btn-info.disabled.focus, - .btn-info.disabled:active, .btn-info.disabled:focus, .btn-info.disabled:hover, - .btn-info[disabled], .btn-info[disabled].active, .btn-info[disabled].focus, - .btn-info[disabled]:active, .btn-info[disabled]:focus, .btn-info[disabled]:hover, - fieldset[disabled] .btn-info, fieldset[disabled] .btn-info.active, - fieldset[disabled] .btn-info.focus, fieldset[disabled] .btn-info:active, - fieldset[disabled] .btn-info:focus, fieldset[disabled] .btn-info:hover - { - background-color: #5bc0de; - border-color: #46b8da -} - -.btn-info .badge { - color: #5bc0de; - background-color: #fff -} - -.btn-warning { - color: #fff; - background-color: #f0ad4e; - border-color: #eea236 -} - -.btn-warning.active, .btn-warning.focus, .btn-warning:active, - .btn-warning:focus, .btn-warning:hover, .open>.dropdown-toggle.btn-warning - { - color: #fff; - background-color: #ec971f; - border-color: #d58512 -} - -.btn-warning.active, .btn-warning:active, .open>.dropdown-toggle.btn-warning - { - background-image: none -} - -.btn-warning.disabled, .btn-warning.disabled.active, .btn-warning.disabled.focus, - .btn-warning.disabled:active, .btn-warning.disabled:focus, .btn-warning.disabled:hover, - .btn-warning[disabled], .btn-warning[disabled].active, .btn-warning[disabled].focus, - .btn-warning[disabled]:active, .btn-warning[disabled]:focus, - .btn-warning[disabled]:hover, fieldset[disabled] .btn-warning, fieldset[disabled] .btn-warning.active, - fieldset[disabled] .btn-warning.focus, fieldset[disabled] .btn-warning:active, - fieldset[disabled] .btn-warning:focus, fieldset[disabled] .btn-warning:hover - { - background-color: #f0ad4e; - border-color: #eea236 -} - -.btn-warning .badge { - color: #f0ad4e; - background-color: #fff -} - -.btn-danger { - color: #fff; - background-color: #d9534f; - border-color: #d43f3a -} - -.btn-danger.active, .btn-danger.focus, .btn-danger:active, .btn-danger:focus, - .btn-danger:hover, .open>.dropdown-toggle.btn-danger { - color: #fff; - background-color: #c9302c; - border-color: #ac2925 -} - -.btn-danger.active, .btn-danger:active, .open>.dropdown-toggle.btn-danger - { - background-image: none -} - -.btn-danger.disabled, .btn-danger.disabled.active, .btn-danger.disabled.focus, - .btn-danger.disabled:active, .btn-danger.disabled:focus, .btn-danger.disabled:hover, - .btn-danger[disabled], .btn-danger[disabled].active, .btn-danger[disabled].focus, - .btn-danger[disabled]:active, .btn-danger[disabled]:focus, .btn-danger[disabled]:hover, - fieldset[disabled] .btn-danger, fieldset[disabled] .btn-danger.active, - fieldset[disabled] .btn-danger.focus, fieldset[disabled] .btn-danger:active, - fieldset[disabled] .btn-danger:focus, fieldset[disabled] .btn-danger:hover - { - background-color: #d9534f; - border-color: #d43f3a -} - -.btn-danger .badge { - color: #d9534f; - background-color: #fff -} - -.btn-link { - font-weight: 400; - color: #337ab7; - border-radius: 0 -} - -.btn-link, .btn-link.active, .btn-link:active, .btn-link[disabled], - fieldset[disabled] .btn-link { - background-color: transparent; - -webkit-box-shadow: none; - box-shadow: none -} - -.btn-link, .btn-link:active, .btn-link:focus, .btn-link:hover { - border-color: transparent -} - -.btn-link:focus, .btn-link:hover { - color: #23527c; - text-decoration: underline; - background-color: transparent -} - -.btn-link[disabled]:focus, .btn-link[disabled]:hover, fieldset[disabled] .btn-link:focus, - fieldset[disabled] .btn-link:hover { - color: #777; - text-decoration: none -} - -.btn-group-lg>.btn, .btn-lg { - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; - border-radius: 6px -} - -.btn-group-sm>.btn, .btn-sm { - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px -} - -.btn-group-xs>.btn, .btn-xs { - padding: 1px 5px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px -} - -.btn-block { - display: block; - width: 100% -} - -.btn-block+.btn-block { - margin-top: 5px -} - -input[type=button].btn-block, input[type=reset].btn-block, input[type=submit].btn-block - { - width: 100% -} - -.fade { - opacity: 0; - -webkit-transition: opacity .15s linear; - -o-transition: opacity .15s linear; - transition: opacity .15s linear -} - -.fade.in { - opacity: 1 -} - -.collapse { - display: none -} - -.collapse.in { - display: block -} - -tr.collapse.in { - display: table-row -} - -tbody.collapse.in { - display: table-row-group -} - -.collapsing { - position: relative; - height: 0; - overflow: hidden; - -webkit-transition-timing-function: ease; - -o-transition-timing-function: ease; - transition-timing-function: ease; - -webkit-transition-duration: .35s; - -o-transition-duration: .35s; - transition-duration: .35s; - -webkit-transition-property: height, visibility; - -o-transition-property: height, visibility; - transition-property: height, visibility -} - -.caret { - display: inline-block; - width: 0; - height: 0; - margin-left: 2px; - vertical-align: middle; - border-top: 4px dashed; - border-right: 4px solid transparent; - border-left: 4px solid transparent -} - -.dropdown, .dropup { - position: relative -} - -.dropdown-toggle:focus { - outline: 0 -} - -.dropdown-menu { - position: absolute; - top: 100%; - left: 0; - z-index: 1000; - display: none; - float: left; - min-width: 160px; - padding: 5px 0; - margin: 2px 0 0; - font-size: 14px; - text-align: left; - list-style: none; - background-color: #fff; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, .15); - border-radius: 4px; - -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175); - box-shadow: 0 6px 12px rgba(0, 0, 0, .175) -} - -.dropdown-menu.pull-right { - right: 0; - left: auto -} - -.dropdown-menu .divider { - height: 1px; - margin: 9px 0; - overflow: hidden; - background-color: #e5e5e5 -} - -.dropdown-menu>li>a { - display: block; - padding: 3px 20px; - clear: both; - font-weight: 400; - line-height: 1.42857143; - color: #333; - white-space: nowrap -} - -.dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover { - color: #262626; - text-decoration: none; - background-color: #f5f5f5 -} - -.dropdown-menu>.active>a, .dropdown-menu>.active>a:focus, .dropdown-menu>.active>a:hover - { - color: #fff; - text-decoration: none; - background-color: #337ab7; - outline: 0 -} - -.dropdown-menu>.disabled>a, .dropdown-menu>.disabled>a:focus, - .dropdown-menu>.disabled>a:hover { - color: #777 -} - -.dropdown-menu>.disabled>a:focus, .dropdown-menu>.disabled>a:hover { - text-decoration: none; - cursor: not-allowed; - background-color: transparent; - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false) -} - -.open>.dropdown-menu { - display: block -} - -.open>a { - outline: 0 -} - -.dropdown-menu-right { - right: 0; - left: auto -} - -.dropdown-menu-left { - right: auto; - left: 0 -} - -.dropdown-header { - display: block; - padding: 3px 20px; - font-size: 12px; - line-height: 1.42857143; - color: #777; - white-space: nowrap -} - -.dropdown-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 990 -} - -.pull-right>.dropdown-menu { - right: 0; - left: auto -} - -.dropup .caret, .navbar-fixed-bottom .dropdown .caret { - content: ""; - border-top: 0; - border-bottom: 4px solid -} - -.dropup .dropdown-menu, .navbar-fixed-bottom .dropdown .dropdown-menu { - top: auto; - bottom: 100%; - margin-bottom: 2px -} - -@media ( min-width :768px) { - .navbar-right .dropdown-menu { - right: 0; - left: auto - } - .navbar-right .dropdown-menu-left { - right: auto; - left: 0 - } -} - -.btn-group, .btn-group-vertical { - position: relative; - display: inline-block; - vertical-align: middle -} - -.btn-group-vertical>.btn, .btn-group>.btn { - position: relative; - float: left -} - -.btn-group-vertical>.btn.active, .btn-group-vertical>.btn:active, - .btn-group-vertical>.btn:focus, .btn-group-vertical>.btn:hover, - .btn-group>.btn.active, .btn-group>.btn:active, .btn-group>.btn:focus, - .btn-group>.btn:hover { - z-index: 2 -} - -.btn-group .btn+.btn, .btn-group .btn+.btn-group, .btn-group .btn-group+.btn, - .btn-group .btn-group+.btn-group { - margin-left: -1px -} - -.btn-toolbar { - margin-left: -5px -} - -.btn-toolbar .btn-group, .btn-toolbar .input-group { - float: left -} - -.btn-toolbar>.btn, .btn-toolbar>.btn-group, .btn-toolbar>.input-group { - margin-left: 5px -} - -.btn-group>.btn:not (:first-child ):not (:last-child ):not (.dropdown-toggle - ){ - border-radius: 0 -} - -.btn-group>.btn:first-child { - margin-left: 0 -} - -.btn-group>.btn:first-child:not (:last-child ):not (.dropdown-toggle ){ - border-top-right-radius: 0; - border-bottom-right-radius: 0 -} - -.btn-group>.btn:last-child:not (:first-child ), .btn-group>.dropdown-toggle:not - (:first-child ){ - border-top-left-radius: 0; - border-bottom-left-radius: 0 -} - -.btn-group>.btn-group { - float: left -} - -.btn-group>.btn-group:not (:first-child ):not (:last-child )>.btn { - border-radius: 0 -} - -.btn-group>.btn-group:first-child:not (:last-child )>.btn:last-child, - .btn-group>.btn-group:first-child:not (:last-child )>.dropdown-toggle { - border-top-right-radius: 0; - border-bottom-right-radius: 0 -} - -.btn-group>.btn-group:last-child:not (:first-child )>.btn:first-child { - border-top-left-radius: 0; - border-bottom-left-radius: 0 -} - -.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { - outline: 0 -} - -.btn-group>.btn+.dropdown-toggle { - padding-right: 8px; - padding-left: 8px -} - -.btn-group>.btn-lg+.dropdown-toggle { - padding-right: 12px; - padding-left: 12px -} - -.btn-group.open .dropdown-toggle { - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125) -} - -.btn-group.open .dropdown-toggle.btn-link { - -webkit-box-shadow: none; - box-shadow: none -} - -.btn .caret { - margin-left: 0 -} - -.btn-lg .caret { - border-width: 5px 5px 0; - border-bottom-width: 0 -} - -.dropup .btn-lg .caret { - border-width: 0 5px 5px -} - -.btn-group-vertical>.btn, .btn-group-vertical>.btn-group, - .btn-group-vertical>.btn-group>.btn { - display: block; - float: none; - width: 100%; - max-width: 100% -} - -.btn-group-vertical>.btn-group>.btn { - float: none -} - -.btn-group-vertical>.btn+.btn, .btn-group-vertical>.btn+.btn-group, - .btn-group-vertical>.btn-group+.btn, .btn-group-vertical>.btn-group+.btn-group - { - margin-top: -1px; - margin-left: 0 -} - -.btn-group-vertical>.btn:not (:first-child ):not (:last-child ){ - border-radius: 0 -} - -.btn-group-vertical>.btn:first-child:not (:last-child ){ - border-top-right-radius: 4px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0 -} - -.btn-group-vertical>.btn:last-child:not (:first-child ){ - border-top-left-radius: 0; - border-top-right-radius: 0; - border-bottom-left-radius: 4px -} - -.btn-group-vertical>.btn-group:not (:first-child ):not (:last-child )>.btn - { - border-radius: 0 -} - -.btn-group-vertical>.btn-group:first-child:not (:last-child )>.btn:last-child, - .btn-group-vertical>.btn-group:first-child:not (:last-child )>.dropdown-toggle - { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0 -} - -.btn-group-vertical>.btn-group:last-child:not (:first-child )>.btn:first-child - { - border-top-left-radius: 0; - border-top-right-radius: 0 -} - -.btn-group-justified { - display: table; - width: 100%; - table-layout: fixed; - border-collapse: separate -} - -.btn-group-justified>.btn, .btn-group-justified>.btn-group { - display: table-cell; - float: none; - width: 1% -} - -.btn-group-justified>.btn-group .btn { - width: 100% -} - -.btn-group-justified>.btn-group .dropdown-menu { - left: auto -} - -[data-toggle=buttons]>.btn input[type=checkbox], [data-toggle=buttons]>.btn input[type=radio], - [data-toggle=buttons]>.btn-group>.btn input[type=checkbox], [data-toggle=buttons]>.btn-group>.btn input[type=radio] - { - position: absolute; - clip: rect(0, 0, 0, 0); - pointer-events: none -} - -.input-group { - position: relative; - display: table; - border-collapse: separate -} - -.input-group[class*=col-] { - float: none; - padding-right: 0; - padding-left: 0 -} - -.input-group .form-control { - position: relative; - z-index: 2; - float: left; - width: 100%; - margin-bottom: 0 -} - -.input-group-lg>.form-control, .input-group-lg>.input-group-addon, - .input-group-lg>.input-group-btn>.btn { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; - border-radius: 6px -} - -select.input-group-lg>.form-control, select.input-group-lg>.input-group-addon, - select.input-group-lg>.input-group-btn>.btn { - height: 46px; - line-height: 46px -} - -select[multiple].input-group-lg>.form-control, select[multiple].input-group-lg>.input-group-addon, - select[multiple].input-group-lg>.input-group-btn>.btn, textarea.input-group-lg>.form-control, - textarea.input-group-lg>.input-group-addon, textarea.input-group-lg>.input-group-btn>.btn - { - height: auto -} - -.input-group-sm>.form-control, .input-group-sm>.input-group-addon, - .input-group-sm>.input-group-btn>.btn { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px -} - -select.input-group-sm>.form-control, select.input-group-sm>.input-group-addon, - select.input-group-sm>.input-group-btn>.btn { - height: 30px; - line-height: 30px -} - -select[multiple].input-group-sm>.form-control, select[multiple].input-group-sm>.input-group-addon, - select[multiple].input-group-sm>.input-group-btn>.btn, textarea.input-group-sm>.form-control, - textarea.input-group-sm>.input-group-addon, textarea.input-group-sm>.input-group-btn>.btn - { - height: auto -} - -.input-group .form-control, .input-group-addon, .input-group-btn { - display: table-cell -} - -.input-group .form-control:not (:first-child ):not (:last-child ), - .input-group-addon:not (:first-child ):not (:last-child ), - .input-group-btn:not (:first-child ):not (:last-child ){ - border-radius: 0 -} - -.input-group-addon, .input-group-btn { - width: 1%; - white-space: nowrap; - vertical-align: middle -} - -.input-group-addon { - padding: 6px 12px; - font-size: 14px; - font-weight: 400; - line-height: 1; - color: #555; - text-align: center; - background-color: #eee; - border: 1px solid #ccc; - border-radius: 4px -} - -.input-group-addon.input-sm { - padding: 5px 10px; - font-size: 12px; - border-radius: 3px -} - -.input-group-addon.input-lg { - padding: 10px 16px; - font-size: 18px; - border-radius: 6px -} - -.input-group-addon input[type=checkbox], .input-group-addon input[type=radio] - { - margin-top: 0 -} - -.input-group .form-control:first-child, .input-group-addon:first-child, - .input-group-btn:first-child>.btn, .input-group-btn:first-child>.btn-group>.btn, - .input-group-btn:first-child>.dropdown-toggle, .input-group-btn:last-child>.btn-group:not - (:last-child )>.btn, .input-group-btn:last-child>.btn:not (:last-child - ):not (.dropdown-toggle ){ - border-top-right-radius: 0; - border-bottom-right-radius: 0 -} - -.input-group-addon:first-child { - border-right: 0 -} - -.input-group .form-control:last-child, .input-group-addon:last-child, - .input-group-btn:first-child>.btn-group:not (:first-child )>.btn, - .input-group-btn:first-child>.btn:not (:first-child ), .input-group-btn:last-child>.btn, - .input-group-btn:last-child>.btn-group>.btn, .input-group-btn:last-child>.dropdown-toggle - { - border-top-left-radius: 0; - border-bottom-left-radius: 0 -} - -.input-group-addon:last-child { - border-left: 0 -} - -.input-group-btn { - position: relative; - font-size: 0; - white-space: nowrap -} - -.input-group-btn>.btn { - position: relative -} - -.input-group-btn>.btn+.btn { - margin-left: -1px -} - -.input-group-btn>.btn:active, .input-group-btn>.btn:focus, - .input-group-btn>.btn:hover { - z-index: 2 -} - -.input-group-btn:first-child>.btn, .input-group-btn:first-child>.btn-group - { - margin-right: -1px -} - -.input-group-btn:last-child>.btn, .input-group-btn:last-child>.btn-group - { - margin-left: -1px -} - -.nav { - padding-left: 0; - margin-bottom: 0; - list-style: none -} - -.nav>li { - position: relative; - display: block -} - -.nav>li>a { - position: relative; - display: block; - padding: 10px 15px -} - -.nav>li>a:focus, .nav>li>a:hover { - text-decoration: none; - background-color: #eee -} - -.nav>li.disabled>a { - color: #777 -} - -.nav>li.disabled>a:focus, .nav>li.disabled>a:hover { - color: #777; - text-decoration: none; - cursor: not-allowed; - background-color: transparent -} - -.nav .open>a, .nav .open>a:focus, .nav .open>a:hover { - background-color: #eee; - border-color: #337ab7 -} - -.nav .nav-divider { - height: 1px; - margin: 9px 0; - overflow: hidden; - background-color: #e5e5e5 -} - -.nav>li>a>img { - max-width: none -} - -.nav-tabs { - border-bottom: 1px solid #ddd -} - -.nav-tabs>li { - float: left; - margin-bottom: -1px -} - -.nav-tabs>li>a { - margin-right: 2px; - line-height: 1.42857143; - border: 1px solid transparent; - border-radius: 4px 4px 0 0 -} - -.nav-tabs>li>a:hover { - border-color: #eee #eee #ddd -} - -.nav-tabs>li.active>a, .nav-tabs>li.active>a:focus, .nav-tabs>li.active>a:hover - { - color: #555; - cursor: default; - background-color: #fff; - border: 1px solid #ddd; - border-bottom-color: transparent -} - -.nav-tabs.nav-justified { - width: 100%; - border-bottom: 0 -} - -.nav-tabs.nav-justified>li { - float: none -} - -.nav-tabs.nav-justified>li>a { - margin-bottom: 5px; - text-align: center -} - -.nav-tabs.nav-justified>.dropdown .dropdown-menu { - top: auto; - left: auto -} - -@media ( min-width :768px) { - .nav-tabs.nav-justified>li { - display: table-cell; - width: 1% - } - .nav-tabs.nav-justified>li>a { - margin-bottom: 0 - } -} - -.nav-tabs.nav-justified>li>a { - margin-right: 0; - border-radius: 4px -} - -.nav-tabs.nav-justified>.active>a, .nav-tabs.nav-justified>.active>a:focus, - .nav-tabs.nav-justified>.active>a:hover { - border: 1px solid #ddd -} - -@media ( min-width :768px) { - .nav-tabs.nav-justified>li>a { - border-bottom: 1px solid #ddd; - border-radius: 4px 4px 0 0 - } - .nav-tabs.nav-justified>.active>a, .nav-tabs.nav-justified>.active>a:focus, - .nav-tabs.nav-justified>.active>a:hover { - border-bottom-color: #fff - } -} - -.nav-pills>li { - float: left -} - -.nav-pills>li>a { - border-radius: 4px -} - -.nav-pills>li+li { - margin-left: 2px -} - -.nav-pills>li.active>a, .nav-pills>li.active>a:focus, .nav-pills>li.active>a:hover - { - color: #fff; - background-color: #337ab7 -} - -.nav-stacked>li { - float: none -} - -.nav-stacked>li+li { - margin-top: 2px; - margin-left: 0 -} - -.nav-justified { - width: 100% -} - -.nav-justified>li { - float: none -} - -.nav-justified>li>a { - margin-bottom: 5px; - text-align: center -} - -.nav-justified>.dropdown .dropdown-menu { - top: auto; - left: auto -} - -@media ( min-width :768px) { - .nav-justified>li { - display: table-cell; - width: 1% - } - .nav-justified>li>a { - margin-bottom: 0 - } -} - -.nav-tabs-justified { - border-bottom: 0 -} - -.nav-tabs-justified>li>a { - margin-right: 0; - border-radius: 4px -} - -.nav-tabs-justified>.active>a, .nav-tabs-justified>.active>a:focus, - .nav-tabs-justified>.active>a:hover { - border: 1px solid #ddd -} - -@media ( min-width :768px) { - .nav-tabs-justified>li>a { - border-bottom: 1px solid #ddd; - border-radius: 4px 4px 0 0 - } - .nav-tabs-justified>.active>a, .nav-tabs-justified>.active>a:focus, - .nav-tabs-justified>.active>a:hover { - border-bottom-color: #fff - } -} - -.tab-content>.tab-pane { - display: none -} - -.tab-content>.active { - display: block -} - -.nav-tabs .dropdown-menu { - margin-top: -1px; - border-top-left-radius: 0; - border-top-right-radius: 0 -} - -.navbar { - position: relative; - min-height: 50px; - margin-bottom: 20px; - border: 1px solid transparent -} - -@media ( min-width :768px) { - .navbar { - border-radius: 4px - } -} - -@media ( min-width :768px) { - .navbar-header { - float: left - } -} - -.navbar-collapse { - padding-right: 15px; - padding-left: 15px; - overflow-x: visible; - -webkit-overflow-scrolling: touch; - border-top: 1px solid transparent; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1) -} - -.navbar-collapse.in { - overflow-y: auto -} - -@media ( min-width :768px) { - .navbar-collapse { - width: auto; - border-top: 0; - -webkit-box-shadow: none; - box-shadow: none - } - .navbar-collapse.collapse { - display: block !important; - height: auto !important; - padding-bottom: 0; - overflow: visible !important - } - .navbar-collapse.in { - overflow-y: visible - } - .navbar-fixed-bottom .navbar-collapse, .navbar-fixed-top .navbar-collapse, - .navbar-static-top .navbar-collapse { - padding-right: 0; - padding-left: 0 - } -} - -.navbar-fixed-bottom .navbar-collapse, .navbar-fixed-top .navbar-collapse - { - max-height: 340px -} - -@media ( max-device-width :480px)and (orientation:landscape) { - .navbar-fixed-bottom .navbar-collapse, .navbar-fixed-top .navbar-collapse - { - max-height: 200px - } -} - -.container-fluid>.navbar-collapse, .container-fluid>.navbar-header, - .container>.navbar-collapse, .container>.navbar-header { - margin-right: -15px; - margin-left: -15px -} - -@media ( min-width :768px) { - .container-fluid>.navbar-collapse, .container-fluid>.navbar-header, - .container>.navbar-collapse, .container>.navbar-header { - margin-right: 0; - margin-left: 0 - } -} - -.navbar-static-top { - z-index: 1000; - border-width: 0 0 1px -} - -@media ( min-width :768px) { - .navbar-static-top { - border-radius: 0 - } -} - -.navbar-fixed-bottom, .navbar-fixed-top { - position: fixed; - right: 0; - left: 0; - z-index: 1030 -} - -@media ( min-width :768px) { - .navbar-fixed-bottom, .navbar-fixed-top { - border-radius: 0 - } -} - -.navbar-fixed-top { - top: 0; - border-width: 0 0 1px -} - -.navbar-fixed-bottom { - bottom: 0; - margin-bottom: 0; - border-width: 1px 0 0 -} - -.navbar-brand { - float: left; - height: 50px; - padding: 15px 15px; - font-size: 18px; - line-height: 20px -} - -.navbar-brand:focus, .navbar-brand:hover { - text-decoration: none -} - -.navbar-brand>img { - display: block -} - -@media ( min-width :768px) { - .navbar>.container .navbar-brand, .navbar>.container-fluid .navbar-brand - { - margin-left: -15px - } -} - -.navbar-toggle { - position: relative; - float: right; - padding: 9px 10px; - margin-top: 8px; - margin-right: 15px; - margin-bottom: 8px; - background-color: transparent; - background-image: none; - border: 1px solid transparent; - border-radius: 4px -} - -.navbar-toggle:focus { - outline: 0 -} - -.navbar-toggle .icon-bar { - display: block; - width: 22px; - height: 2px; - border-radius: 1px -} - -.navbar-toggle .icon-bar+.icon-bar { - margin-top: 4px -} - -@media ( min-width :768px) { - .navbar-toggle { - display: none - } -} - -.navbar-nav { - margin: 7.5px -15px -} - -.navbar-nav>li>a { - padding-top: 10px; - padding-bottom: 10px; - line-height: 20px -} - -@media ( max-width :767px) { - .navbar-nav .open .dropdown-menu { - position: static; - float: none; - width: auto; - margin-top: 0; - background-color: transparent; - border: 0; - -webkit-box-shadow: none; - box-shadow: none - } - .navbar-nav .open .dropdown-menu .dropdown-header, .navbar-nav .open .dropdown-menu>li>a - { - padding: 5px 15px 5px 25px - } - .navbar-nav .open .dropdown-menu>li>a { - line-height: 20px - } - .navbar-nav .open .dropdown-menu>li>a:focus, .navbar-nav .open .dropdown-menu>li>a:hover - { - background-image: none - } -} - -@media ( min-width :768px) { - .navbar-nav { - float: left; - margin: 0 - } - .navbar-nav>li { - float: left - } - .navbar-nav>li>a { - padding-top: 15px; - padding-bottom: 15px - } -} - -.navbar-form { - padding: 10px 15px; - margin-top: 8px; - margin-right: -15px; - margin-bottom: 8px; - margin-left: -15px; - border-top: 1px solid transparent; - border-bottom: 1px solid transparent; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 - rgba(255, 255, 255, .1); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 - rgba(255, 255, 255, .1) -} - -@media ( min-width :768px) { - .navbar-form .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle - } - .navbar-form .form-control { - display: inline-block; - width: auto; - vertical-align: middle - } - .navbar-form .form-control-static { - display: inline-block - } - .navbar-form .input-group { - display: inline-table; - vertical-align: middle - } - .navbar-form .input-group .form-control, .navbar-form .input-group .input-group-addon, - .navbar-form .input-group .input-group-btn { - width: auto - } - .navbar-form .input-group>.form-control { - width: 100% - } - .navbar-form .control-label { - margin-bottom: 0; - vertical-align: middle - } - .navbar-form .checkbox, .navbar-form .radio { - display: inline-block; - margin-top: 0; - margin-bottom: 0; - vertical-align: middle - } - .navbar-form .checkbox label, .navbar-form .radio label { - padding-left: 0 - } - .navbar-form .checkbox input[type=checkbox], .navbar-form .radio input[type=radio] - { - position: relative; - margin-left: 0 - } - .navbar-form .has-feedback .form-control-feedback { - top: 0 - } -} - -@media ( max-width :767px) { - .navbar-form .form-group { - margin-bottom: 5px - } - .navbar-form .form-group:last-child { - margin-bottom: 0 - } -} - -@media ( min-width :768px) { - .navbar-form { - width: auto; - padding-top: 0; - padding-bottom: 0; - margin-right: 0; - margin-left: 0; - border: 0; - -webkit-box-shadow: none; - box-shadow: none - } -} - -.navbar-nav>li>.dropdown-menu { - margin-top: 0; - border-top-left-radius: 0; - border-top-right-radius: 0 -} - -.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu { - margin-bottom: 0; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0 -} - -.navbar-btn { - margin-top: 8px; - margin-bottom: 8px -} - -.navbar-btn.btn-sm { - margin-top: 10px; - margin-bottom: 10px -} - -.navbar-btn.btn-xs { - margin-top: 14px; - margin-bottom: 14px -} - -.navbar-text { - margin-top: 15px; - margin-bottom: 15px -} - -@media ( min-width :768px) { - .navbar-text { - float: left; - margin-right: 15px; - margin-left: 15px - } -} - -@media ( min-width :768px) { - .navbar-left { - float: left !important - } - .navbar-right { - float: right !important; - margin-right: -15px - } - .navbar-right ~.navbar-right { - margin-right: 0 - } -} - -.navbar-default { - background-color: #f8f8f8; - border-color: #e7e7e7 -} - -.navbar-default .navbar-brand { - color: #777 -} - -.navbar-default .navbar-brand:focus, .navbar-default .navbar-brand:hover - { - color: #5e5e5e; - background-color: transparent -} - -.navbar-default .navbar-text { - color: #777 -} - -.navbar-default .navbar-nav>li>a { - color: #777 -} - -.navbar-default .navbar-nav>li>a:focus, .navbar-default .navbar-nav>li>a:hover - { - color: #333; - background-color: transparent -} - -.navbar-default .navbar-nav>.active>a, .navbar-default .navbar-nav>.active>a:focus, - .navbar-default .navbar-nav>.active>a:hover { - color: #555; - background-color: #e7e7e7 -} - -.navbar-default .navbar-nav>.disabled>a, .navbar-default .navbar-nav>.disabled>a:focus, - .navbar-default .navbar-nav>.disabled>a:hover { - color: #ccc; - background-color: transparent -} - -.navbar-default .navbar-toggle { - border-color: #ddd -} - -.navbar-default .navbar-toggle:focus, .navbar-default .navbar-toggle:hover - { - background-color: #ddd -} - -.navbar-default .navbar-toggle .icon-bar { - background-color: #888 -} - -.navbar-default .navbar-collapse, .navbar-default .navbar-form { - border-color: #e7e7e7 -} - -.navbar-default .navbar-nav>.open>a, .navbar-default .navbar-nav>.open>a:focus, - .navbar-default .navbar-nav>.open>a:hover { - color: #555; - background-color: #e7e7e7 -} - -@media ( max-width :767px) { - .navbar-default .navbar-nav .open .dropdown-menu>li>a { - color: #777 - } - .navbar-default .navbar-nav .open .dropdown-menu>li>a:focus, - .navbar-default .navbar-nav .open .dropdown-menu>li>a:hover { - color: #333; - background-color: transparent - } - .navbar-default .navbar-nav .open .dropdown-menu>.active>a, - .navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus, - .navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover { - color: #555; - background-color: #e7e7e7 - } - .navbar-default .navbar-nav .open .dropdown-menu>.disabled>a, - .navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus, - .navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover { - color: #ccc; - background-color: transparent - } -} - -.navbar-default .navbar-link { - color: #777 -} - -.navbar-default .navbar-link:hover { - color: #333 -} - -.navbar-default .btn-link { - color: #777 -} - -.navbar-default .btn-link:focus, .navbar-default .btn-link:hover { - color: #333 -} - -.navbar-default .btn-link[disabled]:focus, .navbar-default .btn-link[disabled]:hover, - fieldset[disabled] .navbar-default .btn-link:focus, fieldset[disabled] .navbar-default .btn-link:hover - { - color: #ccc -} - -.navbar-inverse { - background-color: #222; - border-color: #080808 -} - -.navbar-inverse .navbar-brand { - color: #9d9d9d -} - -.navbar-inverse .navbar-brand:focus, .navbar-inverse .navbar-brand:hover - { - color: #fff; - background-color: transparent -} - -.navbar-inverse .navbar-text { - color: #9d9d9d -} - -.navbar-inverse .navbar-nav>li>a { - color: #9d9d9d -} - -.navbar-inverse .navbar-nav>li>a:focus, .navbar-inverse .navbar-nav>li>a:hover - { - color: #fff; - background-color: transparent -} - -.navbar-inverse .navbar-nav>.active>a, .navbar-inverse .navbar-nav>.active>a:focus, - .navbar-inverse .navbar-nav>.active>a:hover { - color: #fff; - background-color: #080808 -} - -.navbar-inverse .navbar-nav>.disabled>a, .navbar-inverse .navbar-nav>.disabled>a:focus, - .navbar-inverse .navbar-nav>.disabled>a:hover { - color: #444; - background-color: transparent -} - -.navbar-inverse .navbar-toggle { - border-color: #333 -} - -.navbar-inverse .navbar-toggle:focus, .navbar-inverse .navbar-toggle:hover - { - background-color: #333 -} - -.navbar-inverse .navbar-toggle .icon-bar { - background-color: #fff -} - -.navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form { - border-color: #101010 -} - -.navbar-inverse .navbar-nav>.open>a, .navbar-inverse .navbar-nav>.open>a:focus, - .navbar-inverse .navbar-nav>.open>a:hover { - color: #fff; - background-color: #080808 -} - -@media ( max-width :767px) { - .navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header { - border-color: #080808 - } - .navbar-inverse .navbar-nav .open .dropdown-menu .divider { - background-color: #080808 - } - .navbar-inverse .navbar-nav .open .dropdown-menu>li>a { - color: #9d9d9d - } - .navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus, - .navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover { - color: #fff; - background-color: transparent - } - .navbar-inverse .navbar-nav .open .dropdown-menu>.active>a, - .navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus, - .navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover { - color: #fff; - background-color: #080808 - } - .navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a, - .navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus, - .navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover { - color: #444; - background-color: transparent - } -} - -.navbar-inverse .navbar-link { - color: #9d9d9d -} - -.navbar-inverse .navbar-link:hover { - color: #fff -} - -.navbar-inverse .btn-link { - color: #9d9d9d -} - -.navbar-inverse .btn-link:focus, .navbar-inverse .btn-link:hover { - color: #fff -} - -.navbar-inverse .btn-link[disabled]:focus, .navbar-inverse .btn-link[disabled]:hover, - fieldset[disabled] .navbar-inverse .btn-link:focus, fieldset[disabled] .navbar-inverse .btn-link:hover - { - color: #444 -} - -.breadcrumb { - padding: 8px 15px; - margin-bottom: 20px; - list-style: none; - background-color: #f5f5f5; - border-radius: 4px -} - -.breadcrumb>li { - display: inline-block -} - -.breadcrumb>li+li:before { - padding: 0 5px; - color: #ccc; - content: "/\00a0" -} - -.breadcrumb>.active { - color: #777 -} - -.pagination { - display: inline-block; - padding-left: 0; - margin: 20px 0; - border-radius: 4px -} - -.pagination>li { - display: inline -} - -.pagination>li>a, .pagination>li>span { - position: relative; - float: left; - padding: 6px 12px; - margin-left: -1px; - line-height: 1.42857143; - color: #337ab7; - text-decoration: none; - background-color: #fff; - border: 1px solid #ddd -} - -.pagination>li:first-child>a, .pagination>li:first-child>span { - margin-left: 0; - border-top-left-radius: 4px; - border-bottom-left-radius: 4px -} - -.pagination>li:last-child>a, .pagination>li:last-child>span { - border-top-right-radius: 4px; - border-bottom-right-radius: 4px -} - -.pagination>li>a:focus, .pagination>li>a:hover, .pagination>li>span:focus, - .pagination>li>span:hover { - color: #23527c; - background-color: #eee; - border-color: #ddd -} - -.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover, - .pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover - { - z-index: 2; - color: #fff; - cursor: default; - background-color: #337ab7; - border-color: #337ab7 -} - -.pagination>.disabled>a, .pagination>.disabled>a:focus, .pagination>.disabled>a:hover, - .pagination>.disabled>span, .pagination>.disabled>span:focus, - .pagination>.disabled>span:hover { - color: #777; - cursor: not-allowed; - background-color: #fff; - border-color: #ddd -} - -.pagination-lg>li>a, .pagination-lg>li>span { - padding: 10px 16px; - font-size: 18px -} - -.pagination-lg>li:first-child>a, .pagination-lg>li:first-child>span { - border-top-left-radius: 6px; - border-bottom-left-radius: 6px -} - -.pagination-lg>li:last-child>a, .pagination-lg>li:last-child>span { - border-top-right-radius: 6px; - border-bottom-right-radius: 6px -} - -.pagination-sm>li>a, .pagination-sm>li>span { - padding: 5px 10px; - font-size: 12px -} - -.pagination-sm>li:first-child>a, .pagination-sm>li:first-child>span { - border-top-left-radius: 3px; - border-bottom-left-radius: 3px -} - -.pagination-sm>li:last-child>a, .pagination-sm>li:last-child>span { - border-top-right-radius: 3px; - border-bottom-right-radius: 3px -} - -.pager { - padding-left: 0; - margin: 20px 0; - text-align: center; - list-style: none -} - -.pager li { - display: inline -} - -.pager li>a, .pager li>span { - display: inline-block; - padding: 5px 14px; - background-color: #fff; - border: 1px solid #ddd; - border-radius: 15px -} - -.pager li>a:focus, .pager li>a:hover { - text-decoration: none; - background-color: #eee -} - -.pager .next>a, .pager .next>span { - float: right -} - -.pager .previous>a, .pager .previous>span { - float: left -} - -.pager .disabled>a, .pager .disabled>a:focus, .pager .disabled>a:hover, - .pager .disabled>span { - color: #777; - cursor: not-allowed; - background-color: #fff -} - -.label { - display: inline; - padding: .2em .6em .3em; - font-size: 75%; - font-weight: 700; - line-height: 1; - color: #fff; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - border-radius: .25em -} - -a.label:focus, a.label:hover { - color: #fff; - text-decoration: none; - cursor: pointer -} - -.label:empty { - display: none -} - -.btn .label { - position: relative; - top: -1px -} - -.label-default { - background-color: #777 -} - -.label-default[href]:focus, .label-default[href]:hover { - background-color: #5e5e5e -} - -.label-primary { - background-color: #337ab7 -} - -.label-primary[href]:focus, .label-primary[href]:hover { - background-color: #286090 -} - -.label-success { - background-color: #5cb85c -} - -.label-success[href]:focus, .label-success[href]:hover { - background-color: #449d44 -} - -.label-info { - background-color: #5bc0de -} - -.label-info[href]:focus, .label-info[href]:hover { - background-color: #31b0d5 -} - -.label-warning { - background-color: #f0ad4e -} - -.label-warning[href]:focus, .label-warning[href]:hover { - background-color: #ec971f -} - -.label-danger { - background-color: #d9534f -} - -.label-danger[href]:focus, .label-danger[href]:hover { - background-color: #c9302c -} - -.badge { - display: inline-block; - min-width: 10px; - padding: 3px 7px; - font-size: 12px; - font-weight: 700; - line-height: 1; - color: #fff; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - background-color: #777; - border-radius: 10px -} - -.badge:empty { - display: none -} - -.btn .badge { - position: relative; - top: -1px -} - -.btn-group-xs>.btn .badge, .btn-xs .badge { - top: 0; - padding: 1px 5px -} - -a.badge:focus, a.badge:hover { - color: #fff; - text-decoration: none; - cursor: pointer -} - -.list-group-item.active>.badge, .nav-pills>.active>a>.badge { - color: #337ab7; - background-color: #fff -} - -.list-group-item>.badge { - float: right -} - -.list-group-item>.badge+.badge { - margin-right: 5px -} - -.nav-pills>li>a>.badge { - margin-left: 3px -} - -.jumbotron { - padding: 30px 15px; - margin-bottom: 30px; - color: inherit; - background-color: #eee -} - -.jumbotron .h1, .jumbotron h1 { - color: inherit -} - -.jumbotron p { - margin-bottom: 15px; - font-size: 21px; - font-weight: 200 -} - -.jumbotron>hr { - border-top-color: #d5d5d5 -} - -.container .jumbotron, .container-fluid .jumbotron { - border-radius: 6px -} - -.jumbotron .container { - max-width: 100% -} - -@media screen and (min-width:768px) { - .jumbotron { - padding: 48px 0 - } - .container .jumbotron, .container-fluid .jumbotron { - padding-right: 60px; - padding-left: 60px - } - .jumbotron .h1, .jumbotron h1 { - font-size: 63px - } -} - -.thumbnail { - display: block; - padding: 4px; - margin-bottom: 20px; - line-height: 1.42857143; - background-color: #fff; - border: 1px solid #ddd; - border-radius: 4px; - -webkit-transition: border .2s ease-in-out; - -o-transition: border .2s ease-in-out; - transition: border .2s ease-in-out -} - -.thumbnail a>img, .thumbnail>img { - margin-right: auto; - margin-left: auto -} - -a.thumbnail.active, a.thumbnail:focus, a.thumbnail:hover { - border-color: #337ab7 -} - -.thumbnail .caption { - padding: 9px; - color: #333 -} - -.alert { - padding: 15px; - margin-bottom: 20px; - border: 1px solid transparent; - border-radius: 4px -} - -.alert h4 { - margin-top: 0; - color: inherit -} - -.alert .alert-link { - font-weight: 700 -} - -.alert>p, .alert>ul { - margin-bottom: 0 -} - -.alert>p+p { - margin-top: 5px -} - -.alert-dismissable, .alert-dismissible { - padding-right: 35px -} - -.alert-dismissable .close, .alert-dismissible .close { - position: relative; - top: -2px; - right: -21px; - color: inherit -} - -.alert-success { - color: #3c763d; - background-color: #dff0d8; - border-color: #d6e9c6 -} - -.alert-success hr { - border-top-color: #c9e2b3 -} - -.alert-success .alert-link { - color: #2b542c -} - -.alert-info { - color: #31708f; - background-color: #d9edf7; - border-color: #bce8f1 -} - -.alert-info hr { - border-top-color: #a6e1ec -} - -.alert-info .alert-link { - color: #245269 -} - -.alert-warning { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #faebcc -} - -.alert-warning hr { - border-top-color: #f7e1b5 -} - -.alert-warning .alert-link { - color: #66512c -} - -.alert-danger { - color: #a94442; - background-color: #f2dede; - border-color: #ebccd1 -} - -.alert-danger hr { - border-top-color: #e4b9c0 -} - -.alert-danger .alert-link { - color: #843534 -} - -@ --webkit-keyframes progress-bar-stripes { - from {background-position: 40px 0 -} - -to { - background-position: 0 0 -} - -} -@ --o-keyframes progress-bar-stripes { - from {background-position: 40px 0 -} - -to { - background-position: 0 0 -} - -} -@ -keyframes progress-bar-stripes { - from {background-position: 40px 0 -} - -to { - background-position: 0 0 -} - -} -.progress { - height: 20px; - margin-bottom: 20px; - overflow: hidden; - background-color: #f5f5f5; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); - box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1) -} - -.progress-bar { - float: left; - width: 0; - height: 100%; - font-size: 12px; - line-height: 20px; - color: #fff; - text-align: center; - background-color: #337ab7; - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); - -webkit-transition: width .6s ease; - -o-transition: width .6s ease; - transition: width .6s ease -} - -.progress-bar-striped, .progress-striped .progress-bar { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) - 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, - transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, - transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - -webkit-background-size: 40px 40px; - background-size: 40px 40px -} - -.progress-bar.active, .progress.active .progress-bar { - -webkit-animation: progress-bar-stripes 2s linear infinite; - -o-animation: progress-bar-stripes 2s linear infinite; - animation: progress-bar-stripes 2s linear infinite -} - -.progress-bar-success { - background-color: #5cb85c -} - -.progress-striped .progress-bar-success { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) - 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, - transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, - transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent) -} - -.progress-bar-info { - background-color: #5bc0de -} - -.progress-striped .progress-bar-info { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) - 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, - transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, - transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent) -} - -.progress-bar-warning { - background-color: #f0ad4e -} - -.progress-striped .progress-bar-warning { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) - 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, - transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, - transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent) -} - -.progress-bar-danger { - background-color: #d9534f -} - -.progress-striped .progress-bar-danger { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) - 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, - transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, - transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, - rgba(255, 255, 255, .15) 75%, transparent 75%, transparent) -} - -.media { - margin-top: 15px -} - -.media:first-child { - margin-top: 0 -} - -.media, .media-body { - overflow: hidden; - zoom: 1 -} - -.media-body { - width: 10000px -} - -.media-object { - display: block -} - -.media-right, .media>.pull-right { - padding-left: 10px -} - -.media-left, .media>.pull-left { - padding-right: 10px -} - -.media-body, .media-left, .media-right { - display: table-cell; - vertical-align: top -} - -.media-middle { - vertical-align: middle -} - -.media-bottom { - vertical-align: bottom -} - -.media-heading { - margin-top: 0; - margin-bottom: 5px -} - -.media-list { - padding-left: 0; - list-style: none -} - -.list-group { - padding-left: 0; - margin-bottom: 20px -} - -.list-group-item { - position: relative; - display: block; - padding: 10px 15px; - margin-bottom: -1px; - background-color: #fff; - border: 1px solid #ddd -} - -.list-group-item:first-child { - border-top-left-radius: 4px; - border-top-right-radius: 4px -} - -.list-group-item:last-child { - margin-bottom: 0; - border-bottom-right-radius: 4px; - border-bottom-left-radius: 4px -} - -a.list-group-item { - color: #555 -} - -a.list-group-item .list-group-item-heading { - color: #333 -} - -a.list-group-item:focus, a.list-group-item:hover { - color: #555; - text-decoration: none; - background-color: #f5f5f5 -} - -.list-group-item.disabled, .list-group-item.disabled:focus, - .list-group-item.disabled:hover { - color: #777; - cursor: not-allowed; - background-color: #eee -} - -.list-group-item.disabled .list-group-item-heading, .list-group-item.disabled:focus .list-group-item-heading, - .list-group-item.disabled:hover .list-group-item-heading { - color: inherit -} - -.list-group-item.disabled .list-group-item-text, .list-group-item.disabled:focus .list-group-item-text, - .list-group-item.disabled:hover .list-group-item-text { - color: #777 -} - -.list-group-item.active, .list-group-item.active:focus, .list-group-item.active:hover - { - z-index: 2; - color: #fff; - background-color: #337ab7; - border-color: #337ab7 -} - -.list-group-item.active .list-group-item-heading, .list-group-item.active .list-group-item-heading>.small, - .list-group-item.active .list-group-item-heading>small, - .list-group-item.active:focus .list-group-item-heading, - .list-group-item.active:focus .list-group-item-heading>.small, - .list-group-item.active:focus .list-group-item-heading>small, - .list-group-item.active:hover .list-group-item-heading, - .list-group-item.active:hover .list-group-item-heading>.small, - .list-group-item.active:hover .list-group-item-heading>small { - color: inherit -} - -.list-group-item.active .list-group-item-text, .list-group-item.active:focus .list-group-item-text, - .list-group-item.active:hover .list-group-item-text { - color: #c7ddef -} - -.list-group-item-success { - color: #3c763d; - background-color: #dff0d8 -} - -a.list-group-item-success { - color: #3c763d -} - -a.list-group-item-success .list-group-item-heading { - color: inherit -} - -a.list-group-item-success:focus, a.list-group-item-success:hover { - color: #3c763d; - background-color: #d0e9c6 -} - -a.list-group-item-success.active, a.list-group-item-success.active:focus, - a.list-group-item-success.active:hover { - color: #fff; - background-color: #3c763d; - border-color: #3c763d -} - -.list-group-item-info { - color: #31708f; - background-color: #d9edf7 -} - -a.list-group-item-info { - color: #31708f -} - -a.list-group-item-info .list-group-item-heading { - color: inherit -} - -a.list-group-item-info:focus, a.list-group-item-info:hover { - color: #31708f; - background-color: #c4e3f3 -} - -a.list-group-item-info.active, a.list-group-item-info.active:focus, a.list-group-item-info.active:hover - { - color: #fff; - background-color: #31708f; - border-color: #31708f -} - -.list-group-item-warning { - color: #8a6d3b; - background-color: #fcf8e3 -} - -a.list-group-item-warning { - color: #8a6d3b -} - -a.list-group-item-warning .list-group-item-heading { - color: inherit -} - -a.list-group-item-warning:focus, a.list-group-item-warning:hover { - color: #8a6d3b; - background-color: #faf2cc -} - -a.list-group-item-warning.active, a.list-group-item-warning.active:focus, - a.list-group-item-warning.active:hover { - color: #fff; - background-color: #8a6d3b; - border-color: #8a6d3b -} - -.list-group-item-danger { - color: #a94442; - background-color: #f2dede -} - -a.list-group-item-danger { - color: #a94442 -} - -a.list-group-item-danger .list-group-item-heading { - color: inherit -} - -a.list-group-item-danger:focus, a.list-group-item-danger:hover { - color: #a94442; - background-color: #ebcccc -} - -a.list-group-item-danger.active, a.list-group-item-danger.active:focus, - a.list-group-item-danger.active:hover { - color: #fff; - background-color: #a94442; - border-color: #a94442 -} - -.list-group-item-heading { - margin-top: 0; - margin-bottom: 5px -} - -.list-group-item-text { - margin-bottom: 0; - line-height: 1.3 -} - -.panel { - margin-bottom: 20px; - background-color: #fff; - border: 1px solid transparent; - border-radius: 4px; - -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05); - box-shadow: 0 1px 1px rgba(0, 0, 0, .05) -} - -.panel-body { - padding: 15px -} - -.panel-heading { - padding: 10px 15px; - border-bottom: 1px solid transparent; - border-top-left-radius: 3px; - border-top-right-radius: 3px -} - -.panel-heading>.dropdown .dropdown-toggle { - color: inherit -} - -.panel-title { - margin-top: 0; - margin-bottom: 0; - font-size: 16px; - color: inherit -} - -.panel-title>.small, .panel-title>.small>a, .panel-title>a, .panel-title>small, - .panel-title>small>a { - color: inherit -} - -.panel-footer { - padding: 10px 15px; - background-color: #f5f5f5; - border-top: 1px solid #ddd; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px -} - -.panel>.list-group, .panel>.panel-collapse>.list-group { - margin-bottom: 0 -} - -.panel>.list-group .list-group-item, .panel>.panel-collapse>.list-group .list-group-item - { - border-width: 1px 0; - border-radius: 0 -} - -.panel>.list-group:first-child .list-group-item:first-child, .panel>.panel-collapse>.list-group:first-child .list-group-item:first-child - { - border-top: 0; - border-top-left-radius: 3px; - border-top-right-radius: 3px -} - -.panel>.list-group:last-child .list-group-item:last-child, .panel>.panel-collapse>.list-group:last-child .list-group-item:last-child - { - border-bottom: 0; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px -} - -.panel-heading+.list-group .list-group-item:first-child { - border-top-width: 0 -} - -.list-group+.panel-footer { - border-top-width: 0 -} - -.panel>.panel-collapse>.table, .panel>.table, .panel>.table-responsive>.table - { - margin-bottom: 0 -} - -.panel>.panel-collapse>.table caption, .panel>.table caption, .panel>.table-responsive>.table caption - { - padding-right: 15px; - padding-left: 15px -} - -.panel>.table-responsive:first-child>.table:first-child, .panel>.table:first-child - { - border-top-left-radius: 3px; - border-top-right-radius: 3px -} - -.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child, - .panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child, - .panel>.table:first-child>tbody:first-child>tr:first-child, .panel>.table:first-child>thead:first-child>tr:first-child - { - border-top-left-radius: 3px; - border-top-right-radius: 3px -} - -.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child, - .panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child, - .panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child, - .panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child, - .panel>.table:first-child>tbody:first-child>tr:first-child td:first-child, - .panel>.table:first-child>tbody:first-child>tr:first-child th:first-child, - .panel>.table:first-child>thead:first-child>tr:first-child td:first-child, - .panel>.table:first-child>thead:first-child>tr:first-child th:first-child - { - border-top-left-radius: 3px -} - -.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child, - .panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child, - .panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child, - .panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child, - .panel>.table:first-child>tbody:first-child>tr:first-child td:last-child, - .panel>.table:first-child>tbody:first-child>tr:first-child th:last-child, - .panel>.table:first-child>thead:first-child>tr:first-child td:last-child, - .panel>.table:first-child>thead:first-child>tr:first-child th:last-child - { - border-top-right-radius: 3px -} - -.panel>.table-responsive:last-child>.table:last-child, .panel>.table:last-child - { - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px -} - -.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child, - .panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child, - .panel>.table:last-child>tbody:last-child>tr:last-child, .panel>.table:last-child>tfoot:last-child>tr:last-child - { - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px -} - -.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child, - .panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child, - .panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child, - .panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child, - .panel>.table:last-child>tbody:last-child>tr:last-child td:first-child, - .panel>.table:last-child>tbody:last-child>tr:last-child th:first-child, - .panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child, - .panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child - { - border-bottom-left-radius: 3px -} - -.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child, - .panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child, - .panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child, - .panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child, - .panel>.table:last-child>tbody:last-child>tr:last-child td:last-child, - .panel>.table:last-child>tbody:last-child>tr:last-child th:last-child, - .panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child, - .panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child { - border-bottom-right-radius: 3px -} - -.panel>.panel-body+.table, .panel>.panel-body+.table-responsive, .panel>.table+.panel-body, - .panel>.table-responsive+.panel-body { - border-top: 1px solid #ddd -} - -.panel>.table>tbody:first-child>tr:first-child td, .panel>.table>tbody:first-child>tr:first-child th - { - border-top: 0 -} - -.panel>.table-bordered, .panel>.table-responsive>.table-bordered { - border: 0 -} - -.panel>.table-bordered>tbody>tr>td:first-child, .panel>.table-bordered>tbody>tr>th:first-child, - .panel>.table-bordered>tfoot>tr>td:first-child, .panel>.table-bordered>tfoot>tr>th:first-child, - .panel>.table-bordered>thead>tr>td:first-child, .panel>.table-bordered>thead>tr>th:first-child, - .panel>.table-responsive>.table-bordered>tbody>tr>td:first-child, - .panel>.table-responsive>.table-bordered>tbody>tr>th:first-child, - .panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child, - .panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child, - .panel>.table-responsive>.table-bordered>thead>tr>td:first-child, - .panel>.table-responsive>.table-bordered>thead>tr>th:first-child { - border-left: 0 -} - -.panel>.table-bordered>tbody>tr>td:last-child, .panel>.table-bordered>tbody>tr>th:last-child, - .panel>.table-bordered>tfoot>tr>td:last-child, .panel>.table-bordered>tfoot>tr>th:last-child, - .panel>.table-bordered>thead>tr>td:last-child, .panel>.table-bordered>thead>tr>th:last-child, - .panel>.table-responsive>.table-bordered>tbody>tr>td:last-child, .panel>.table-responsive>.table-bordered>tbody>tr>th:last-child, - .panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child, .panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child, - .panel>.table-responsive>.table-bordered>thead>tr>td:last-child, .panel>.table-responsive>.table-bordered>thead>tr>th:last-child - { - border-right: 0 -} - -.panel>.table-bordered>tbody>tr:first-child>td, .panel>.table-bordered>tbody>tr:first-child>th, - .panel>.table-bordered>thead>tr:first-child>td, .panel>.table-bordered>thead>tr:first-child>th, - .panel>.table-responsive>.table-bordered>tbody>tr:first-child>td, - .panel>.table-responsive>.table-bordered>tbody>tr:first-child>th, - .panel>.table-responsive>.table-bordered>thead>tr:first-child>td, - .panel>.table-responsive>.table-bordered>thead>tr:first-child>th { - border-bottom: 0 -} - -.panel>.table-bordered>tbody>tr:last-child>td, .panel>.table-bordered>tbody>tr:last-child>th, - .panel>.table-bordered>tfoot>tr:last-child>td, .panel>.table-bordered>tfoot>tr:last-child>th, - .panel>.table-responsive>.table-bordered>tbody>tr:last-child>td, .panel>.table-responsive>.table-bordered>tbody>tr:last-child>th, - .panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td, .panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th - { - border-bottom: 0 -} - -.panel>.table-responsive { - margin-bottom: 0; - border: 0 -} - -.panel-group { - margin-bottom: 20px -} - -.panel-group .panel { - margin-bottom: 0; - border-radius: 4px -} - -.panel-group .panel+.panel { - margin-top: 5px -} - -.panel-group .panel-heading { - border-bottom: 0 -} - -.panel-group .panel-heading+.panel-collapse>.list-group, .panel-group .panel-heading+.panel-collapse>.panel-body - { - border-top: 1px solid #ddd -} - -.panel-group .panel-footer { - border-top: 0 -} - -.panel-group .panel-footer+.panel-collapse .panel-body { - border-bottom: 1px solid #ddd -} - -.panel-default { - border-color: #ddd -} - -.panel-default>.panel-heading { - color: #333; - background-color: #f5f5f5; - border-color: #ddd -} - -.panel-default>.panel-heading+.panel-collapse>.panel-body { - border-top-color: #ddd -} - -.panel-default>.panel-heading .badge { - color: #f5f5f5; - background-color: #333 -} - -.panel-default>.panel-footer+.panel-collapse>.panel-body { - border-bottom-color: #ddd -} - -.panel-primary { - border-color: #337ab7 -} - -.panel-primary>.panel-heading { - color: #fff; - background-color: #337ab7; - border-color: #337ab7 -} - -.panel-primary>.panel-heading+.panel-collapse>.panel-body { - border-top-color: #337ab7 -} - -.panel-primary>.panel-heading .badge { - color: #337ab7; - background-color: #fff -} - -.panel-primary>.panel-footer+.panel-collapse>.panel-body { - border-bottom-color: #337ab7 -} - -.panel-success { - border-color: #d6e9c6 -} - -.panel-success>.panel-heading { - color: #3c763d; - background-color: #dff0d8; - border-color: #d6e9c6 -} - -.panel-success>.panel-heading+.panel-collapse>.panel-body { - border-top-color: #d6e9c6 -} - -.panel-success>.panel-heading .badge { - color: #dff0d8; - background-color: #3c763d -} - -.panel-success>.panel-footer+.panel-collapse>.panel-body { - border-bottom-color: #d6e9c6 -} - -.panel-info { - border-color: #bce8f1 -} - -.panel-info>.panel-heading { - color: #31708f; - background-color: #d9edf7; - border-color: #bce8f1 -} - -.panel-info>.panel-heading+.panel-collapse>.panel-body { - border-top-color: #bce8f1 -} - -.panel-info>.panel-heading .badge { - color: #d9edf7; - background-color: #31708f -} - -.panel-info>.panel-footer+.panel-collapse>.panel-body { - border-bottom-color: #bce8f1 -} - -.panel-warning { - border-color: #faebcc -} - -.panel-warning>.panel-heading { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #faebcc -} - -.panel-warning>.panel-heading+.panel-collapse>.panel-body { - border-top-color: #faebcc -} - -.panel-warning>.panel-heading .badge { - color: #fcf8e3; - background-color: #8a6d3b -} - -.panel-warning>.panel-footer+.panel-collapse>.panel-body { - border-bottom-color: #faebcc -} - -.panel-danger { - border-color: #ebccd1 -} - -.panel-danger>.panel-heading { - color: #a94442; - background-color: #f2dede; - border-color: #ebccd1 -} - -.panel-danger>.panel-heading+.panel-collapse>.panel-body { - border-top-color: #ebccd1 -} - -.panel-danger>.panel-heading .badge { - color: #f2dede; - background-color: #a94442 -} - -.panel-danger>.panel-footer+.panel-collapse>.panel-body { - border-bottom-color: #ebccd1 -} - -.embed-responsive { - position: relative; - display: block; - height: 0; - padding: 0; - overflow: hidden -} - -.embed-responsive .embed-responsive-item, .embed-responsive embed, - .embed-responsive iframe, .embed-responsive object, .embed-responsive video - { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 100%; - height: 100%; - border: 0 -} - -.embed-responsive-16by9 { - padding-bottom: 56.25% -} - -.embed-responsive-4by3 { - padding-bottom: 75% -} - -.well { - min-height: 20px; - padding: 19px; - margin-bottom: 20px; - background-color: #f5f5f5; - border: 1px solid #e3e3e3; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05) -} - -.well blockquote { - border-color: #ddd; - border-color: rgba(0, 0, 0, .15) -} - -.well-lg { - padding: 24px; - border-radius: 6px -} - -.well-sm { - padding: 9px; - border-radius: 3px -} - -.close { - float: right; - font-size: 21px; - font-weight: 700; - line-height: 1; - color: #000; - text-shadow: 0 1px 0 #fff; - filter: alpha(opacity = 20); - opacity: .2 -} - -.close:focus, .close:hover { - color: #000; - text-decoration: none; - cursor: pointer; - filter: alpha(opacity = 50); - opacity: .5 -} - -button.close { - -webkit-appearance: none; - padding: 0; - cursor: pointer; - background: 0 0; - border: 0 -} - -.modal-open { - overflow: hidden -} - -.modal { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1050; - display: none; - overflow: hidden; - -webkit-overflow-scrolling: touch; - outline: 0 -} - -.modal.fade .modal-dialog { - -webkit-transition: -webkit-transform .3s ease-out; - -o-transition: -o-transform .3s ease-out; - transition: transform .3s ease-out; - -webkit-transform: translate(0, -25%); - -ms-transform: translate(0, -25%); - -o-transform: translate(0, -25%); - transform: translate(0, -25%) -} - -.modal.in .modal-dialog { - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - -o-transform: translate(0, 0); - transform: translate(0, 0) -} - -.modal-open .modal { - overflow-x: hidden; - overflow-y: auto -} - -.modal-dialog { - position: relative; - width: auto; - margin: 10px -} - -.modal-content { - position: relative; - background-color: #fff; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #999; - border: 1px solid rgba(0, 0, 0, .2); - border-radius: 6px; - outline: 0; - -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5); - box-shadow: 0 3px 9px rgba(0, 0, 0, .5) -} - -.modal-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1040; - background-color: #000 -} - -.modal-backdrop.fade { - filter: alpha(opacity = 0); - opacity: 0 -} - -.modal-backdrop.in { - filter: alpha(opacity = 50); - opacity: .5 -} - -.modal-header { - min-height: 16.43px; - padding: 15px; - border-bottom: 1px solid #e5e5e5 -} - -.modal-header .close { - margin-top: -2px -} - -.modal-title { - margin: 0; - line-height: 1.42857143 -} - -.modal-body { - position: relative; - padding: 15px -} - -.modal-footer { - padding: 15px; - text-align: right; - border-top: 1px solid #e5e5e5 -} - -.modal-footer .btn+.btn { - margin-bottom: 0; - margin-left: 5px -} - -.modal-footer .btn-group .btn+.btn { - margin-left: -1px -} - -.modal-footer .btn-block+.btn-block { - margin-left: 0 -} - -.modal-scrollbar-measure { - position: absolute; - top: -9999px; - width: 50px; - height: 50px; - overflow: scroll -} - -@media ( min-width :768px) { - .modal-dialog { - width: 600px; - margin: 30px auto - } - .modal-content { - -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5); - box-shadow: 0 5px 15px rgba(0, 0, 0, .5) - } - .modal-sm { - width: 300px - } -} - -@media ( min-width :992px) { - .modal-lg { - width: 900px - } -} - -.tooltip { - position: absolute; - z-index: 1070; - display: block; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 12px; - font-weight: 400; - line-height: 1.4; - filter: alpha(opacity = 0); - opacity: 0 -} - -.tooltip.in { - filter: alpha(opacity = 90); - opacity: .9 -} - -.tooltip.top { - padding: 5px 0; - margin-top: -3px -} - -.tooltip.right { - padding: 0 5px; - margin-left: 3px -} - -.tooltip.bottom { - padding: 5px 0; - margin-top: 3px -} - -.tooltip.left { - padding: 0 5px; - margin-left: -3px -} - -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #fff; - text-align: center; - text-decoration: none; - background-color: #000; - border-radius: 4px -} - -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid -} - -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0; - border-top-color: #000 -} - -.tooltip.top-left .tooltip-arrow { - right: 5px; - bottom: 0; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #000 -} - -.tooltip.top-right .tooltip-arrow { - bottom: 0; - left: 5px; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #000 -} - -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: #000 -} - -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: #000 -} - -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000 -} - -.tooltip.bottom-left .tooltip-arrow { - top: 0; - right: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000 -} - -.tooltip.bottom-right .tooltip-arrow { - top: 0; - left: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000 -} - -.popover { - position: absolute; - top: 0; - left: 0; - z-index: 1060; - display: none; - max-width: 276px; - padding: 1px; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - text-align: left; - white-space: normal; - background-color: #fff; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, .2); - border-radius: 6px; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2); - box-shadow: 0 5px 10px rgba(0, 0, 0, .2) -} - -.popover.top { - margin-top: -10px -} - -.popover.right { - margin-left: 10px -} - -.popover.bottom { - margin-top: 10px -} - -.popover.left { - margin-left: -10px -} - -.popover-title { - padding: 8px 14px; - margin: 0; - font-size: 14px; - background-color: #f7f7f7; - border-bottom: 1px solid #ebebeb; - border-radius: 5px 5px 0 0 -} - -.popover-content { - padding: 9px 14px -} - -.popover>.arrow, .popover>.arrow:after { - position: absolute; - display: block; - width: 0; - height: 0; - border-color: transparent; - border-style: solid -} - -.popover>.arrow { - border-width: 11px -} - -.popover>.arrow:after { - content: ""; - border-width: 10px -} - -.popover.top>.arrow { - bottom: -11px; - left: 50%; - margin-left: -11px; - border-top-color: #999; - border-top-color: rgba(0, 0, 0, .25); - border-bottom-width: 0 -} - -.popover.top>.arrow:after { - bottom: 1px; - margin-left: -10px; - content: " "; - border-top-color: #fff; - border-bottom-width: 0 -} - -.popover.right>.arrow { - top: 50%; - left: -11px; - margin-top: -11px; - border-right-color: #999; - border-right-color: rgba(0, 0, 0, .25); - border-left-width: 0 -} - -.popover.right>.arrow:after { - bottom: -10px; - left: 1px; - content: " "; - border-right-color: #fff; - border-left-width: 0 -} - -.popover.bottom>.arrow { - top: -11px; - left: 50%; - margin-left: -11px; - border-top-width: 0; - border-bottom-color: #999; - border-bottom-color: rgba(0, 0, 0, .25) -} - -.popover.bottom>.arrow:after { - top: 1px; - margin-left: -10px; - content: " "; - border-top-width: 0; - border-bottom-color: #fff -} - -.popover.left>.arrow { - top: 50%; - right: -11px; - margin-top: -11px; - border-right-width: 0; - border-left-color: #999; - border-left-color: rgba(0, 0, 0, .25) -} - -.popover.left>.arrow:after { - right: 1px; - bottom: -10px; - content: " "; - border-right-width: 0; - border-left-color: #fff -} - -.carousel { - position: relative -} - -.carousel-inner { - position: relative; - width: 100%; - overflow: hidden -} - -.carousel-inner>.item { - position: relative; - display: none; - -webkit-transition: .6s ease-in-out left; - -o-transition: .6s ease-in-out left; - transition: .6s ease-in-out left -} - -.carousel-inner>.item>a>img, .carousel-inner>.item>img { - line-height: 1 -} - -@media all and (transform-3d) , ( -webkit-transform-3d ) { - .carousel-inner>.item { - -webkit-transition: -webkit-transform .6s ease-in-out; - -o-transition: -o-transform .6s ease-in-out; - transition: transform .6s ease-in-out; - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - -webkit-perspective: 1000; - perspective: 1000 - } - .carousel-inner>.item.active.right, .carousel-inner>.item.next { - left: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0) - } - .carousel-inner>.item.active.left, .carousel-inner>.item.prev { - left: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0) - } - .carousel-inner>.item.active, .carousel-inner>.item.next.left, - .carousel-inner>.item.prev.right { - left: 0; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0) - } -} - -.carousel-inner>.active, .carousel-inner>.next, .carousel-inner>.prev { - display: block -} - -.carousel-inner>.active { - left: 0 -} - -.carousel-inner>.next, .carousel-inner>.prev { - position: absolute; - top: 0; - width: 100% -} - -.carousel-inner>.next { - left: 100% -} - -.carousel-inner>.prev { - left: -100% -} - -.carousel-inner>.next.left, .carousel-inner>.prev.right { - left: 0 -} - -.carousel-inner>.active.left { - left: -100% -} - -.carousel-inner>.active.right { - left: 100% -} - -.carousel-control { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 15%; - font-size: 20px; - color: #fff; - text-align: center; - text-shadow: 0 1px 2px rgba(0, 0, 0, .6); - filter: alpha(opacity = 50); - opacity: .5 -} - -.carousel-control.left { - background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0, - rgba(0, 0, 0, .0001) 100%); - background-image: -o-linear-gradient(left, rgba(0, 0, 0, .5) 0, - rgba(0, 0, 0, .0001) 100%); - background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), - to(rgba(0, 0, 0, .0001))); - background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0, - rgba(0, 0, 0, .0001) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', - endColorstr='#00000000', GradientType=1); - background-repeat: repeat-x -} - -.carousel-control.right { - right: 0; - left: auto; - background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0, - rgba(0, 0, 0, .5) 100%); - background-image: -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0, - rgba(0, 0, 0, .5) 100%); - background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), - to(rgba(0, 0, 0, .5))); - background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0, - rgba(0, 0, 0, .5) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', - endColorstr='#80000000', GradientType=1); - background-repeat: repeat-x -} - -.carousel-control:focus, .carousel-control:hover { - color: #fff; - text-decoration: none; - filter: alpha(opacity = 90); - outline: 0; - opacity: .9 -} - -.carousel-control .glyphicon-chevron-left, .carousel-control .glyphicon-chevron-right, - .carousel-control .icon-next, .carousel-control .icon-prev { - position: absolute; - top: 50%; - z-index: 5; - display: inline-block -} - -.carousel-control .glyphicon-chevron-left, .carousel-control .icon-prev - { - left: 50%; - margin-left: -10px -} - -.carousel-control .glyphicon-chevron-right, .carousel-control .icon-next - { - right: 50%; - margin-right: -10px -} - -.carousel-control .icon-next, .carousel-control .icon-prev { - width: 20px; - height: 20px; - margin-top: -10px; - font-family: serif; - line-height: 1 -} - -.carousel-control .icon-prev:before { - content: '\2039' -} - -.carousel-control .icon-next:before { - content: '\203a' -} - -.carousel-indicators { - position: absolute; - bottom: 10px; - left: 50%; - z-index: 15; - width: 60%; - padding-left: 0; - margin-left: -30%; - text-align: center; - list-style: none -} - -.carousel-indicators li { - display: inline-block; - width: 10px; - height: 10px; - margin: 1px; - text-indent: -999px; - cursor: pointer; - background-color: #000 \9; - background-color: rgba(0, 0, 0, 0); - border: 1px solid #fff; - border-radius: 10px -} - -.carousel-indicators .active { - width: 12px; - height: 12px; - margin: 0; - background-color: #fff -} - -.carousel-caption { - position: absolute; - right: 15%; - bottom: 20px; - left: 15%; - z-index: 10; - padding-top: 20px; - padding-bottom: 20px; - color: #fff; - text-align: center; - text-shadow: 0 1px 2px rgba(0, 0, 0, .6) -} - -.carousel-caption .btn { - text-shadow: none -} - -@media screen and (min-width:768px) { - .carousel-control .glyphicon-chevron-left, .carousel-control .glyphicon-chevron-right, - .carousel-control .icon-next, .carousel-control .icon-prev { - width: 30px; - height: 30px; - margin-top: -15px; - font-size: 30px - } - .carousel-control .glyphicon-chevron-left, .carousel-control .icon-prev - { - margin-left: -15px - } - .carousel-control .glyphicon-chevron-right, .carousel-control .icon-next - { - margin-right: -15px - } - .carousel-caption { - right: 20%; - left: 20%; - padding-bottom: 30px - } - .carousel-indicators { - bottom: 20px - } -} - -.btn-group-vertical>.btn-group:after, .btn-group-vertical>.btn-group:before, - .btn-toolbar:after, .btn-toolbar:before, .clearfix:after, .clearfix:before, - .container-fluid:after, .container-fluid:before, .container:after, - .container:before, .dl-horizontal dd:after, .dl-horizontal dd:before, - .form-horizontal .form-group:after, .form-horizontal .form-group:before, - .modal-footer:after, .modal-footer:before, .nav:after, .nav:before, - .navbar-collapse:after, .navbar-collapse:before, .navbar-header:after, - .navbar-header:before, .navbar:after, .navbar:before, .pager:after, - .pager:before, .panel-body:after, .panel-body:before, .row:after, .row:before - { - display: table; - content: " " -} - -.btn-group-vertical>.btn-group:after, .btn-toolbar:after, .clearfix:after, - .container-fluid:after, .container:after, .dl-horizontal dd:after, - .form-horizontal .form-group:after, .modal-footer:after, .nav:after, - .navbar-collapse:after, .navbar-header:after, .navbar:after, .pager:after, - .panel-body:after, .row:after { - clear: both -} - -.center-block { - display: block; - margin-right: auto; - margin-left: auto -} - -.pull-right { - float: right !important -} - -.pull-left { - float: left !important -} - -.hide { - display: none !important -} - -.show { - display: block !important -} - -.invisible { - visibility: hidden -} - -.text-hide { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0 -} - -.hidden { - display: none !important -} - -.affix { - position: fixed -} - -@ --ms-viewport { - width: device-width -} - -.visible-lg, .visible-md, .visible-sm, .visible-xs { - display: none !important -} - -.visible-lg-block, .visible-lg-inline, .visible-lg-inline-block, - .visible-md-block, .visible-md-inline, .visible-md-inline-block, - .visible-sm-block, .visible-sm-inline, .visible-sm-inline-block, - .visible-xs-block, .visible-xs-inline, .visible-xs-inline-block { - display: none !important -} - -@media ( max-width :767px) { - .visible-xs { - display: block !important - } - table.visible-xs { - display: table - } - tr.visible-xs { - display: table-row !important - } - td.visible-xs, th.visible-xs { - display: table-cell !important - } -} - -@media ( max-width :767px) { - .visible-xs-block { - display: block !important - } -} - -@media ( max-width :767px) { - .visible-xs-inline { - display: inline !important - } -} - -@media ( max-width :767px) { - .visible-xs-inline-block { - display: inline-block !important - } -} - -@media ( min-width :768px)and (max-width:991px) { - .visible-sm { - display: block !important - } - table.visible-sm { - display: table - } - tr.visible-sm { - display: table-row !important - } - td.visible-sm, th.visible-sm { - display: table-cell !important - } -} - -@media ( min-width :768px)and (max-width:991px) { - .visible-sm-block { - display: block !important - } -} - -@media ( min-width :768px)and (max-width:991px) { - .visible-sm-inline { - display: inline !important - } -} - -@media ( min-width :768px)and (max-width:991px) { - .visible-sm-inline-block { - display: inline-block !important - } -} - -@media ( min-width :992px)and (max-width:1199px) { - .visible-md { - display: block !important - } - table.visible-md { - display: table - } - tr.visible-md { - display: table-row !important - } - td.visible-md, th.visible-md { - display: table-cell !important - } -} - -@media ( min-width :992px)and (max-width:1199px) { - .visible-md-block { - display: block !important - } -} - -@media ( min-width :992px)and (max-width:1199px) { - .visible-md-inline { - display: inline !important - } -} - -@media ( min-width :992px)and (max-width:1199px) { - .visible-md-inline-block { - display: inline-block !important - } -} - -@media ( min-width :1200px) { - .visible-lg { - display: block !important - } - table.visible-lg { - display: table - } - tr.visible-lg { - display: table-row !important - } - td.visible-lg, th.visible-lg { - display: table-cell !important - } -} - -@media ( min-width :1200px) { - .visible-lg-block { - display: block !important - } -} - -@media ( min-width :1200px) { - .visible-lg-inline { - display: inline !important - } -} - -@media ( min-width :1200px) { - .visible-lg-inline-block { - display: inline-block !important - } -} - -@media ( max-width :767px) { - .hidden-xs { - display: none !important - } -} - -@media ( min-width :768px)and (max-width:991px) { - .hidden-sm { - display: none !important - } -} - -@media ( min-width :992px)and (max-width:1199px) { - .hidden-md { - display: none !important - } -} - -@media ( min-width :1200px) { - .hidden-lg { - display: none !important - } -} - -.visible-print { - display: none !important -} - -@media print { - .visible-print { - display: block !important - } - table.visible-print { - display: table - } - tr.visible-print { - display: table-row !important - } - td.visible-print, th.visible-print { - display: table-cell !important - } -} - -.visible-print-block { - display: none !important -} - -@media print { - .visible-print-block { - display: block !important - } -} - -.visible-print-inline { - display: none !important -} - -@media print { - .visible-print-inline { - display: inline !important - } -} - -.visible-print-inline-block { - display: none !important -} - -@media print { - .visible-print-inline-block { - display: inline-block !important - } -} - -@media print { - .hidden-print { - display: none !important - } -} \ No newline at end of file diff --git a/_examples/file-server/embedding-files-into-app/assets/favicon.ico b/_examples/file-server/embedding-files-into-app/assets/favicon.ico deleted file mode 100644 index c370da518ec542579b7cc0d5d30f4778b4a96318..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 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 0 && name[0] == '/' { - name = name[1:] - } - content, err := Asset(name) - if err == nil { - return &assetFile{name: name, Reader: bytes.NewReader(content)}, nil - } - children, err := AssetDir(name) - if err == nil { - childInfos := make([]os.FileInfo, 0, len(children)) - for _, child := range children { - childPath := filepath.Join(name, child) - info, errInfo := AssetInfo(filepath.Join(name, child)) - if errInfo == nil { - childInfos = append(childInfos, info) - } else { - childInfos = append(childInfos, newDirFileInfo(childPath)) - } - } - return &assetFile{name: name, childInfos: childInfos}, nil - } else { - // If the error is not found, return an error that will - // result in a 404 error. Otherwise the server returns - // a 500 error for files not found. - if strings.Contains(err.Error(), "not found") { - return nil, os.ErrNotExist - } - return nil, err - } -} - -// Close no need do anything -func (f *assetFile) Close() error { - return nil -} - -// Readdir read dir's children file info -func (f *assetFile) Readdir(count int) ([]os.FileInfo, error) { - if len(f.childInfos) == 0 { - return nil, os.ErrNotExist - } - if count <= 0 { - return f.childInfos, nil - } - if f.childInfoOffset+count > len(f.childInfos) { - count = len(f.childInfos) - f.childInfoOffset - } - offset := f.childInfoOffset - f.childInfoOffset += count - return f.childInfos[offset : offset+count], nil -} - -// Stat read file info from asset item -func (f *assetFile) Stat() (os.FileInfo, error) { - if len(f.childInfos) != 0 { - return newDirFileInfo(f.name), nil - } - return AssetInfo(f.name) -} - -// newDirFileInfo return default dir file info -func newDirFileInfo(name string) os.FileInfo { - return &bindataFileInfo{ - name: name, - size: 0, - mode: os.FileMode(2147484068), // equal os.FileMode(0644)|os.ModeDir - modTime: time.Time{}} -} - -// AssetFile return a http.FileSystem instance that data backend by asset -func AssetFile() http.FileSystem { - return &assetOperator{} -} - -var _cssBootstrapMinCss = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\xef\x8f\xe3\x38\x92\x20\xfa\xb9\x1a\xe8\xff\x41\x5b\x8d\x41\x57\x4d\x59\x2e\xf9\x77\xda\x89\xce\xb7\xfb\xe6\x0e\xb7\x03\xdc\xec\x97\x9b\x0f\x07\xf4\xf4\x7b\xa0\x25\xda\xd6\x94\x2c\x69\x24\x39\x2b\xb3\xfb\xf6\xfe\xf6\x83\xf8\x4b\x41\x32\x48\xd1\x4e\x77\xcf\xdc\x62\xb7\xee\x7a\x9c\x62\x44\x30\x18\x0c\x06\x83\x41\x32\xf8\xf9\xf7\xff\xf4\xed\x37\xd1\xef\xa3\xff\xb7\xaa\xba\xb6\x6b\x48\x1d\x3d\x2f\xa6\x8b\xe9\x32\xfa\x70\xea\xba\x7a\xf7\xf9\xf3\x91\x76\x7b\x59\x36\x4d\xab\xf3\x47\x06\xfe\x87\xaa\x7e\x6d\xf2\xe3\xa9\x8b\xe6\xc9\x6c\x16\xcf\x93\xd9\x2a\xfa\xf3\xd7\xbc\xeb\x68\x33\x89\xfe\x58\xa6\x53\x06\xf5\xdf\xf3\x94\x96\x2d\xcd\xa2\x4b\x99\xd1\x26\xfa\xd3\x1f\xff\xcc\xc9\xb6\x3d\xdd\xbc\x3b\x5d\xf6\x3d\xc5\xcf\xdd\xd7\x7d\xfb\x59\x55\xf2\x79\x5f\x54\xfb\xcf\x67\xd2\x76\xb4\xf9\xfc\xdf\xff\xf8\x87\xff\xfa\x6f\xff\xe3\xbf\xb2\x4a\x3f\x47\x9f\x7f\xff\x4f\x51\x59\x35\x67\x52\xe4\x3f\xd3\x69\xda\xb6\x3d\xb3\xc9\x74\x1e\xfd\x2f\x46\x5b\x54\x17\xfd\xaf\xe8\x98\x77\xd3\xbc\xfa\xac\x60\xa3\xdf\x7f\xfe\xf6\x9b\x53\x77\x2e\xa2\x5f\xbe\xfd\xe6\xdd\xa1\x2a\xbb\xf8\x40\xce\x79\xf1\xba\x8b\x5a\x52\xb6\x71\x4b\x9b\xfc\xf0\xf8\xed\x37\xef\xe2\xaf\x74\xff\x25\xef\xe2\x8e\xbe\x74\x71\x9b\xff\x4c\x63\x92\xfd\xf5\xd2\x76\xbb\x68\x96\x24\xbf\x63\x10\xe7\xd6\x51\xfa\xed\x37\xff\xfe\xed\x37\xdf\x7e\xb3\xaf\xb2\x57\x56\xcd\x99\x34\xc7\xbc\xdc\x45\x89\x28\x20\x4d\x97\xa7\x05\x9d\x44\xa4\xcd\x33\x3a\x89\x32\xda\x91\xbc\x68\x27\xd1\x21\x3f\xa6\xa4\xee\xf2\xaa\x64\xbf\x2f\x0d\x9d\x44\x87\xaa\x62\xb2\x3c\x51\x92\xb1\xff\x3d\x36\xd5\xa5\x9e\x30\xb2\x79\x39\x89\xce\xb4\xbc\x4c\xa2\x92\x3c\x4f\xa2\x96\xa6\x1c\xb7\xbd\x9c\xcf\xa4\xe1\x95\x67\x79\x5b\x17\xe4\x75\x17\xed\x8b\x2a\xfd\x22\x39\xb8\x64\x79\x35\x89\x52\x52\x3e\x93\x76\x12\xd5\x4d\x75\x6c\x68\xdb\x4e\xa2\xe7\x3c\xa3\x95\x8e\x97\x97\x45\x5e\xd2\x98\xa1\xf7\xed\x7e\xa6\x3d\xfb\xa4\x88\x49\x91\x1f\xcb\x5d\xb4\x27\x2d\xed\x21\x20\xe9\x5d\x59\x75\xd1\x87\x1f\xd3\xaa\xec\x9a\xaa\x68\x7f\x8a\x3e\x6a\x24\xcb\xaa\xa4\x3d\xa9\x13\xed\x35\x67\x10\xcc\x8f\xa7\x3c\xcb\x68\xf9\xd3\x24\xea\xe8\xb9\x2e\x48\x47\x23\x0b\x4f\x56\xc3\x4a\xf6\x24\xfd\xd2\xcb\xa3\xcc\xe2\xb4\x2a\xaa\x66\x17\x75\x0d\x29\xdb\x9a\x34\xb4\xec\x24\xe4\x8e\xa4\x5d\xfe\xdc\x8b\x7b\x77\xaa\x9e\x69\xc3\x30\xab\x4b\xd7\x33\x0d\x3a\x65\xbf\x6f\x7e\xec\xf2\xae\xa0\x3f\x71\xd2\x55\x93\xd1\x26\xde\x57\x5d\x57\x9d\x77\xd1\xac\x7e\x89\xb2\xaa\xeb\x68\x26\x7b\x77\x12\xb5\x5d\x53\x95\xc7\x41\x93\xbe\x8a\xe6\x6c\x12\x49\x34\x3b\x94\x43\x71\xdb\xbd\x16\x74\x17\xe5\x1d\x29\xf2\x54\x00\x9c\x66\x9a\x86\x4c\xd7\x1b\x7a\x8e\x92\x47\x85\x92\xff\x4c\x77\xd1\x9c\x9e\x05\xf8\x99\x34\x5f\x18\x82\x68\xed\x77\x49\xc2\x80\x07\x39\xec\xa2\xef\x0e\x07\x59\x7d\x7b\x26\x05\xd0\x74\x4e\xed\x41\x29\x68\x7b\xe9\x1b\x71\xa9\x19\x44\x5d\xb5\x79\xaf\x3d\xbb\xa8\xa1\x05\xe9\x05\x66\x70\xb1\x59\x31\xb5\x67\xca\xa0\x3a\x2e\x40\x21\x64\x05\x5d\x55\xef\xa2\x78\xba\x52\x8d\x69\x2f\x7b\x21\x69\x2e\xe2\x78\x3a\x1f\x0a\xf3\xf3\x11\x74\xc3\xd0\x4d\xed\xf3\x91\x2b\xd7\xae\xa9\xaa\x8e\xeb\x55\xdf\xa9\x87\xa2\xfa\xba\x8b\xb8\xfe\x08\x50\x3e\x82\x34\xf9\xce\xe8\x39\x5a\x26\xf5\x8b\x94\x3e\xd7\x05\xad\x35\x72\xe0\xef\xab\x97\xbe\xe1\x79\x79\xdc\x45\xbd\x1e\xd3\x92\x7d\xe3\x23\xbf\xfa\xd9\x57\xee\x28\x12\x95\xd6\x82\xa7\x81\x6b\x72\xe9\x2a\x51\x98\x56\xbd\x41\xf8\xb2\xcf\xfa\x41\x49\x27\x51\x4b\xce\xb5\x6d\xaa\xce\x55\x59\xb5\x35\x49\xe9\x64\xf8\x69\xf4\xd6\x4c\x49\x72\x7f\xe9\xba\xde\x28\xe4\x65\x7d\xe9\x26\x51\x55\x77\xdc\x82\x44\x2d\x2d\x68\xda\xf5\x63\xed\xa5\x23\x0d\x25\xba\xad\x92\xf4\x7a\x03\x70\xa2\x4d\xde\x3d\x0e\x6a\x27\xbe\x68\x15\x18\x6d\x7a\xce\xdb\x7c\x5f\x50\x83\x07\x5e\x25\x57\x87\xde\x74\xb2\xd1\x7a\xa8\x9a\xb3\x36\xb6\x25\x34\xb3\xd3\x8c\xed\x1f\xbb\xd7\x9a\xfe\xc0\xbf\xff\x34\x81\xdf\x1a\xda\xd2\x4e\xff\xd4\x5e\xf6\xe7\xbc\xe3\xa3\x58\xf6\x26\xa9\x6b\x4a\x1a\x52\xa6\x74\x17\x71\x32\xac\x39\x97\xa6\xed\xdb\x53\x57\x79\xd9\xd1\x46\xab\xfe\xc7\x2c\x6f\xc9\xbe\xa0\xd9\x4f\x1a\x23\xea\x2b\x1f\x86\x82\x40\x46\x0f\xe4\x52\xe8\x02\xd9\xed\x98\x9e\x1c\xaa\xf4\xd2\xc6\x79\x59\xf6\xc6\x9b\xd1\xb0\x0b\xf8\x00\x24\x59\xc6\x54\x86\x8f\x68\x43\xef\x19\x26\x83\xd3\x06\x20\x9f\xd8\x20\x0c\x97\x41\x7a\xa2\xe9\x97\x7d\xf5\x62\x08\x8b\x64\x79\xa5\x0b\x06\xea\xaa\x32\x79\xb8\x96\xeb\xc5\xee\x92\xa1\x21\x36\x5f\xe5\xe5\xbc\xa7\xcd\x4f\xbb\x9d\xac\x9f\xb5\x3f\x6e\xeb\xbc\x8c\x35\x45\x75\x80\x57\x97\x4e\x07\xff\xf6\x9b\x77\x70\x08\x83\xa1\x04\x35\x82\x92\x26\x3d\xb9\x1b\x7e\x9f\xf1\xfd\xe8\xd0\xb7\x5e\xd3\x0f\x39\x2d\x32\x27\x63\x43\xfb\xf8\x87\x38\xed\x31\x0b\x4c\x22\x2e\x8c\x8c\xa6\x55\x43\x7a\x03\x2e\x24\x82\x71\x02\xc6\x18\x63\xa8\xa5\x9d\xae\x7a\xd3\xc5\x8a\x9e\xa3\xe9\x7a\xce\xfe\x67\xb3\xa2\xe7\x47\x68\x13\xa2\x79\xfd\x02\x95\xb3\x9f\x14\xdb\xaa\xc8\xb3\xa8\xcd\x8b\x67\x35\x80\x0a\x7a\xa4\x65\x16\xa0\xd4\x9a\xe5\x41\xed\xa1\xb4\x56\xbe\x49\xb6\xeb\x07\x24\x9c\xb3\x7b\x7b\x68\x56\xda\xfb\x07\x05\xa9\x5b\xda\x77\x19\xff\x25\xd1\xb3\x49\xd4\x9d\x0c\x6e\x59\xd9\xbb\xde\xcd\xfc\x1f\xd5\xa5\xe9\x65\x87\xb8\xab\xa7\xd5\xbe\xfe\xdc\xdb\x86\x55\xbc\xaf\xf2\x82\x36\xcc\x65\xd1\xdc\xd6\xb6\x49\x3f\xa7\x6d\xfb\xb9\xf7\xd5\x98\x9f\xda\xfb\x9f\xff\x7c\xa6\x59\x4e\xa2\xba\xc9\x4b\x2e\xff\xdf\x4f\xa2\x1d\x39\x30\x37\x6f\xb7\xa7\x87\x4a\xcc\x10\x70\x96\x8f\xfe\x29\x3f\xd7\x55\xd3\x91\x92\x19\x62\x6e\x3e\xdb\x13\xc9\x7a\x81\xf5\xfd\x6a\x02\x40\x97\x20\x89\x2c\x7c\x6d\x18\xf8\xc8\xb8\xcb\xbf\xfd\xe6\x5d\x2f\x24\xd2\x3b\x56\xbd\xb9\xef\x28\xef\x73\xce\xdb\xa0\x90\x3b\xee\xf5\x73\x97\x80\xa3\xfc\x78\x6a\xe8\xe1\x27\xde\x66\xd9\x54\x36\x8e\x76\xd1\xfb\xe8\xc3\xfb\x88\x74\x5d\xf3\xa1\x87\xf9\x18\xbd\xff\xf8\x5e\x62\x0d\x1e\xda\x08\x26\x03\xd2\x50\x59\x85\xff\xdf\x0f\xef\xff\x4a\x9e\x49\x9b\x36\x79\xdd\xed\xde\xff\x24\x65\xae\x4a\xbf\x7b\xef\xa0\x2c\xe9\x30\x27\xf8\x6f\x97\xaa\xa3\x6c\x7e\xe6\x60\xf6\x68\xf8\x6e\xbb\xdd\x32\xe9\xd5\xe4\x48\xe3\x7d\x43\xc9\x97\x38\x2f\x7b\x67\x7f\x17\x91\xe7\x2a\xcf\x04\xb9\xae\x77\xea\x39\x11\xe5\xe3\x32\x6d\x8e\xb9\xb7\x1f\x33\xdd\x17\xc0\xf9\xf9\x38\x89\x3a\xc1\xda\x08\x61\xe9\x3d\xbd\x3b\x93\x97\xf8\x6b\x9e\x75\x27\xbe\x32\xb1\x7b\xef\x34\x9f\x44\xa7\xc5\x24\xe2\x23\xec\x5d\xd5\xd4\x27\x52\xb6\xbb\x68\xc1\xf8\xff\x9a\x67\xd5\xd7\xfe\x2f\x0d\xda\x62\x81\xc9\x4c\xe7\x00\xcc\xf4\xa6\x77\x7a\xb0\xb9\x98\x96\xe4\x79\x4f\x1a\x43\x14\xdc\x5c\x71\x80\x7d\x57\x3e\x4d\x53\xd2\xd0\x6e\x12\x4d\xb3\xa6\xaa\x2f\xf5\x13\xf8\x08\x7b\x22\xee\xaa\x3a\xc6\x87\x8e\xa4\x56\x90\x3d\x2d\x9c\xbd\x97\xf4\xa6\x85\x03\x0e\xb6\xc5\x6d\x47\x10\xfa\x1c\xad\xb7\x2c\xf2\xe7\xc9\x14\x85\xe2\x10\x17\x08\x57\x03\x5e\x27\xcd\x00\x29\xf0\xed\xe4\x6c\x41\x96\x65\x16\x4d\x66\xec\xfe\x59\xf8\x91\x29\xb5\xbd\xca\xef\xff\x5b\xf1\x5a\x9f\xf2\xb4\x2a\xdb\xe8\x5f\x49\x71\x28\xf2\xf2\xd8\x7e\xdf\xeb\x41\xdb\xa4\xbb\xe8\xd2\x14\x1f\xa6\xd3\xcf\x3d\x4a\xfb\xf9\xa8\x40\xe3\x93\x04\x8d\x1b\x7a\xbc\x14\xa4\x99\xd2\xaa\xfb\x78\x1b\xda\xff\xf3\x5d\x4e\x0f\xf9\xcb\xc7\xbe\x59\xbd\x5b\x48\xba\x0f\xdf\xd3\xf3\x9e\x66\x19\xcd\xe2\xaa\xa6\x65\x3f\x07\x7e\xff\xb1\x5f\xfd\xbe\x0b\x27\xfc\xb5\x3a\x1c\xe6\x1f\x23\x49\x90\xfd\x79\x13\x11\x9d\xc6\xd5\x24\xba\x0e\x50\xe8\x9a\x0b\xbd\xa9\x35\xed\xf3\xf1\xbb\x01\xe0\xff\x57\x00\xa2\x5c\x93\x5d\xfb\x7c\xfc\xfe\xa3\xe8\xfa\xa9\x42\xf2\xac\xf7\xd8\x22\x6d\xc6\x67\x79\x67\x04\x20\x50\x6b\xe0\xa2\x97\xfb\xa9\x8f\xe6\x24\xbe\xe4\xcb\x57\xcd\xa5\x9d\x41\x3f\x8a\xd3\x38\x57\x55\x77\x62\x13\x33\x29\xbb\x9c\x14\x39\x69\x69\xa6\x3c\xb5\xaa\x7d\xb1\xe0\x8e\x0d\x79\x6d\x53\xa2\x16\x20\x43\xe3\x63\x36\x31\xe7\xed\x17\x38\xd3\x0e\x96\xfe\x2f\x73\xf2\xde\xc6\xa9\x8b\x4b\xeb\x82\xdf\x23\xf0\xf4\xd2\x08\xf0\x49\xa4\x7f\xae\x5c\x64\x12\x92\x22\x84\xce\x79\xe9\xae\x79\x3e\x9b\x23\x28\x69\x51\x5d\x32\x17\xca\x3a\x99\x61\xec\x96\xcf\xb4\xa8\x6a\xea\xc2\xda\x24\x5b\x4c\x28\xb4\x4c\xf3\xc2\x8d\x73\x40\x70\x8e\x05\x69\x5d\xed\xa1\x09\xca\xdc\xf9\xd2\xe6\xa9\x1b\x05\x13\x01\xf7\x89\xdd\x38\x0b\x04\xe7\x44\x49\xd3\xb9\x51\x56\x58\x35\x1d\x69\xdc\x18\x6b\x07\x46\x4c\xcf\x75\xf7\xea\xc6\xdb\x20\x78\x97\x96\x7a\x6a\x7a\x40\x30\x0e\x79\x71\x76\x63\x60\xdd\xd9\x9d\xe2\x82\x34\x47\x97\x12\xd0\x64\x96\xa0\x58\x6e\x78\xac\x37\xfb\x5a\xf2\xd6\x2d\x68\x54\xa5\x2b\xd7\x60\xa5\xc9\x0c\xeb\xcb\x86\x9e\xab\x67\x4f\x43\x96\x08\xce\xcf\x55\x75\x8e\xf3\xd2\x8d\x84\x69\x00\x43\xaa\x2e\x9e\xe6\x60\x5a\x50\x1d\x0e\x6e\x04\xac\xfb\xdb\xfc\x58\x12\xd7\x48\xa3\xc9\x0c\x53\x80\xb4\x3a\xba\x11\xd0\xfe\x6f\x48\xeb\xee\xcc\x39\xd6\xf9\xa7\xea\xec\x96\xf2\x1c\xeb\xfe\x43\x5e\x78\x30\xb0\xbe\xef\x72\x5f\x1d\x68\xef\x57\xc4\x65\xff\x68\x32\xc7\xfa\x3e\xab\xbe\x96\x45\x45\xb2\x98\x14\xee\xae\x9c\x63\x0a\x20\x31\xdd\x58\x98\x02\x5c\x6a\x3f\x0e\xa6\x03\x79\xb9\xaf\x5e\xdc\x28\x98\x0a\xf4\xb3\x77\x9c\xe6\x4d\xea\x93\x39\xa6\x0a\x0d\xad\x29\x71\x4b\x62\x81\xe9\x42\x43\x0f\x0d\xf5\x28\xd0\x02\x53\x87\xde\x14\x78\x85\xbe\xc0\x54\xa2\xf7\x43\xdc\x18\x98\x4a\x1c\x0a\xe2\x1e\x0d\x0b\x4c\x25\xfa\x05\x58\x7d\xaa\x4a\xea\x9e\xad\x16\x98\x42\x3c\x57\xc5\xe5\x4c\xbd\x43\x7c\x81\xa9\x84\xc0\xeb\xf5\xc9\x8d\x88\xe9\x85\x40\xbc\xd4\x6e\x34\x4c\x37\xfe\xd6\xa4\x55\xe6\x56\x8b\x05\xa6\x16\x7b\xe2\x47\x5a\xa2\x13\x84\x47\xf2\x4b\x74\x86\x20\x47\xb7\xcc\x97\x98\x3e\xec\x2b\xcf\x04\xb1\xc4\xf4\xa1\xc7\x38\x93\xc6\x83\x85\xe9\x04\x0b\xd8\xb8\x51\x30\x75\x48\xc9\x99\x36\xc4\x8d\x83\xa9\x02\x8b\xba\x3b\x31\x30\x1d\xd8\x57\x85\xdb\x9a\x2c\xb1\xee\xe7\x9b\x50\x6e\x1c\x74\x82\xa0\x2f\x9d\xf4\xd2\x5d\x88\x2b\x54\x05\x7a\x44\x1e\x85\x70\xe2\x61\x9a\xc0\xf6\x93\xe2\x82\x1e\x3c\xf5\x61\xfa\xc0\xf1\x52\x5a\x76\x1e\xaf\x69\x85\xe9\x05\xc7\x6c\xfc\x4d\xc4\x54\x83\x23\xfe\xf5\xd2\x76\xf9\xc1\xed\xdb\xad\x30\x15\xf1\xba\x43\x2b\x4c\x41\xf2\x32\xa3\x65\x37\x22\x18\x7c\x0e\x61\x88\x23\xed\x43\xdd\x49\x92\xd2\x7e\x26\x8e\xd9\x06\xb1\x1b\x17\x5d\x27\xe4\x69\x77\x69\xdc\x66\x63\x8d\xe9\xcc\x99\xd4\x71\x3f\x42\x3d\x3d\xb8\x46\xfb\x9e\xef\xc3\x3b\x71\xb0\x5e\xef\x7c\xc3\x7a\x8d\x75\x37\xcd\x72\x0f\x06\xba\x56\x38\x11\x9f\x08\xb0\x6e\x66\x7b\x38\x6e\x14\xac\x83\xbd\x6e\xef\x1a\xeb\xd8\xb6\xa3\x75\xbc\x27\xe9\x97\xaf\xa4\x71\xdb\x90\x35\xd6\xaf\x07\xd2\x76\xe3\xa8\x1b\xac\x77\xc7\xb1\x30\x7b\xc0\xa2\x11\x4e\x0c\x4c\x1b\x6a\x72\x69\xdd\x02\xd9\x60\xca\xd0\x76\x95\x7b\x2a\xdd\x60\xca\x70\xa8\x1a\x7f\x5b\x30\x7d\x60\xc2\x1b\xc5\xc4\xd7\x90\xb4\x1e\xc7\xc4\xb4\x83\xfe\x95\xa6\x6e\xb5\xdd\xa0\xab\x88\x13\x7d\x6e\xaa\x11\x23\xbc\xc1\xb4\x43\x62\xfa\x8d\xcd\x03\xa6\x1d\x75\x71\x69\xd9\x9a\xc7\x8d\x86\x06\x0a\xf2\x72\x14\x0f\x53\x12\xbe\x5a\x1c\x41\xc4\x54\xa5\xfa\x32\x82\x84\x69\xcb\xdf\x2e\xb4\xed\x72\xb1\xa8\x73\xa3\x62\x3a\x93\x97\x87\x6a\x04\x0d\x55\x98\xb4\xa1\xb4\x6c\x4f\x95\xa7\x1b\x30\x75\x11\x72\x19\x59\x40\x3c\x60\x6a\x53\x7d\x19\x45\xc3\x1d\xcc\x72\x0c\x6f\x8b\x29\x0c\x69\x9a\xea\xab\x5f\x47\xb7\xa8\x83\xc1\xf0\xfc\x1a\xba\x45\x67\x19\x86\xe8\xf1\xb9\xb7\xa8\x77\xc1\xb0\xbc\x2e\xfe\x16\x53\x19\x36\x77\x78\x97\x49\x5b\x4c\x5d\x1a\xca\x4e\xa6\x1d\x2e\x85\x3b\x74\xb0\xc5\x14\x46\x20\xb2\xd3\x43\x6e\x4c\xd4\xc2\xbc\xa4\x05\x39\x93\x51\xfd\x9e\xa1\x91\xbe\x63\xee\xee\xc0\x19\x1a\xe8\x2b\x28\x71\xae\xb3\x66\x68\x98\xef\x90\xbb\xa7\xe1\x59\x82\xce\xf5\xaf\x94\x6d\x3d\xb8\xb1\x30\xe1\xf7\x58\x69\x51\xb9\x67\x9f\x19\x1a\x20\xfc\x4a\x9a\x32\x2f\x8f\x23\xc2\xc3\x44\x5f\x17\xa4\xf4\x54\x86\x1a\x77\x52\xd0\x32\x73\xc7\x30\x67\x68\x9c\xb0\x21\x65\x56\x39\x63\x8b\x33\x34\x4a\x98\x56\xe7\x33\x75\x3b\x59\x33\x34\x54\x78\x26\xc7\x92\x7a\x70\xd0\xe0\xb7\x98\x75\xdc\x43\x73\x86\x46\x0c\x25\x9e\x6f\x70\xce\xd0\xb8\x61\x43\xbb\xaf\xd4\xc7\x26\xee\x0d\x56\x75\xdd\xf7\x73\xea\x09\x3a\xcf\xd0\xe0\xe1\xa1\x2a\xd8\x36\xa4\x57\xb7\xd0\x28\xa2\xc0\xf4\xea\x32\x1a\x4a\x14\xf6\x40\x9e\xf3\x73\x23\xe3\xb1\x24\x86\x7c\xaa\x9a\xfc\xe7\xaa\xec\x3c\xe8\x78\x88\x31\x73\x3a\x39\x33\x34\xc2\xb8\xbf\x14\xc5\xa9\x6a\xdc\x4d\x44\xa3\x8c\x7b\xea\x36\x75\x33\x34\xca\x98\xf6\xd2\x38\xe4\x29\xe9\xdc\xdd\x80\x06\x1b\xbb\xd3\xe5\xbc\x6f\x7d\x1a\x8a\x46\x1a\x05\x9a\x57\x41\xd1\x60\xe3\x89\x94\x99\x7f\x8e\x9b\xa1\x01\x47\x86\xe7\x9b\x53\x67\x68\xd0\x91\xa1\xf9\x1a\x87\x29\x09\x43\xf2\x36\x0d\x8d\x39\x72\x5f\x21\x64\x1a\x9f\xa1\xe1\x47\x0d\xdf\xdb\x54\x34\x0e\xa9\xa1\x7b\x9a\x8c\x86\x24\x35\x64\x7f\xd3\x31\x2d\x3a\x16\xd5\xde\xad\x78\x68\x68\xf2\x6b\x43\x4b\xf7\xae\xd8\x0c\x0d\x4b\x76\xa4\xfd\xe2\x8c\xc6\xcd\xd0\x80\xe4\x21\x2f\x3c\x71\x97\x19\x1a\x8d\xdc\x37\x39\x3d\xa4\xc4\x63\xd1\xd0\x80\x64\xef\xda\x70\xef\xd6\x89\x87\xc6\x24\x33\xd2\x9e\xf6\x95\x67\xfd\x34\x43\x23\x93\x35\xa9\x69\x93\x16\xb9\xbb\xa7\xd1\xf0\x24\xdb\x59\xf4\xef\xfa\xcd\xd0\x28\x65\x91\x97\xce\xf5\xff\x0c\x8f\x50\x9e\x2a\x8f\x13\x80\x46\x28\xeb\x4b\x7b\xaa\xdd\xfb\x5e\x33\x34\x44\x79\x69\x3d\xa2\xc3\x3a\xf8\xb8\xf7\x08\x0d\xeb\xda\xb6\xf2\x4c\x8c\x68\x94\xb1\xc7\x88\xf7\xaf\x31\x29\xea\x13\xd9\x7b\x66\x64\x34\xd6\x68\x62\xfb\xdc\xed\x19\x1a\x75\x94\x14\xf8\x69\x1c\x27\x2a\x1a\x73\x80\xa8\xfe\x9a\xd1\xf5\x81\xe4\xbd\xeb\x9a\x7c\x7f\xe9\xdc\x7b\x16\x33\x34\x02\x69\xe3\xfb\x79\x40\x35\xa2\x64\xe1\x2a\xea\xd6\x0b\x34\x22\x49\x5f\x6a\x52\x7a\x70\xf0\x9d\x4d\x7e\xee\xca\x6f\x35\xd1\x50\xa4\x42\xf5\x58\x6b\x34\x1c\x59\x54\x47\xcf\xe6\xf0\x6c\x8d\xee\x75\x16\x9e\x0d\xd5\x19\x1a\xbd\xec\xab\xf1\x6c\x27\xcf\xd0\xf0\x65\x49\xbf\xc6\x5f\xf3\x32\xab\xbe\xba\xf1\x70\xcf\x35\xad\x3c\x26\x10\x0f\x63\x12\x77\x80\x71\x86\x46\x31\xbd\xee\x26\x1a\xc4\xec\xeb\xf0\xb0\x85\x6e\x67\xb0\xa3\x6e\x6e\x1c\x4c\x17\xe8\x8b\x17\x07\x8d\x5b\xb6\xd4\xa3\xac\x68\xcc\xf2\x50\x54\x75\xfd\x1a\x67\xee\x03\x47\x74\x86\x86\x2e\x05\xa2\x5f\x18\x68\x04\x53\x60\xfa\x0f\x41\xcc\xf0\x50\xe6\x50\xa9\x1b\x11\x0d\x67\x72\x44\x6f\x67\xa3\xd1\xcc\xb4\xa1\x59\xde\xf5\xeb\x20\x4f\x2b\x31\x2d\xe1\x57\x47\x3c\x96\x16\x8f\x67\x5e\xba\x82\x36\xee\x79\x18\x0d\x65\xf2\xc3\xb8\x4e\x1c\x34\x86\x99\x56\xe7\xba\xa1\x6d\xeb\xe9\x3c\x34\x88\x49\x49\xe3\x9f\xc4\xd1\x10\x26\x43\xf1\x1a\x6d\x34\x80\xd9\x55\x5f\x7d\xed\x42\xe7\x9a\x8e\x74\xee\xe9\x05\x0d\x5b\xb6\x99\x7f\xd7\x68\x86\x46\x2d\x4f\xa3\x58\xa8\xed\xb8\xec\xd9\xe1\x6f\x0f\x8b\xe8\x2e\x08\x3b\x91\xdb\x76\xb4\xf1\x55\x88\xfb\x29\x17\xb6\x74\x29\xf6\x6e\xa5\x42\x63\x96\x1c\x71\x15\xcf\xdc\x68\xb8\x9f\xd2\xa3\xad\x7d\x68\xb8\x73\xd2\xa3\x6d\x7c\x68\xe8\x22\x45\xde\xee\x8d\x7d\xbb\xe5\x33\x34\x6a\xd9\xd0\x63\xde\x76\xfc\x0a\xc0\x08\x3a\xba\x73\x5e\x54\x97\x6c\xf4\x7c\xcd\x0c\x0d\x43\x72\x5c\xff\x29\x9b\xd9\x16\x53\x84\xae\xa1\x34\x4e\xab\x32\xf7\x59\x96\x2d\x7e\x7c\x8a\xd2\x38\xa3\x69\x9e\x5d\x2a\xe7\x91\x4d\x3a\x4f\x50\x63\xe1\xe4\x72\x8e\x06\x4a\x7b\xfb\xec\x3d\x4a\x35\x47\xa3\xa5\xbd\x75\x1e\x41\x43\x97\x21\xf4\x99\x16\x1e\x8f\x69\x8e\x86\x4d\x7b\xd5\x71\x63\xa0\x2b\x11\xd2\xba\x63\x29\x73\x34\x5c\x4a\x0a\xea\x9e\xc2\xe7\x68\xf8\x92\xfe\xed\xc2\x6e\x82\x3b\xbb\x77\x8e\x46\x30\xbf\xe4\xa5\xf3\x1c\xcb\x1c\x0d\x5f\xfe\xed\xe2\x59\x97\xe2\x47\x77\x6b\xe2\x76\x68\xe7\x68\xdc\x72\x9f\xb7\x27\xf7\x7e\xe5\x1c\x8d\x58\x7e\x29\x7d\x91\x92\x39\x1a\xb0\xdc\x93\xfd\x6b\x7c\xa8\x9a\xf3\xa5\x70\x9e\x66\x99\xa3\xf1\xca\xce\x1d\xf7\x9d\xaf\x0f\xd8\x61\xeb\x7d\x41\xd2\x2f\xde\xe5\xf9\x1c\x0d\x53\xee\xdd\x73\xed\x1c\x0d\x4d\x92\xba\x76\x8e\x85\xc3\xc3\x01\x3b\xbf\x4c\x1b\x4f\x90\x62\x8e\x06\x24\x4f\xd5\xa5\xf1\x1d\x7b\x9e\x2f\x66\xd8\x11\xf2\x82\x9c\xdd\xfd\x8a\x46\x24\xb3\x4b\x5d\x78\xe3\x91\x73\x34\x1e\x59\xe7\xc7\xe3\x6b\xbc\x27\xee\x58\xc3\x1c\x0d\x48\xb6\x69\xde\xb6\x55\xe3\x36\x75\x68\x34\x72\x9f\x77\x69\xe5\x5e\x49\xcd\xd1\x50\xe4\xbe\x73\x1e\x55\xc2\x11\x5e\xf6\x6e\xfd\x46\x11\x5e\x9d\x43\x35\x49\x08\xd6\xfa\xbf\x3a\xad\x9b\x03\xa1\xb9\xec\x9d\xca\x36\x4f\xf6\x19\x8e\x72\x1d\x02\xbb\xf1\xe0\x6c\x38\x1a\x42\xcd\x53\x1a\x17\x55\x51\xb8\x6d\x35\x1a\x39\x55\x68\x71\xd7\x5b\x6d\xf7\xc0\x43\x03\xa7\x34\xbb\xa4\xfc\x6a\xa0\x13\x0d\xdd\x6f\x67\xa9\x31\x02\xb6\x12\xe6\x68\xc8\x54\xa0\x8f\x6d\x63\xcc\xd1\xe0\xe9\x99\x96\x97\xf8\x44\xce\xfb\x4b\x73\xf4\xcc\x1d\x68\x10\xf5\x5c\x65\xa4\x18\x59\xa2\xcf\xd1\x58\x6a\xe5\xbc\x5f\x41\xe7\x68\x20\xf5\xd8\x10\xcf\xe0\x42\x83\xa8\xed\xa5\x64\xe6\xc9\xed\x33\xcf\xf1\x83\x9d\x32\xf7\x89\x1b\x0d\x3d\xde\xd9\xa3\xf1\xbb\x6f\x4e\x3c\xf4\x1c\x78\x8f\x07\x6e\x12\x3a\x91\x51\xcd\xd9\xff\x95\xa6\x9d\x38\xa5\xe7\x39\xe0\x33\x47\xa3\xaa\x1a\xb6\xc8\x56\xe1\x24\x80\x29\x8f\x46\x20\x40\x7d\xd1\x98\xab\x46\xc4\xb7\x59\x31\x47\xcf\x88\x6a\xe8\xa3\x63\x00\x0d\xe2\x6a\x24\xbc\xdb\x2d\x73\xfc\x00\x69\x93\x93\xf2\x58\xd0\x11\x5c\xfc\x0c\xa9\xc4\xf5\xb6\x1c\x0d\xed\x2a\xd4\x91\xae\x43\xa3\xba\x0a\xd9\xa7\x35\x68\x50\x37\xad\xca\xb6\xf2\x98\x63\x3c\x94\x7b\xa9\x69\x23\x2e\x28\x3b\x11\xd1\xd9\xf8\xb2\x1f\x43\x43\x4d\x53\x6f\xd6\xfc\x22\x45\xcf\x19\xf6\x68\x23\xbd\x88\x69\x10\xc3\xf3\x85\x6d\xe7\x68\xd8\x96\xa1\x79\x16\x20\x43\xc8\xf6\xf7\xac\xf0\x57\x4a\x6e\x21\xea\xc0\xae\xea\xff\xba\x35\xea\x09\xab\x44\x82\x97\xa4\xd6\x32\x4e\x74\xa4\x8e\x4f\xf9\xf1\x54\xb0\xe5\xba\xb8\x5c\xdc\x1c\xf7\xe4\x43\x32\x89\xc4\xff\x93\x57\x41\x55\x66\x2a\xed\x26\xe7\xfb\x7f\xa5\xc5\x33\xed\xed\x42\xf4\x6f\xf4\x42\xdf\x4f\x22\xf5\x61\x12\xfd\x4b\x93\x93\x62\x62\x24\xc9\x82\xec\x2c\x39\x3b\xfa\x55\xce\xe9\x72\xfe\xb0\xda\xcc\x96\x0b\x90\x3c\xe6\xbb\xc5\x62\xf1\x88\xe6\x6e\xfa\xee\x70\x38\x48\x0e\xf5\xa4\x35\x68\xaa\x1a\x8d\x79\x90\xa4\x06\x70\x05\xbe\x6a\x8c\xe9\x09\x6c\x88\xd0\x28\xc9\xde\x86\xec\x37\x8f\x32\x45\x0d\xcc\x63\x00\xf3\x4f\xed\x58\xfe\x16\x3d\xa9\x94\x24\x31\x5f\xac\xe6\x9b\x14\x25\x01\x52\x21\x40\x3a\x0c\x5d\xe5\xa4\xea\x4e\x79\x29\xb2\x4d\x3d\xc2\xef\xab\xfa\x85\x25\xc7\x88\x86\xeb\xb1\xe9\xa5\x8d\x1b\x76\x92\xa4\xaf\x1b\x40\xc7\xd5\xe1\xd0\xd2\x6e\x17\xc5\x73\x95\xef\x08\xc9\x88\xa4\x72\xb4\x88\x8c\x01\x66\x32\xa7\x73\x9e\x65\xc3\x2d\xda\x94\x34\xd5\xa5\xa5\x05\x4f\xdb\xf2\x34\xcd\x3b\x7a\x7e\x22\x4f\x2c\x35\x01\x5e\xc8\x8b\xf2\xf3\x31\x6e\x68\x5b\x57\x65\x9b\x3f\xd3\x09\xbb\xe0\x7e\xba\x9c\xf7\x25\xc9\x8b\x48\xe2\xab\x2f\x4f\x92\x19\x3d\x77\x19\x4f\x45\xa2\xe5\x33\x78\xc4\x53\xbf\xf0\xfa\x7a\xd5\x12\x29\x29\xc4\x88\x6a\x48\x96\x5f\xda\x5d\xb4\x56\x12\x61\x90\x03\x2b\xbf\xf8\xae\x3d\x8f\xd4\xad\xa5\xbe\x19\x1f\x0d\xb8\xfa\xe3\xd9\x55\xbe\xcb\xb2\xec\xd1\x6e\xc6\xd2\xb0\x00\x0d\x29\xe5\x9d\x6e\x52\x14\xd1\x74\xde\x46\x94\xb4\x34\xce\xcb\xb8\xba\xb0\x41\x10\x57\x21\x50\x23\x20\x50\x74\xfc\x14\x03\x26\xe3\x95\x4a\x33\x26\xb2\x6c\x71\x8d\x63\xf3\x68\x34\x17\xc6\x4b\x7c\x93\x19\xc0\xe4\x67\x95\x27\x06\x34\x5a\xde\x4c\x97\x22\xa1\x54\x69\x65\xdb\xc4\x55\x59\x70\x8b\x36\x5c\x6b\x27\xfb\xb6\x2a\x2e\x1d\xbb\xd6\x2e\xbb\x8d\x93\x57\x1d\x52\x1b\xf9\x8a\x60\xb2\x9b\x58\x94\x9a\xc9\xc5\x98\x25\x2b\xf2\x7a\x17\x35\x34\xed\xa0\x71\xc5\x32\xdc\x48\xde\xf8\x48\x25\xfd\x12\x50\x66\xa3\x43\x8a\x06\x53\x30\x34\xa3\xed\x48\x97\xa7\xa0\x11\x52\xd7\x4c\xdd\xd3\x32\x77\x59\x89\xb8\x06\xb6\xc1\x38\xf9\xb1\xa9\x0a\x95\x56\x8b\x5b\x30\x34\x23\xd6\xf4\x34\x9b\x44\xd3\xd3\xbc\xff\xcf\xa2\xff\xcf\xb2\xff\xcf\xaa\xff\xcf\x7a\x12\xf5\x85\x32\x8d\x48\x5f\xd2\x17\x9c\xd6\xe3\x26\x5a\x26\x01\x58\x61\x49\x00\xa6\x33\x67\xbe\xb1\xe9\x69\x16\x4d\xd9\xe1\xd4\x9e\x81\x59\xa4\x7e\xce\xc1\xe7\xf9\xf0\x79\x01\x3e\x2f\x86\xcf\x4b\xf9\xb9\xb7\x46\xa7\xe5\x50\xb0\x02\xf0\xab\xe1\xf3\x1a\x7c\x5e\xcb\xcf\x80\x15\xc5\x09\xcb\x93\x32\x7c\x56\x9c\x00\x46\x06\x3e\x06\x36\xa2\x81\x87\x81\x85\x9e\x96\xe2\x01\xb0\x20\x39\x18\xa4\x3c\x9a\x52\x41\x5a\x99\xcd\x66\x83\x77\xeb\xd0\x8f\xa1\xe3\x75\x36\xa4\xd2\xbb\x4b\xa7\x0c\x34\xfa\x76\x2b\x22\xa1\xd2\x34\x5d\xa4\xf5\xea\x77\x8a\x3b\x5d\x63\x75\x2d\x85\x2d\x9d\x05\xb4\x74\x09\x78\xbf\x55\x6f\xa0\xf6\x61\x1d\x1f\x05\x76\xbb\xca\xcd\x08\xfb\x54\x64\x95\x04\x00\x0b\x30\xe5\xb1\x3e\x9e\x5b\x10\xb0\x85\x0b\xa5\x05\x30\x0d\xe5\x12\xca\x80\xb5\xc1\xf4\x49\x1f\x00\xc4\x8a\xb5\xc1\x84\x80\x34\xd6\xba\x9d\x10\x10\x83\xbb\x52\xeb\x9e\x4a\x94\x68\xdd\x50\xc8\xdc\x49\x8e\x49\x04\xd2\x5c\x83\x4f\x72\xa0\x2c\x50\xb3\xb3\x14\xe4\x45\x8e\xae\x0f\xd1\x39\x2f\xf9\xac\x1f\xed\x36\xeb\x87\xfa\xe5\x23\xab\x73\xa8\x5d\x93\xd0\xac\x67\x4f\x25\xdb\x91\xbd\x86\xa7\xe1\x1c\xba\xec\x4c\x9a\x2f\x93\x48\xe5\xf6\x1c\xb2\xb1\xcd\x79\xfe\x35\xcc\x55\x48\x0f\x0f\x74\x21\x09\x30\x2f\xb3\x5f\xc5\x31\x7c\xf6\x97\x70\xdf\xfa\x8f\x1a\x14\xcf\xd5\x6b\x82\xb1\xaf\x1a\x1c\xbf\x3d\x69\x01\xf2\xcf\x1a\xa4\xb8\xf4\x68\x81\x8a\xef\x1a\x6c\x59\x7d\x6d\x08\xef\xd6\xaf\xa7\xbc\xa3\x2c\x55\x1b\x4b\x0f\xd3\x7f\xd7\x9b\x53\x7d\xa5\x4d\x4a\x5a\x3a\x10\x06\xd9\x22\x55\xa9\x86\x73\xa9\x6b\x0f\x8e\x2a\xd5\x1b\x4a\x6a\x76\x19\xf6\x67\x1c\x69\x28\xd6\xb0\xce\x17\x99\xed\x0c\x31\xab\x0c\xa2\x6e\x72\x95\x83\x57\x5f\x5a\x48\xcf\x5f\x83\xc3\x56\x11\x0f\xeb\x64\x9b\x68\x44\xdb\x4b\x9a\xd2\xb6\xd5\x89\xa6\x9b\xf5\x22\xd3\x89\x0a\x38\x8c\xe8\x7e\xb5\x9c\xa7\x1a\xd1\xbc\x3c\x54\x3a\xc5\xd9\x26\x79\x38\xe8\x14\x7b\x20\x8c\xdc\x72\x35\x5f\x6f\x35\x72\xe2\x0a\x83\x06\xf6\x40\xd6\xd9\x62\xaf\x53\x14\x70\x08\xd1\xf5\x7a\x35\x33\x78\xcc\x48\x79\x34\xa0\xc8\x76\xb9\x5c\xce\x75\x9a\x1c\x0c\x21\xf9\xb0\x5c\xac\x16\x72\x6c\x4f\xf7\x47\xb4\x7b\xa4\xff\x6d\x0f\x37\xa3\xe3\x06\x7c\x50\x15\x82\xa6\xf7\xe0\xfe\xa8\xf5\x1f\x02\x9f\x1d\x0e\x49\xf6\x00\xab\xb1\x3b\x12\x41\x4b\x67\x74\xbe\x5f\x80\x6a\x54\x8f\x62\x75\x6c\x69\x76\xd0\x9a\x62\x74\x2d\x82\x43\x0e\xd9\x76\x70\xb7\xf7\x47\xad\x8f\xc7\xac\x13\x01\x08\xfe\x6a\x0e\x1b\x9a\xee\x57\xa0\x1a\xd0\xeb\x18\xf8\x3c\xa3\x19\x85\xb5\x58\xdd\x8f\x60\xd1\xe5\x7e\xbb\x57\x1a\xcb\x92\xd8\xf1\xf3\x3d\xd0\xf6\xaa\xc9\x64\x0b\xbd\x81\x1d\xcb\x1d\x1c\x25\xc6\x3a\x45\xcb\x11\x6d\xad\x4e\xaa\x62\x12\x5d\x0a\xcb\xcf\x48\xfc\x4e\x46\x55\x44\x3d\x62\x55\x44\x17\x8e\x2f\xc8\xe8\x94\x24\xa2\x52\x31\x96\x4f\xe3\x52\xb2\xa4\x5b\x5a\x02\x4e\x1e\xe3\x8b\xc4\x8c\xd7\x82\xbc\x5c\x2a\x12\xc1\x91\xf9\xa2\xd7\x85\x2a\xea\xe5\x5f\xe2\x95\x5c\xe4\x8e\xd2\x7b\x2a\x72\xff\xda\x5a\xd6\xd5\x88\x25\x81\xb6\x32\x13\xf5\xad\x94\x74\xb2\x30\x79\xce\x07\x79\x66\xd9\x24\xca\x90\xfc\xb9\xc3\x9a\x5c\x02\x76\xb6\x4b\x0d\xf2\x79\x6b\x1e\x87\x10\x4c\xa0\xc7\x90\x15\x20\xf4\x2f\x99\x79\x77\x28\x2a\xd2\xf1\x79\x5a\x66\x5c\x64\x2b\xd5\xb5\x50\x31\x74\xfd\xf9\x2e\x2d\x28\x69\x00\x96\x35\x97\x0f\x5f\x07\x7c\x5a\x14\x79\xdd\xe6\x2d\xaf\x07\x9b\x7e\x79\xea\x41\x83\x51\xe1\xe6\x68\x6d\x9e\x3d\x24\x9a\xa7\xc3\x52\x73\x66\xa4\x23\x71\xd5\xe4\xc7\xbc\x24\x45\xcc\x13\x75\x4e\x22\x33\xaf\xba\x5c\x61\x9e\x68\x51\x3b\xc6\x10\x8f\x7c\x69\x53\x6a\x5e\xe6\x2c\xf1\x5b\x7b\x36\xfd\xa8\x2d\x8f\xc4\x8c\x4d\xf6\x43\xe6\x4e\xdd\xc7\xea\xc7\x9c\xb1\xbc\xe1\xae\x26\xe6\x46\x6e\xa6\x2b\x6d\xe0\x2b\xbd\xb4\x87\x3d\xa8\xaf\x2a\x76\x05\x69\xbb\x38\x3d\xe5\x45\x36\x89\x40\x49\xed\x2a\xb8\x40\x14\x91\xd0\xd7\x31\xe6\x01\x96\xf4\x37\xc1\x27\xf9\x7a\x00\xf8\x34\x78\xa3\x76\x78\x4d\x4f\x13\x1f\x18\xcf\x1d\xba\xc9\xe2\x45\x84\xc8\x11\x96\xb0\x12\x88\x22\x1a\xad\xc2\xfc\xdf\xff\x65\x9e\xcc\x96\xd1\x5f\x92\xe4\x5f\x92\xef\xd5\x14\xa1\x70\xe3\x86\x3e\xd3\xa6\xd5\xe8\x4d\xeb\x4b\x51\x00\x87\xd7\xb0\x31\x33\xd4\xc8\x24\x8f\x98\x6b\x0c\x83\x6f\xca\x42\x81\x4e\xb7\x74\x22\x71\xb3\x68\x8a\x06\x03\xd1\x65\xc4\xf2\x9f\xda\x40\x2e\x09\xc3\x76\xeb\x75\x69\x19\x6c\x21\x98\xb3\x4f\x20\x90\xb7\x7b\x3c\x7d\x22\x99\x10\xdb\x26\x9e\xf6\x72\x08\x6f\x73\x05\x11\x6f\x6b\x15\x19\x6f\x63\xbd\x94\x00\xa1\xc8\xd0\xc3\x5e\x03\x23\xa6\x8d\xb2\xcd\x24\xcb\x1a\xe9\xd5\x79\x17\xa3\x66\x2e\x4c\xff\x54\x14\xf6\x16\xc0\x9f\x68\x59\x54\x93\xe8\x4f\x55\x49\xd2\x6a\x12\xfd\x81\xed\x3a\x92\x76\x12\xbd\xff\x43\x75\x69\x72\xda\x44\xff\x46\xbf\xbe\x07\x0f\x05\x00\xea\xba\x29\x9c\xd7\x2f\x32\xa4\x6c\xdb\x57\xe5\x6b\x6e\xe6\xab\x25\x75\xad\x4a\xb7\x87\xf9\x61\x89\x47\xaa\x45\xb5\x5f\xf6\xd9\x0d\xb5\xfa\x3c\xf3\x05\x52\xdf\x42\x8f\x8c\xc3\x24\xd6\x79\xd9\xd2\x2e\x4a\x58\x7c\x37\x4a\x8c\x1d\xb2\xe9\x7c\xf5\x51\xed\xc6\x85\x22\x80\x96\x59\xad\x33\x9f\xf2\x90\x1b\x07\xa6\x7f\xe1\xe2\x56\xbe\x94\x62\x7e\x93\x11\x12\xb1\x9b\x63\x5b\x72\xc5\xc1\x56\xce\x59\x66\x1c\xc5\xe4\x6c\x71\xed\x06\xde\xd7\xaa\xc9\x78\x02\xe8\x5d\x24\xf2\x40\x17\x85\x2a\xe8\x3d\x0a\xf9\xbd\xff\xe0\x52\x99\x55\xff\xcf\xb1\xed\x91\xa6\xa9\x57\x99\xfa\xe6\xdb\x7a\x6c\xca\xdc\xf9\x7e\xc5\xa3\x19\x86\xa8\x1b\xca\xf8\xc6\x79\x05\x4f\xcb\x20\x5c\x29\x8b\xdf\x13\x69\xd3\xa6\x2a\x0a\x95\x3b\xfa\x4c\x5e\x94\x48\x17\xcb\x44\xdf\x58\x88\x5f\x77\x11\x87\x57\xbb\x6c\xbd\xe7\x95\x1b\xef\x42\xf8\xa7\xad\x99\xd6\xc9\x12\x56\xdf\x1a\x10\xa0\x20\xfe\x3f\xe6\xb2\xea\x8c\x48\xdf\x74\xb3\xd2\x9d\x3f\x8c\xca\x76\x3b\x1f\xa1\xb2\xdd\x8c\x53\x99\xcd\x93\x64\x84\xcc\x6c\x66\xd0\x19\xe0\xe2\x43\x71\xc9\xb3\x5f\x5b\x86\xd3\xa6\xfa\x0a\x2d\xbf\x40\x8b\x0d\x6a\x62\xc9\x34\x1b\x16\x31\xd3\xb4\x2a\xe2\xe2\x18\xcf\x26\x91\xfa\x99\x80\xdf\xf0\xfb\x7c\xf8\x0d\x7e\x2e\x26\x5c\x2e\xec\x8f\xe5\xf0\x7d\x35\xfc\x5c\x0f\x3f\x37\xc3\xcf\x87\xe1\xe7\x56\xd1\x38\x67\x8a\x95\xfe\x67\x02\x7e\xc3\xef\xf3\xe1\x37\xf8\xb9\x80\x64\x96\xc3\xf7\xd5\xf0\x73\x3d\xfc\xdc\x0c\x3f\x1f\x86\x9f\x03\x2b\xed\x59\xb1\xd2\xff\x4c\xc0\x6f\xf8\x7d\x3e\xfc\x06\x3f\x17\x90\xcc\x72\xf8\xbe\x1a\x7e\xae\x87\x9f\x9b\xe1\xe7\xc3\xf0\x73\x60\xe5\xa5\x55\xac\xf4\x3f\x13\xf0\x1b\x7e\x9f\x0f\xbf\xc1\xcf\x05\x24\xb3\x1c\xbe\xaf\x86\x9f\xeb\xe1\xe7\x66\xf8\xf9\x30\xfc\xdc\x1a\xfb\x81\x30\x5b\x77\x3f\x54\xf0\xcd\xcc\x71\x4d\x87\x5a\xf8\x0f\xd2\x48\xb0\x16\x36\xb9\xe3\xdb\x15\x60\xf7\xdd\x04\x98\x41\x80\xed\x6c\xba\xe6\xff\xb7\xb1\x00\x13\x08\xf8\xb0\x98\x2e\xc4\xff\x99\x80\x5b\x08\x07\xf6\x57\x24\xf3\xb0\x78\xbd\x76\xd6\xb7\x81\x70\xab\x07\x67\x75\x6b\x0d\xce\x6a\xdf\x0a\x16\x2f\xdd\xcd\x5b\x42\xb8\x85\xbb\x75\x0b\x08\x37\xb7\x5a\xa7\x8b\xdb\xdd\x3a\x4d\xea\xee\xc6\x31\xc7\x5a\xf4\xa1\x54\x4c\xbb\x0f\x39\xd4\x0c\x42\x79\x3a\x92\x43\x27\x10\xda\xd3\x9b\x0c\x7a\x0b\x81\xed\x2e\x65\x30\x0f\x10\xc6\xd3\xaf\x0c\x78\x03\x81\x3d\x9d\xcb\x80\xd7\x1a\x30\xde\xfa\x15\x84\xf1\x74\x33\x03\x5e\x42\x60\x4f\x5f\x33\xe0\x05\x04\xb6\x3b\x9c\xc1\xe8\x1d\x34\xd2\x76\xad\x9f\x46\x9a\xae\xf5\x12\x9c\x3b\x15\x50\x7b\x92\xfa\x21\x2c\x14\xa6\x1e\x3d\xd0\x0c\x00\x79\xb5\xa3\x07\x4e\x00\xb0\x57\x39\xda\x93\x50\x0e\x0e\x8b\xe9\x46\x7b\x12\xba\xc1\x41\xbc\xaa\xd1\x9e\x84\x6a\x88\x00\x91\x4f\x3c\xed\x49\x68\x86\x80\xc5\xdb\xbd\x02\x20\x5e\xbd\x68\x4f\x42\x2f\x38\xac\x57\x2d\xda\x93\x50\x0b\x0e\x8b\x69\x45\x7b\x8a\xb5\x6e\x19\x69\x35\xec\x9d\x91\x46\xc3\xbe\x41\x54\x82\x9f\x5e\x93\x4a\xa1\x07\x1f\x6d\xdd\x90\xd0\x33\x1b\xda\xa3\x24\x12\x2b\xb1\xb1\x3c\xda\x22\xb0\xb6\x36\x92\xad\x36\x02\xf6\xc1\x86\xf5\xe8\x8f\x40\xda\xd8\x48\x1e\x45\x12\x48\x6b\x04\xc9\x25\xad\x95\x0d\xeb\x51\x2d\x81\xb4\xb4\x91\x3c\x3a\x26\x90\x16\x36\x92\xad\x6c\x02\x16\xeb\xf0\x51\x59\x21\xfd\x3e\x2a\x2a\xa4\xd7\x43\x43\xf9\xf7\xf1\x51\xdf\xec\xa4\x5a\x3b\x08\x32\x82\xaf\x2a\xd7\x97\x4a\x6c\xdc\xe8\x10\x33\x7d\x4d\xa6\x75\xbf\x0e\x99\x68\x90\xfa\xf8\xd0\x20\xb7\xc6\x62\xd1\x2c\x7f\xd0\xca\xf5\x71\xa0\x01\x6e\x34\x40\x5d\xf7\x35\xc0\xb5\x0e\x68\xb5\x72\xa5\x95\x2f\xdd\x8d\x5c\x6a\x80\x0b\x77\x1b\x17\x1a\xe0\xdc\x6a\xa3\x21\x78\x77\x1b\x75\xf9\xbb\x9b\x08\x3d\x28\xdd\x85\x42\xc0\x66\x1a\x98\xa7\x53\xa1\x0f\x85\x3b\x51\x36\xf8\x56\x83\xb6\xbb\x17\x78\x51\xb8\x1b\x65\x43\x6f\x34\x68\x4f\x47\x03\x3f\x4a\x73\xa4\x6c\xa0\x95\x06\xe4\xe9\x72\xe0\x49\xe1\xae\x94\x0d\xbd\xd0\xa0\xed\xce\x07\xbe\x14\xee\x4c\x21\x7d\xa0\x77\x81\xbf\x7e\xbd\xbf\xf8\xdc\x69\x40\x0d\xee\x94\xe6\x4f\x21\x50\x33\x08\xe5\x55\x95\xc1\xa1\x42\x3d\x2a\x1b\x7a\x0b\x81\x31\x45\x51\x2e\x15\xea\x53\xd9\xc0\x1b\x08\xec\x55\x13\xe5\x54\x41\xaf\xca\x86\x59\x41\x18\xaf\x92\x28\xb7\x0a\xf5\xab\x6c\xe0\x05\x04\xc6\x54\x44\x39\x56\xa8\x67\x85\x88\x5e\x93\xbc\xbf\x72\xad\x97\x10\xfd\xd0\x7d\x2b\xcc\xb9\x42\xc1\x67\x08\xb8\x47\x63\x74\xef\xca\xe7\x5e\x61\x68\x5b\x04\xcb\xd6\x21\xcd\xbf\xf2\x39\x58\x18\xd6\x06\xc1\xf2\x68\x95\xe6\x61\x21\x2e\x16\x06\xbc\x42\x80\x3d\x7a\xa6\xf9\x58\x3e\x27\x0b\xc3\x5a\x20\x58\xb6\xe6\x69\x5e\x96\xcf\xcd\x42\xfb\x12\xeb\xca\x31\xbe\xb0\xfe\x4f\xae\x0a\x1f\xdf\x23\x36\xf9\xe6\xe0\xa4\xd7\xd9\x62\x95\x7b\x9d\x2d\xc6\x6a\x90\xb3\xc5\x1a\x18\xe4\x6c\x0d\x6c\xe1\xce\x56\xdf\x82\x20\x67\xab\x6f\x75\x90\xb3\xd5\x4b\xca\xe7\x6c\xf5\x42\x0d\x72\xb6\xfa\x8e\x08\x72\xb6\xfa\xfe\xf3\x39\x5b\x7d\x57\x07\x39\x5b\xbd\x58\x43\x9c\xad\x73\x16\xe4\x6c\x29\xb0\x30\x67\x4b\x81\x87\x39\x5b\x12\xdc\xeb\x6c\x49\xa0\x30\x67\x4b\x42\x87\x39\x5b\x12\xda\xeb\x6c\x49\xa0\x30\x67\x4b\x42\x87\x39\x5b\x12\xda\xeb\x6c\x49\xa0\x30\x67\x4b\xf5\x41\x88\xb3\x25\x81\xfd\xce\x16\x83\x1a\x75\xb6\x14\x54\x90\xb3\xa5\xa0\x83\x9c\x2d\x09\xed\x73\xb6\x24\x4c\x90\xb3\x25\x81\x83\x9c\x2d\x09\xec\x73\xb6\x24\x4c\x90\xb3\x25\x81\x83\x9c\x2d\x09\xec\x73\xb6\x24\x4c\x90\xb3\xa5\x44\x1f\xe0\x6c\x49\x58\xaf\xb3\x75\xce\xae\x72\xb6\x00\xf8\x35\xce\x16\x40\xbb\xc6\xd9\x1a\xd0\x02\x9c\xad\x01\xf8\x1a\x67\x6b\xc0\xba\xc6\xd9\x1a\xb0\x02\x9c\xad\x01\xf8\x1a\x67\x6b\xc0\xba\xc6\xd9\x1a\xb0\x02\x9c\xad\x01\xf8\x1a\x67\x0b\xf4\x65\xb8\xb3\x35\x20\xdd\xe2\x6c\x19\xbb\xec\xf7\xd8\x94\x7e\xf3\xae\xb4\xd7\xdb\x62\x95\x7b\xbd\x2d\xc6\x6a\x90\xb7\xc5\x1a\x18\xe4\x6d\x0d\x6c\xe1\xde\x56\xdf\x82\x20\x6f\xab\x6f\x75\x90\xb7\xd5\x4b\xca\xe7\x6d\xf5\x42\x0d\xf2\xb6\xfa\x8e\x08\xf2\xb6\xfa\xfe\xf3\x79\x5b\x7d\x57\x07\x79\x5b\xbd\x58\x43\xbc\xad\xe2\x18\xe4\x6d\x29\xb0\x30\x6f\x4b\x81\x87\x79\x5b\x12\xdc\xeb\x6d\x49\xa0\x30\x6f\x4b\x42\x87\x79\x5b\x12\xda\xeb\x6d\x49\xa0\x30\x6f\x4b\x42\x87\x79\x5b\x12\xda\xeb\x6d\x49\xa0\x30\x6f\x4b\xf5\x41\x88\xb7\x25\x81\xfd\xde\x16\x83\x1a\xf5\xb6\x14\x54\x90\xb7\xa5\xa0\x83\xbc\x2d\x09\xed\xf3\xb6\x24\x4c\x90\xb7\x25\x81\x83\xbc\x2d\x09\xec\xf3\xb6\x24\x4c\x90\xb7\x25\x81\x83\xbc\x2d\x09\xec\xf3\xb6\x24\x4c\x90\xb7\xa5\x44\x1f\xe0\x6d\x49\x58\xaf\xb7\x55\x1c\xaf\xf2\xb6\x00\xf8\x35\xde\x16\x40\xbb\xc6\xdb\x1a\xd0\x02\xbc\xad\x01\xf8\x1a\x6f\x6b\xc0\xba\xc6\xdb\x1a\xb0\x02\xbc\xad\x01\xf8\x1a\x6f\x6b\xc0\xba\xc6\xdb\x1a\xb0\x02\xbc\xad\x01\xf8\x1a\x6f\x0b\xf4\x65\xb8\xb7\x35\x20\x8d\x79\x5b\x9d\x3a\x01\xea\x3d\x4d\x2a\x4f\x64\x13\x96\xa0\x8e\xc1\xcb\xf3\x5a\xec\x6e\xd3\x83\x7e\x86\x4b\x9e\x2d\x17\x9f\xc1\x35\x0c\xf3\xee\x02\x38\x49\xd5\x9d\x18\x5d\xe7\xdd\x60\xc5\xa9\x91\xe1\x04\x49\x7a\xe2\xbe\x65\xc5\xc9\x3c\x75\xfb\x2a\x7b\x7d\xea\x9a\xa7\x2e\x9b\x44\xd6\xb7\xd3\xf0\xed\x50\x55\x9d\x09\xa7\xbe\x9d\x78\x9a\x18\xfe\xf5\x44\x49\x66\x42\xaa\x6f\x27\x28\x32\x25\x17\xcf\x41\x66\x33\xc9\x4d\x57\xd5\x9e\x4c\x23\x59\x96\x19\xed\x33\x6a\x36\xc9\x71\xc9\x20\x97\x9b\xe6\x1e\xa2\xa2\xf7\x3f\x49\xe2\xbb\x43\xde\xc8\x1b\x40\xb0\xd9\x7e\x38\x28\xb4\xb4\x2a\x7a\x95\xab\xc7\x49\xfa\x01\xad\x8e\xd0\x8b\x9d\x64\xc7\x61\x4f\xe2\x1a\x09\x14\x7c\x82\xe8\xd2\xa7\x4e\x65\xac\x82\xa0\x1e\x71\x46\x53\xdf\xd8\x03\x89\xa6\x38\x5c\x9c\x56\x65\x46\xcb\x96\x66\x98\xf2\xa2\xa5\x40\x2a\xb0\xdc\x56\x69\xb4\xd4\x81\x6d\xab\x39\x5a\x6a\x28\xfc\xca\x18\x80\x31\x17\x92\x96\xfb\xc8\xab\xd1\x0a\x01\x6d\x3d\x52\x08\xd9\x1f\x8a\x91\xb6\x23\x85\x38\x2e\xd2\x72\xa4\xf0\x74\x43\x8b\xae\xa7\x2c\xc6\xab\xb4\x7b\x73\x53\xbc\x6d\xd7\xe4\x35\x90\xc7\xae\xec\x4e\x71\x75\x88\xbb\xd7\x9a\x7e\xa8\xb2\xec\xa3\x53\xed\xb6\xfd\x3f\x9d\x18\xbb\xac\x3c\x90\xf2\x5f\x90\x66\x97\x25\xb4\xc9\x25\xad\x8a\x1f\xd3\x82\xb4\xed\xef\x7f\xe8\xe7\x26\x7e\xc7\x12\xcb\x1e\xa4\xae\x88\x48\xb5\x2a\x2e\x67\x76\x99\x54\x2c\xb2\xc1\xad\x12\x4e\xb9\xcb\x34\xc2\x93\x48\x7c\x3e\xdd\x56\x1f\xe5\x77\x43\xec\xda\x8c\x09\x62\xca\xf3\x23\x61\x73\x87\x2a\x3a\x21\xd3\x4a\x26\x4a\xa1\xb1\x1a\xf4\x75\xaa\xb2\x2e\xe9\xd3\x0c\x56\x9b\x59\xa4\xd9\xbf\x41\xc7\x5d\x24\xb1\xda\x84\x9a\x81\xda\xec\xb9\x0d\x6b\xdd\xa0\xbb\x2e\x92\x43\x6d\xd2\x96\x8e\xa8\x0d\xaa\x76\x82\xc4\x4e\x7c\x1d\x46\x8a\x17\x0c\x8e\x64\x4c\x8d\x9f\x0c\xa6\x0d\xa0\xa1\x55\x1c\xdc\x49\x6d\x68\xe3\xc8\xd5\xfe\x87\xfe\x9f\x43\xad\x44\x26\x05\x54\xaf\x54\x19\xae\x58\xa2\xd8\xa1\x59\xb2\xd4\xd2\x1f\xac\x46\xab\xcc\xa5\x5c\x2e\xaa\x68\x8d\x52\x83\x40\x8d\x88\x7e\x61\xad\x04\x0a\xe6\xa2\x0a\x6a\x74\xab\x98\x96\xb9\x02\xd7\x1d\x2d\x95\x85\x47\xc7\x0c\xb8\x71\x25\x33\x18\x47\xb4\x4c\x23\xe9\x55\xb3\xa0\x7c\x1b\x59\x42\xb7\xe9\xda\xa1\x67\x79\x79\xa8\x50\x25\xe3\x05\xb8\x86\xf5\x65\x0e\xf5\x62\x45\x96\xfe\x58\xb5\xe8\x05\x2e\xad\x42\x89\xd9\xb5\x48\x8d\x91\xb5\x20\xca\x64\xb5\x06\x68\x12\x4a\x4c\xd6\xe2\xd1\x21\x98\x99\x04\xd7\x8d\x21\x55\x89\x47\x81\x20\xd0\xb8\xf6\x40\x66\x11\xd5\x19\x88\x79\xf5\x66\x3c\x87\x4a\xba\xa4\x8b\xc3\xc2\xa1\x34\x22\x3d\x0a\xaa\x37\xaa\x0c\x57\x1d\x51\xec\xd0\x1e\x59\x6a\xe9\x09\x56\xa3\x55\xe6\x52\x23\x17\x55\xb4\x46\xa9\x31\xa0\x46\x44\x9f\xb0\x56\x02\x95\x72\x51\x05\x35\x7a\xe6\x3f\x3d\x59\x16\xa6\x33\x5a\x7e\x1a\x8f\x6e\x19\x70\xe3\xea\x65\x30\x8e\x68\x98\x46\xd2\xab\x64\x61\x49\x74\xc8\x61\x9e\xa6\x0e\x3d\xe3\x09\x72\x50\x35\x93\x45\xb8\x96\xf1\x52\x87\x92\x89\x42\x4b\x8f\x90\xda\xcc\x22\x97\x86\x39\x48\x62\xb5\x49\x0d\x1a\x6a\x43\xd4\x0b\x69\x1d\xd0\x2e\x07\xc9\xa1\x36\x8f\x6e\xc1\x24\x44\xb8\xce\xc0\xac\x44\x1e\xd5\xd2\xc1\xc6\x35\x4b\x67\x1a\x51\x2c\x48\xd0\xab\x57\x41\x69\x93\xf6\x69\x6a\xa8\x15\xc8\xe8\xcb\xb0\xe0\x6d\xc4\x69\x32\xfb\x9d\x76\xc9\xf9\x05\xbb\x78\xcc\xdf\x6e\x8d\x48\x99\x45\x1f\x86\x40\xd3\x66\xbd\x51\xdb\x91\x68\x45\x66\x8c\xca\xca\xa3\xb4\x32\x72\xe7\xc4\xaf\x5a\xf6\x9c\xf8\xdc\xaa\xb4\x38\x32\x29\x43\xff\xad\x67\xf0\x94\xb3\x18\x1b\xbf\x90\xbd\x27\x2c\xa3\xb2\x73\xc1\xc9\x63\x82\x26\x8f\x4f\x20\xf6\x80\x64\x6d\xf1\x22\xa1\x0b\x70\x1f\xd4\x89\x6f\xb7\x3a\x01\x91\x35\xb9\x0f\x6a\x8c\x1c\xb2\x98\xf6\x41\x9d\x7a\x6a\xbc\xcb\xdc\xf9\x86\x1c\x64\xf4\x28\x06\xcc\xac\x1b\x86\x06\x45\x09\xc3\x4e\xde\x16\xa2\xc1\x8e\x5b\xb0\x07\xb9\xbf\x09\xfb\xa6\xba\x87\x4e\x7a\x13\xb6\x56\x37\xec\x04\x3d\xd2\x7d\x65\x4f\x80\x8c\x47\xd7\x77\xc4\xf5\xc8\xa0\x1f\xde\x80\x7c\x4b\xcd\xa0\x17\xde\x80\x0c\x6b\xd6\xfa\x40\xec\x91\x5e\xdf\x09\x80\xa0\x98\x2c\x6f\x45\xf6\x1b\x0b\x5b\x8e\xb7\xd5\x8c\x21\x9f\x34\x51\x18\xc6\x95\xcd\x30\x87\x9c\x16\x59\x4b\x3b\x35\x33\x89\x39\x23\x71\x67\xfc\x4e\xb0\x04\xde\x05\x3d\xd2\x92\x4b\xde\x4e\xb2\x62\xcc\x43\x18\x59\x5f\x5a\xda\xf9\x0c\xd9\xa9\xb0\xb3\x95\xe8\x39\x6e\xf4\xac\xe8\x58\xea\xc1\x55\xff\x4f\xb2\x4f\xf6\xf4\xfa\xb4\xf6\x06\xeb\x2b\x24\x7b\xee\x90\x13\x8f\x3d\xd1\xf0\x63\xf7\x5a\xd3\x1f\x5a\x4a\x9a\xf4\xc4\x63\x82\xbf\xee\x8b\x18\xa0\x52\xf6\xee\xf4\xbe\x7a\xf9\x49\xbc\x16\xc1\xbf\x36\x24\xcb\x2b\xce\x89\x4a\xde\xc8\xf2\xf7\xc0\xbe\x51\x3b\x3d\x7f\xd9\x5a\xfd\xc0\xb3\x34\xd9\xd5\x1d\x72\x99\xc9\x4e\xd7\x07\x1b\xb2\xe9\xdd\x2a\x0c\xf4\x11\x4d\x65\xc0\xdf\xb8\xf8\xf1\x7c\x29\xba\xbc\x66\xa9\xf3\xc4\x97\x5e\x59\x38\x19\xe4\xa9\x03\x93\x33\xf9\x2c\x05\x26\x20\xa4\x8c\x8b\x89\x17\x08\x27\xf7\x57\x7f\x85\xa2\xba\x74\xf5\xa5\x73\xc8\x45\xdb\xf8\xdc\xd8\x59\x8a\xc2\x9f\x19\x59\xad\x54\xc8\xf3\x50\x35\xe7\x38\xad\xca\xae\xa9\x5c\x99\xef\x1c\x0f\x3b\x2c\x96\xc6\x1b\x01\xeb\xfa\x85\xa5\xa8\x7e\x13\x5f\xae\x5c\x48\x56\x96\xab\xfc\x4c\x8e\x14\x66\x81\x0a\x4f\x91\x34\x96\xff\xaa\xa7\xd1\xff\x7f\x23\x9f\x55\xb2\x71\x67\xc0\x1a\x41\xc1\xde\xa1\x10\x7c\xb1\x16\xc2\x37\x24\xa2\xe9\x6c\xd5\x4e\x22\x9b\xc1\xde\xac\x9b\x70\x8f\xf6\xcb\x15\x23\x74\x07\x7a\xfa\xc3\x15\xef\xde\x49\x7a\x6f\x26\xc6\x0a\x31\x05\x03\xaf\x38\x40\xc2\x2c\xaf\x31\x39\xd0\xad\x36\x96\x9c\x89\xbf\x02\x64\x3e\x61\xa9\xbc\x58\xca\xf5\x77\xef\x58\xf9\x2c\x99\x4f\xa2\xd9\x66\x35\x89\xe6\x8b\xc5\x24\x9a\xae\x6f\xe9\xca\x10\xb2\x68\xbb\x77\xcc\xa0\xd7\x05\x49\xe9\xa9\x2a\x32\x23\x03\xf3\x76\xcb\x5b\x5e\x93\x34\xef\x5e\x77\xd1\x0c\xa5\xd1\x2f\xc3\x98\x79\xf2\xd1\x71\xd4\x2e\xa4\x78\x13\xfa\x8f\x59\xce\x9e\xe0\xc8\x7e\x9a\x44\x7a\x41\x43\x49\x56\x95\xc5\xeb\x4f\x93\x48\xfa\x14\x03\xb0\x0e\xeb\x8e\x12\x88\x14\x91\xfe\xc6\x43\x1e\xc6\xaa\xe2\x6d\x12\xa9\x54\xcb\xaa\x8b\x49\x51\x54\x5f\xa9\xdc\x04\x95\xef\x24\xd9\x38\xfe\x29\x04\x9b\xc0\x49\x5d\x53\xd2\x90\x32\xd5\xd3\xfb\x22\x4b\x78\x89\xd1\xbb\x5b\x19\x7d\xce\x53\x1a\xd7\xf9\x0b\x2d\x62\xf6\xf8\xd1\x2e\xe1\x6b\x7a\x50\x5d\x46\x3a\xaa\x4f\xdb\x5d\x7e\x36\xbe\xf4\x30\xfd\xd7\xb8\xa8\x52\x52\xe8\x65\xe7\xaa\xec\x4e\x3f\xa9\x35\xa6\x66\x7c\x17\x4b\x99\x16\xec\xdd\x94\xab\x04\x3b\xe3\x10\xb7\x67\x93\x7a\xdf\xe5\x6e\x08\xce\x11\x33\x1d\x7e\x32\x1a\x93\x1e\x58\xce\x34\xa3\x68\x32\x22\xb0\xda\xb3\x2d\x13\xbc\xc8\xa8\x77\x00\x32\xa8\xf3\x3a\x55\x71\x84\x88\x2b\xc1\xc5\x55\x1c\xc7\xc4\xa5\x43\x38\xc4\x65\x93\x71\x8b\x4b\x87\x1d\x17\x57\x71\x74\x8a\xcb\x28\xc2\xc5\x55\x1c\xbd\xe2\x2a\x8e\x88\xb8\x96\x6b\x3d\xe9\x1c\x1b\x67\x8c\x7d\xe0\x72\x6a\x01\x29\x95\x84\x42\x78\x63\x93\x68\xca\x9c\x2f\x63\x03\x1d\xa6\xf7\xc2\x9e\xbf\xba\xea\xa5\x12\x59\x57\xc4\x96\x01\xaa\xc6\x61\x51\x00\x43\x76\x72\x81\xa2\xa7\x0a\x73\xbc\xfc\x92\x58\x0b\x02\xf1\xee\x8c\xe3\x01\x21\xc5\x09\xee\xb8\xab\x72\x99\x7f\x1c\x05\xeb\x75\x93\xb7\xc0\xf2\x60\x65\xdb\x10\x7c\xb0\x12\xc0\x1f\x87\x82\x42\x5d\xaa\xc5\x80\x9e\xb7\x6f\x8e\x48\xf5\x93\xd5\x97\x9f\x40\x97\x42\xaa\x31\xd2\xff\x82\x53\x93\xf1\x00\x6d\x70\xe5\x4e\xbf\xad\xc3\xf0\x07\xdf\x02\xba\x52\x70\xfc\x69\xa4\x45\x9f\xec\xf6\xb9\xf2\xb6\xcb\x63\xba\xe0\xbd\x3a\x6b\x16\xc4\xf5\xc7\x0f\x28\x54\x44\x9f\x7b\x14\xf6\x54\xe2\xe0\x8b\x26\x38\x2b\x5b\x34\x07\x5c\x9d\x38\x2f\x05\xdc\xf8\xa7\x6b\x53\x84\x80\x25\x4d\x7a\xe0\x3b\xe6\x20\x98\x1d\xd1\xf7\x38\x02\x66\xf5\x47\x00\x63\xaa\x66\xdd\x94\x58\x9f\x7d\x6c\x09\x18\x1f\x57\xc0\x34\x79\x98\x82\x4e\x4d\xcc\x4f\x1c\x59\xd6\xcc\x58\xb8\x69\xeb\x49\xf3\x20\xed\x06\x1f\x31\x9e\xea\xc0\xf4\xe2\x29\x16\x13\xad\x91\x92\x31\x41\x92\x8e\xcb\xaa\x34\x3c\x38\x35\x3f\x1a\xe7\xfd\xd0\x0c\xbe\x73\x74\x0d\xba\xc2\xf3\x23\x6b\x51\x07\x7f\xc5\x88\xa3\x80\x46\x2c\x80\x8f\xa2\x1c\x50\x94\x30\xcc\xf7\x35\xcc\x9c\x3d\x94\xdb\x61\xfd\x2d\xa4\x70\x2d\x2f\xc1\x82\xf1\x10\x06\xb2\xf2\x40\x89\xa5\xc5\x95\x02\x84\x83\xc3\xe4\x5d\x1b\x2c\xf3\xb7\xc9\x56\x57\x5f\xe1\x30\x41\x57\xe9\xd1\x7a\x72\x41\x7b\x92\x6b\x78\x3d\x0c\xa1\x2e\x8e\xe0\x23\xfd\xb7\xc6\xb5\xd8\x51\x3f\xe2\xbf\xf9\xb4\xb8\x1f\xdb\x86\x16\x1b\x84\x1d\x9d\x50\x1c\x3d\x9a\xf3\x1b\x0a\xe3\x5a\x96\x82\xe5\xe3\x21\x8c\x2b\xb3\x09\x15\xa6\xcc\x26\x16\xa6\xcc\x92\x77\x4d\x99\x1f\xee\x22\x62\xc9\xd1\x89\xb4\xf1\x81\xd2\xac\x5f\xd5\x3b\xbc\x33\x14\xd4\x16\xb8\x31\x0f\x2c\xe7\x53\xe0\x16\x6a\x2d\x75\xd4\x07\x9d\xd6\xc1\x79\x82\xd3\xca\xcf\x71\x5e\x66\xf4\x65\x17\xcd\xf1\xf5\x83\xbc\xfe\xb9\xd4\x1f\x42\x5d\x60\xd1\x4b\xf9\xd1\x7e\xfe\x8d\x49\x97\x3b\x85\x31\x7d\xa6\x65\xd7\xea\x07\x7a\xe5\x68\xf9\xe4\x69\x95\xbc\xb1\xba\xd6\x39\x19\x53\x46\x35\x9f\x04\xd0\x96\x96\x2e\xd4\x6a\xb3\xfe\x93\x2f\x74\x41\xdf\x1e\xfd\x3e\x78\xbb\x7a\xb1\x60\x48\xf9\x3a\x7a\xf1\x89\x16\x35\xf7\xdc\x4d\x44\xe6\xff\xa0\x1f\x81\x3b\x07\x4b\xed\xd5\x1d\x56\x28\xfd\x3c\x94\x1f\xe8\x74\x19\xf8\x9a\x93\x08\xbc\x32\xec\xd1\x39\x9d\x67\x4b\xef\x8d\x28\x28\x47\xfd\x6d\xc3\xd3\xa3\x8c\xba\x83\xb6\xfc\xc1\xbc\x37\x87\x69\xd7\xf5\x4b\xf4\xdd\x7a\xb3\x9f\xad\x1f\x6e\x8e\xc9\x02\x1a\x68\x83\x60\x10\x85\x64\x99\xb8\x4a\x66\xcb\xdd\x79\x7e\xf7\xd1\xd5\x5b\xa3\xf2\xd3\x07\xa0\x1b\x59\x3e\x1c\x67\x0e\x2f\xeb\xbb\x3e\xbc\x86\x62\x74\x78\xa9\x62\x6b\x78\xa9\x12\x38\xbc\xf4\x8f\xe6\xf0\x12\xa5\xf8\xf0\x32\x0b\xf1\xe1\x25\xa1\xec\xe1\xa5\x95\xb8\x87\x97\xf6\x5e\xa2\xce\xf3\xd8\xf0\xe2\xa8\x7f\xbf\xe1\x85\x32\xea\xdb\x13\x59\xcd\xee\x35\xbc\xd2\x84\xcc\xd6\xfb\xb7\x0d\x2f\x4e\x03\x6d\x90\x7f\x78\x0d\x72\x77\x9e\x40\x45\x86\x57\x60\x47\xe3\xc3\xcb\x46\xa6\x4d\x53\x35\xd6\xe0\x32\xbe\xea\x43\x4b\x16\xa2\x03\x4b\x14\x5a\xc3\x4a\x7c\x87\x83\x0a\x7e\x32\x87\x14\x2b\xc3\x07\x94\x5e\xa4\x0f\x27\x08\x01\x87\x92\x4e\x76\x64\x28\x69\xcf\x84\x42\x4e\xc7\x06\x12\x47\xfc\xfb\x0d\x24\x84\x4d\xf7\x30\xe2\xef\x9b\xde\x69\x18\xd1\x87\xe5\xc3\xe2\x8d\xc3\x88\xd1\x40\x9a\xe3\x1f\x44\x83\xcc\x9d\x47\x6d\x91\x41\x14\xd4\xc5\xf8\x10\xb2\x51\x15\x18\x57\xa5\xff\xed\x21\xc2\x2f\xa1\xae\x74\x07\x52\xc7\x97\x8f\xfc\x8f\xd3\x51\x31\xa0\x61\xb0\x39\x8e\x2a\xc0\xf0\xe9\xca\xb9\x07\x00\x8f\x1c\x6c\x16\xfd\xbf\xc0\xe4\xd6\x8c\x4f\x31\x9c\xcc\x7d\x0d\x77\x10\x1a\x8d\x37\x3b\x82\xcb\x72\x9f\xc9\xae\x09\x0e\x47\x4f\x5d\xc2\xc1\x97\x4f\xf3\xdc\x5a\x0d\x5c\x51\xe2\xb5\xa1\x24\x80\x0a\xe3\xa8\xec\x04\xdb\xb5\x8c\x41\xaa\xc6\x9a\xda\x03\x68\x0d\x27\xbe\xf5\x16\x86\xb0\xef\x4a\xed\x3c\x35\xcc\xa7\xe1\xa2\xf0\x84\x74\x14\x92\x84\x49\x43\xd7\xe6\x16\xfc\x58\xf4\xb5\xd2\x02\x33\x9c\xf6\x7d\xd8\x7f\x19\x57\xd5\x61\x09\x7d\x37\x76\xd4\xc4\x85\x30\x05\x5a\x6f\x45\x7f\x7d\x24\x1d\x3b\x66\x48\x0d\xd6\x06\x84\xda\x19\xc7\x77\x94\xd0\xc4\x15\x06\x1b\xee\x98\x86\x6e\xc3\x94\x11\x33\xf6\x44\xc1\x4b\xb2\x56\xa7\x61\x65\xd0\x75\xb0\x80\xa4\xbf\x81\x17\x60\x6f\x17\xc3\xb0\xff\xd8\x73\xc1\xc9\x4d\x8c\x83\x1d\x3f\xb8\x99\xba\x31\x42\x3b\x10\x05\xdf\x2c\x0e\x7e\x38\x2c\xc8\x80\x6b\xec\xdb\xe3\x0f\x93\x0f\x3e\x0a\xac\xb7\x50\xbd\x5d\x1c\xaa\x2e\xe0\x79\xaa\x5b\x5b\x65\x84\x0a\xc7\x1a\x39\x5b\x4e\x17\x8b\xd1\x17\xe7\x42\x6b\x6c\xcf\xe3\x35\x1a\x47\x04\xa4\xb5\x1d\xdb\xc7\xd5\xcf\x18\x3a\xb7\x71\xf5\x73\x87\xd8\xce\xae\xe7\x2c\x22\x1e\xd3\x43\xee\x68\xf8\x77\x88\xe3\x73\x1b\x77\xd5\x25\x3d\xc5\x24\xe5\xe6\xe5\x4c\xca\xbc\xbe\xf4\x26\xa6\x2a\x79\x98\xd2\x57\x6a\xec\x30\x43\xf7\xf5\xd2\xd2\x26\xe6\xa1\xe7\xe1\xfc\x23\x3b\x60\xe6\x28\x69\xf1\x02\xf4\xe3\x35\x27\x2c\xfd\xaf\x3e\x0e\x6f\x51\xf6\xfd\x2b\x6e\xa9\x4f\xc5\x39\x5b\xf0\x69\x07\x3f\x81\xdf\x3b\x0d\xa3\xd7\xba\xe1\x23\xc4\x01\x9e\xff\xaf\x7e\x3e\xd7\xe2\x11\xfe\x1e\x2e\x89\x19\xa7\xd3\x99\x4a\x65\x34\xad\xd8\x61\xaf\x52\x8f\x08\x0f\x82\xd0\x9a\x6d\x5e\x36\x33\x3a\x23\xfc\x94\xe4\xa2\x7e\x61\xcd\x36\x16\x25\x33\xcf\x73\xae\x1e\x14\xc8\x35\xd8\x89\xdf\x77\xe5\xd8\x11\x3d\x39\xc6\xb1\xe8\xf8\x23\xbe\xa9\xcd\x46\x6f\x5e\x74\xbd\xd6\x91\xa2\x3e\x91\x0f\xe2\x94\x60\xf4\x43\xb4\xd6\x0f\xd6\x86\x3c\x0c\xab\x1d\x33\x9c\xae\x57\xa0\x2d\x71\x46\x0f\xe4\x52\x74\x58\xef\x79\x4e\x23\xeb\x6b\x2d\x70\x09\x10\x90\xd4\x3a\x57\x7d\x04\x7a\x23\xbf\xed\x40\x92\x0e\xf8\x19\x03\xe5\x17\x17\xa3\x69\x55\xd3\xf2\x69\x9a\x35\x55\x9d\x55\x5f\xfb\xf9\xfb\x78\x2c\x28\x84\x54\x8f\x51\x8f\x35\x89\xae\xfb\x7f\xd8\x0a\x32\xeb\xff\x85\x36\x6c\xa7\x3e\x86\xb2\x86\xeb\x38\x56\x9f\xae\x6f\xd6\x67\x5c\xd0\xaa\x54\x33\x23\x56\xf1\xce\x8b\x8c\xf5\xc1\x50\x38\xdc\x22\x05\xc5\xda\xa9\x59\xf4\x3b\xca\x2f\x28\x46\x19\x1e\xca\x51\x8e\x41\xf1\x18\xba\x50\x21\xc7\x50\x95\x08\xa3\x00\x20\xb5\xcc\x18\xa4\x10\xe2\x08\xd8\x2e\x98\xe0\x2e\x90\x20\x6b\xa9\xe7\x9a\xf2\x15\x83\x39\x9a\xee\x49\x76\xa4\x9a\x99\xf0\x3e\xc0\x0d\x69\xd4\x4d\x7e\x26\xcd\x6b\x30\xf2\x86\xec\x37\x08\x67\x73\xba\xce\xc8\x12\x21\xac\x2b\x94\xfc\x08\x55\x57\x7c\x33\x2d\x8d\xfc\x8c\x81\x8e\x5b\x1a\x01\x69\x58\x1a\x77\xc3\xe6\x0f\xeb\x64\x9b\x60\x0d\x4b\x96\xd9\x26\xb8\x61\x21\x96\x46\x67\x6d\xdc\xd2\xc8\xfa\x0c\x4b\x63\x7e\xc6\x05\xed\xb0\x34\x66\xf1\xce\x8b\x8c\xf5\x81\xcb\xd2\x88\x62\xcb\xd2\x58\xdf\x51\x7e\x9d\x96\xc6\x2a\x47\x39\x76\x5a\x1a\xbb\x7c\xc4\xd2\x08\x84\x51\x80\x00\x4b\x63\xe8\xfc\x08\x58\x80\xa5\x31\x46\xc6\x18\xd8\x88\xa5\xb9\x7e\x48\x63\xf6\x06\x50\xf1\x66\xef\xeb\xc9\xc8\x0d\xc9\xb0\x91\xb9\x4a\xf7\x0f\xab\x14\xe1\x6f\x99\x12\xba\x4c\x11\xc2\xba\x66\xc9\x8f\x50\x87\x65\xd6\x20\xc3\xe4\xc8\xcf\x18\xe8\xb8\xc9\xd1\x73\x2e\x8d\x37\x6c\xb9\xdc\x66\xcb\x25\xb6\x85\xbb\x7d\x58\x2e\xb6\xa1\x0d\x0b\x31\x39\xce\x74\x50\x0e\x93\x23\xeb\x33\x4c\x8e\xf9\x19\x17\xb4\xc3\xe4\x98\xc5\x3b\x2f\x32\xd6\x07\x2e\x93\x23\x8a\x2d\x93\x63\x7d\x47\xf9\x75\x9a\x1c\xab\x1c\xe5\xd8\x69\x72\xec\xf2\x11\x93\xa3\xd2\x62\x8d\x00\x04\x98\x1c\x43\xe7\x47\xc0\x02\x4c\x8e\x31\x32\xc6\xc0\x46\x4c\xce\xf5\x43\x1a\x33\x39\x80\xca\xa8\xc9\xc9\xcb\x43\x15\x6a\x6f\xf6\x69\x82\xee\x5a\x2d\xd7\xfb\x87\x8c\x98\x54\x75\x9d\x62\x5f\xa0\xea\xb2\x3c\x53\x16\x88\xa1\x2a\x20\x67\x95\x6f\x14\x5f\xd1\x88\xc5\x6c\x9f\x64\x2b\xcc\xa8\xaf\xb7\x64\x9f\x8e\x37\x22\xc4\xaa\x28\x7e\xc6\x0d\x0a\xab\xc4\xb0\x26\xda\x37\x44\x8c\x0e\x3b\xa2\x95\xd9\xa2\xc5\x2d\x88\x5e\xa2\x9b\x8f\xbe\xcc\xb2\x1d\xfa\x47\x9b\x3b\xa7\xd5\xd0\x0b\x6d\xfe\x2c\x7b\x81\x16\x29\x0e\x5d\x23\x8d\x67\x41\xf3\x95\x06\x98\x09\xa8\xad\x3e\x98\x00\x03\x01\xb4\xda\x4f\x6a\xcc\x34\x5c\x37\xfa\x50\xbb\x30\x90\x18\xb5\x0b\xf2\xf0\x46\xd8\xa8\x3a\x24\x24\x5b\x62\xcc\x51\x4a\xe6\x8b\x35\x42\x58\x57\x1c\xf9\x11\x76\xbc\xcc\x11\x66\xb8\x22\xf2\x33\x06\x3a\x6e\x29\xf4\x0c\x6b\xe3\x0d\xa3\xe9\x76\x33\xc3\x16\x9c\xd9\xea\x61\x35\x9b\x87\x36\x2c\xc4\x68\x38\x93\xbf\x39\x2c\x87\xac\xcf\x30\x1e\xe6\x67\x5c\xd0\x0e\x13\x62\x16\xef\xbc\xc8\x58\x1f\xb8\x6c\x89\x28\xb6\xcc\x89\xf5\x1d\xe5\xd7\x69\x54\xac\x72\x94\x63\xa7\x2b\x62\x97\x8f\xb8\x22\x2a\x09\xde\x08\x40\x80\x8d\x31\x74\x7e\x04\x2c\xc0\xd2\x18\x23\x63\x0c\x6c\x2c\xce\x72\xf5\x90\x46\xa3\x2d\x03\x95\x51\x93\xc3\x93\xb7\x05\x5a\x9c\x6c\xbb\x5a\x2c\xd1\x81\xb9\x5c\x1c\x16\xc4\xa6\x6b\xc4\xef\xf8\x37\x2d\x50\xc8\x73\xc7\x21\x60\x66\x70\x0e\x66\xa3\xf3\x46\x4e\xaf\x69\x50\xba\x5d\x24\x73\xcc\xf5\x23\xe9\x7c\x3b\x5f\x85\x35\x28\x28\x9e\xeb\xc8\x03\xe8\x0a\xe7\xf2\xca\xcc\x68\xae\xfe\x15\x15\xae\x2b\x96\xab\x97\x62\x02\x77\x44\x72\x8d\x32\x23\x90\xcb\x4a\xed\x38\xae\xf1\x19\xe3\xd4\x1d\xc5\x35\x8a\x31\x5e\x1d\x6e\x8b\x55\x38\xea\xb8\xc8\x2c\x88\xfe\xf2\x90\x00\xae\xa6\xdb\x7e\xa8\x90\xf0\x2d\x1c\x03\x63\xe4\x46\x8c\xca\xd5\xa3\x16\xb3\x29\x80\xc8\xa8\x4d\x29\xf2\x92\x6f\xd3\xa3\x37\xbc\x5d\x81\x1e\xb9\x27\x9a\x98\xa4\x44\xe7\xf6\x3f\x75\x45\xea\xbf\xec\xac\x2f\x40\x1b\x3d\x02\x56\x3c\x7a\x9f\x56\xb9\x76\xfb\xcc\xc3\xba\xcd\xa8\xa6\xba\xec\x03\x48\xa1\xa9\xf5\x94\xfd\xd8\x4b\x10\x11\xb5\xca\x5a\xac\xe6\x9b\x14\xdd\x65\xbd\x94\x19\x6d\x8a\xdc\xda\xd7\x1e\xaf\xd8\x31\x04\x8d\xa2\x91\x99\x1d\xb4\x60\xa4\xaf\x90\x66\xc1\x17\x6b\x3c\x3b\xc7\xea\x90\xc7\x53\xff\x97\x64\xf3\x08\xcf\xf9\xfc\x2a\xf7\xe8\x40\xdd\xed\x19\xd6\xad\xdf\xeb\xbd\xef\x4d\x54\x50\xe9\x4b\x0b\x2b\x7d\x69\x8d\x06\xf3\xfd\xeb\xbb\xd5\xe9\x3b\x71\x6a\x27\x2b\x1b\x50\x3e\x19\xd8\xc6\xe9\x54\x3b\xc7\xcc\xfe\xd2\x75\x55\xf9\xd3\x80\xa6\xdf\xab\xa7\x2d\xed\x5c\x85\xed\x65\x7f\xce\x61\xa9\xb0\x99\x08\x7f\x07\x92\x71\xfb\xa7\x36\xc3\xb5\x43\x04\x30\xfd\x93\xdc\x6f\x9f\xce\x56\x6d\xd4\x0b\x8e\x67\x7d\x35\x32\x4e\x39\xa0\x46\x40\x20\x3b\xd3\xbc\xd4\x39\x52\x59\x80\xd2\xaa\x28\x48\xdd\x52\x5d\xfc\x70\x18\x48\x08\x49\x03\xcd\x3d\xd7\x35\x6e\x38\x91\x67\xb1\xfa\x2a\x61\xf7\x55\xf6\x1a\x00\xce\x75\xd1\x60\x43\x2e\x71\xf1\x63\x85\x52\xed\x98\xc0\x65\x9e\x5d\x98\x80\xd7\xee\x84\xb8\xcb\xcf\x79\x79\x8c\x0f\x97\x52\x1c\x15\xa2\xa4\xa5\x56\x2f\xb8\xc1\x82\x48\xd9\xd5\x66\x17\x69\x73\xa6\x0b\x24\xcf\x18\x52\xee\x47\xb6\x6b\xa8\x9b\xaa\xa6\x4d\xdf\xdb\x5c\x2c\x93\xe8\x39\x6f\xf3\x7d\x5e\xe4\xdd\xab\x5d\xdf\x18\x74\x20\xa8\xea\x2e\xd2\xd0\xce\x7f\xe8\x0c\xa6\xc5\xd4\x3a\x4e\x7f\x6c\x8d\x5b\x15\xf7\x49\x30\xf8\x2c\xd3\xb2\x7e\x89\x32\xd2\x9e\xf8\xd9\x16\x3d\x5d\xe9\x72\xe4\x5c\x95\x78\x47\x0e\x83\x92\x8d\x92\xde\xf9\x24\x62\x3f\xc5\x21\x4a\xf7\xad\x5c\xc3\x9b\xc7\x4e\x52\x25\x16\xec\x99\x96\x97\xb1\xdb\xb7\x32\x57\xa0\x38\x3e\xfb\x08\xef\xdf\xce\x12\xee\x2c\x69\x83\xf9\x71\x78\xff\xa6\xc7\x79\xd4\x33\x93\xce\xd6\x58\x86\x03\x2d\x43\xe9\x7c\xc8\x60\x89\x9c\x01\x34\xdf\x76\xe3\xf3\x40\xdb\xc9\x14\xd7\xc8\xe9\x37\x63\x81\xa5\x3c\x25\x00\x51\xe4\xf5\x2e\x1a\x32\x66\xbc\x98\x14\xd0\xf2\x91\x3c\x85\xb0\xc4\x3c\x7f\x25\x4f\x6c\x85\xe6\x33\x4c\xd4\x71\x49\x8b\x14\x72\x07\xc7\x0f\x8d\xaa\xc1\x94\xbd\x4c\xca\xf4\x17\x1e\x5d\x4d\x86\xae\x87\x17\xd8\x75\x0d\x9a\x66\xf9\x73\x2e\x53\xd0\xa9\xe9\x18\x9e\xec\xdc\x45\x5b\xd9\xcb\x98\xa9\xc4\x82\x6b\x30\xbf\xab\x5e\xdf\x53\x91\x3f\x11\x7f\x62\x4d\x36\xef\xab\x24\x41\x69\x41\x49\xc3\x1e\xac\x3b\xdd\x70\x8a\xd4\x38\x70\x85\xa6\xf8\x76\x71\xa9\x7c\x4e\xa4\x08\x71\x80\xd7\xfd\x3f\xa7\xb3\xe8\xd2\x6a\xed\xdd\x23\xbd\x22\xf9\xda\x12\xb1\x58\x50\x25\x0e\x16\x87\x72\xb8\x6c\x33\x46\xd2\x35\x6c\x0e\x0b\xa9\x11\x83\xf4\xa4\x56\xf1\x18\xdb\x43\x19\x88\xbc\xb8\x61\x50\x77\x7c\xb4\x5a\x97\x4c\x50\xc2\x4e\x21\x38\x8e\x41\x8e\xae\xe4\xdc\x47\x45\xe5\x09\xca\xba\xa9\x8e\x79\xb6\xfb\x2f\xff\xf3\x8f\x7d\xf9\x9f\x7b\xf4\x43\xd5\x9c\xa7\x7f\xca\xd3\xa6\x6a\xab\x43\x37\x3d\xf6\x36\x85\x96\xdd\x07\x5a\x32\x8e\x7f\x38\x90\xa2\xa5\x6a\xe8\x1b\x11\x20\x35\x0f\xa0\x0e\x17\x87\x26\x21\x93\xc9\x6d\x06\x84\xcd\x87\x10\x49\x5e\x79\x32\xf2\x06\x29\xa4\x13\x25\xd2\xdc\x04\x9a\x80\xf1\xc5\x03\x36\xe4\xc5\xd2\x2d\x64\xc8\xf7\x9d\xd6\xff\x61\x4c\xa7\x87\xfc\x85\xf7\x3a\x9e\xc9\x42\x3b\xf0\x8e\xcd\xb0\xdb\xad\x6a\xfd\x60\xa0\xb1\x9e\x1b\x17\xf7\xa5\x8e\xb8\xab\x34\x89\xa6\x25\x79\xde\x93\x26\x66\xdc\x89\x53\xf7\x83\xb2\x47\xc0\xa3\x4a\xab\xb2\xa3\x65\xb7\x8b\xde\xbf\x37\x1d\x20\x2c\x41\xb7\x72\x69\xcc\x8a\x35\x86\xc7\x19\xb0\xdb\xc7\xaa\x94\x7a\x31\xdc\x00\xc4\xdf\x6a\x0d\xbe\x6e\x21\xd8\xe0\x5a\x8b\xd4\xaa\x89\x15\x79\x8f\xd9\x83\x3f\x28\xb5\xa9\xd5\xef\xec\x27\x74\x87\xf5\xb0\x58\x07\xf3\xb5\xb1\xf4\x44\x6f\xc9\x97\xe7\xba\xd7\x65\xae\xbf\x25\x1c\x5c\x85\x8b\x3b\x70\xc3\x39\x6f\xac\x66\xe0\xe3\x8d\x50\xd5\xc3\x61\x08\x80\xb9\x8f\x87\x81\xc0\xe8\x0d\x56\xae\x47\x7c\x87\x16\x20\x95\x6b\x75\x5a\xdf\xf5\x30\x2f\x28\x18\x4c\xfe\x90\x80\xc6\x6a\x39\x23\xf7\xc9\x94\xe5\xf0\xd5\xee\x65\xf0\x93\xe3\x69\x55\x9b\xa5\xf6\x8d\x2a\x79\x75\x4a\x0f\x74\x74\x55\x55\xec\x49\x83\x00\xae\x70\x40\x8b\x39\x55\x60\xde\x04\x75\x74\xbc\x80\x87\x7a\x04\x3f\x61\xb4\x9f\x2c\xda\xfa\xab\xdc\x48\xbc\x88\x77\x45\x59\x75\xd1\x07\xed\xe1\x8e\x8f\xe2\x1b\x78\x47\x42\x7c\x32\x97\x46\xdf\x7e\xf3\xee\xe3\x2f\x23\xf1\x5c\xa8\x0e\xc6\xeb\x20\xe6\x6d\xc2\x31\xa4\x60\xbe\x22\xc8\x55\x57\xd5\xdc\xaa\x0c\xfc\x59\xe6\xd6\x04\x70\xf0\x32\xd4\x8c\x89\x4d\xd7\x7f\x73\x15\x59\x56\xdd\xb7\xdf\xbc\x33\x50\x0c\x36\x7b\x49\xf8\xb8\xd4\xcb\x71\x26\xc7\xb5\xcb\x84\x0d\x54\x81\xc1\x88\x85\x75\xb7\x20\xee\xef\x3f\x53\xae\x88\xb1\x08\xa4\x63\xaa\xc0\xaf\xa2\x01\x82\x17\xbf\x1e\xe0\xca\x7e\xbf\x6e\x8e\x2c\xdd\xb2\xed\x2f\x73\x34\x2d\x40\x87\xdf\xa9\xb7\xf1\x13\x8a\x65\xe4\x22\x7b\xc0\x52\xff\x3e\xb8\x8c\x0c\x4b\xed\x15\x40\x75\x36\xc7\xc8\xce\xe6\x08\x5d\x4f\x03\xff\x2e\xf7\xbe\x7c\x5c\xe9\xdb\x4f\x37\xee\x2e\x41\x57\xd2\x6d\x38\xd9\xc5\x56\x05\x27\xd4\x4a\xc4\x8b\x56\xa2\x21\x88\xc6\xc9\xa0\x9e\xe9\x6b\x8e\x91\x4c\x24\xd1\x2b\x9c\x21\xbd\x44\xcc\x65\x1e\x77\xc5\x74\xa1\xec\x65\x0a\x78\x22\xfa\xd1\x7e\x99\xc3\x78\xae\x66\x84\x53\xb3\x36\xe4\xf9\x69\x07\xa6\xe5\xa9\x20\xc5\xa1\xad\x1d\xa1\x65\x39\x31\x22\xa6\xa0\xa5\x90\x9e\x21\xb7\xc2\xed\x21\x6f\xb8\x7e\x61\x53\x41\xd0\x24\x60\x3a\x9d\x5e\xfb\xed\xb5\xd6\x22\x98\xe7\xb5\xd7\x57\x5b\x51\x83\x3d\xbf\x49\x0f\x35\xe0\x41\x33\x8d\x86\xbd\x1c\x1d\x3b\xd7\x4f\xd2\xf2\x60\xc0\x75\x3d\x74\x87\xf9\xfa\x26\x82\xb6\x4f\xf9\xcb\xaf\xdc\xd9\xb7\xcd\xe2\x3a\x63\xd7\xaa\x81\xcd\xd2\x5f\x2f\x6d\x97\x1f\x72\x9a\x21\x1b\x69\x88\x19\xe3\x1b\x6c\x05\x79\xad\x2e\x1d\x08\x86\x0c\xc7\x06\xd8\xbe\xdc\x2e\x6a\x69\x4d\x1a\xd2\x21\xd6\x4a\x55\x68\x9b\x64\xbd\x08\xb8\x90\xe3\x8f\xf2\x43\x56\x11\xe3\x8a\x52\x56\xd6\xd5\x6b\x97\x71\x54\x3b\xb2\x60\xc5\x68\x7e\xcc\x48\x47\x84\x3a\x89\xdd\xe3\xf6\x27\x6e\xd2\xf1\xdc\x28\x61\x08\x43\x56\x78\x37\x3c\x9c\x3e\xae\xad\xcb\x81\xab\x32\xb3\xb8\x77\x97\xf8\x9e\x4a\x43\xd3\x6e\x70\x50\x12\xe6\xd0\x8c\x67\x5d\x1d\xfa\x7a\x24\x2a\xa2\x14\x73\x54\xe5\x00\xe1\x1f\xd3\x82\xb4\xed\xef\x7f\x48\xab\x22\xfe\xc9\x9c\x50\x1f\x6f\xc9\x75\x7e\xb4\x13\x1e\x79\xb8\xd7\xf3\xdb\x1a\x7b\x69\xfe\x47\xec\xb0\x7a\xd9\x99\x12\x23\xd7\x92\x59\x8c\x66\x58\xf2\x42\xed\xbb\x72\x70\x38\xfe\x6e\x59\xb0\x5d\x0d\x74\x00\xa1\xcd\x0c\x80\xf5\x36\xf6\xca\x94\xdb\x7e\x96\x3d\xe0\x1e\xe6\x03\xb1\x64\x33\xac\x9c\xdf\x0e\x9e\xc4\xee\x06\x0a\x68\x73\xe3\x26\x8a\xf1\xe0\x49\x8f\xad\xbf\x2a\xe4\xd5\xdd\xbe\x78\x5c\x77\x4d\x28\xb4\x3b\x7f\xbb\x07\x08\x5c\x2d\x73\x00\x85\x2a\xed\x55\xad\xbc\xf2\xb5\x03\x3f\xcb\x1e\xf0\xeb\x95\xd6\xd5\x0c\x87\x7e\x59\x3c\xb9\x94\x16\xe7\xc6\x4d\xf4\x76\xa5\xb5\x32\xdb\x21\xd5\xa2\x29\xea\x10\xc7\x65\x94\x7c\xa0\x8f\x6d\x8d\x09\xc6\xc7\xad\xc8\xf7\x59\x75\x85\x8a\x45\x79\x6a\x8e\xcd\xb8\xf1\xed\x0e\x3c\x1f\x67\xe8\x73\x97\xe3\x07\x06\x1e\xed\x97\x2f\xf1\xe4\x53\xee\x57\xf3\xae\x79\xf5\xd2\xd9\x2c\xf4\x49\x96\x51\x4b\xe6\x3e\x32\xe9\xaa\xe0\xda\x73\xa9\xee\xd3\xa7\x76\xcf\x38\x32\x01\x7a\x01\x35\x77\x53\xcb\x80\x37\x3e\x7e\xe0\xe3\xe1\x48\x35\xe6\xe3\xe2\xd6\x38\x00\xe5\x72\x8d\x32\x06\x02\x9c\xe6\x71\x92\xc6\x52\x13\x21\x0f\xde\x8c\xd6\xd7\xde\x2c\x76\x6f\xad\x84\xc7\x29\x58\xe3\xf8\xdb\x6f\xde\xfd\xda\xbb\x16\x5e\xc1\x6b\x11\x7c\xf5\x24\xf8\x58\xcf\x82\x15\x3f\xd6\xb1\x46\x40\x20\xac\xd3\x9c\xab\xee\x20\x1a\x8e\x1d\x98\x91\xee\x40\x49\xa3\x9d\x1e\xd2\xbf\xde\xd0\xc5\xed\x91\x7e\x9f\x7c\x61\xf7\xb9\xd7\x47\xf1\xc8\x7e\xf3\x60\x56\x92\x91\x53\x19\x4e\x2f\xc8\x7d\x7e\x12\x43\xf9\xa4\xf0\x9c\x5b\xad\x18\xda\xb0\xb3\x81\x96\x0e\xfb\xcb\x68\xb1\x6f\x97\xf9\x6e\xa6\x47\xb7\x94\x2a\x27\xa7\xb3\x5d\x96\x46\x06\x1a\x21\xbd\x1e\x5b\x7c\x25\x79\xd6\xb6\x54\xc0\x11\x18\x2c\x25\xa4\x79\xce\x13\x90\x79\x2a\xf2\x90\x78\x80\x76\xae\x89\xa3\x89\x93\x4d\xa1\x8f\x53\x1a\x73\xde\x4a\x6b\x8c\x7e\xe8\x4f\x7d\x08\x38\x2c\x86\x3b\x06\x3a\x69\x70\xfe\xcc\x75\xa4\xcd\x02\x34\x98\x19\x3d\x1b\xe7\x3d\xd6\x77\xcb\x89\x36\xd8\xd5\xe2\x24\x19\xe7\x46\xfe\x05\x39\x54\xdf\xc0\x15\xa3\x11\x8f\xc9\x38\x60\xa8\x55\x57\x92\xe7\xf8\x57\x3f\x9b\x2a\x7b\xf9\x29\x3f\x1f\x85\xb1\x50\x7b\x37\x86\x92\xc6\x1d\xd9\x6b\x89\xed\xd5\x41\xa6\xc1\xe9\xcb\xb2\xcc\xc4\x90\xba\x6d\x9e\xaa\xd6\x47\x88\x31\xae\x24\xa6\xd0\x15\x7d\xa8\x8f\x1f\x81\xbb\x21\x45\x28\xfb\xff\xc9\x60\xda\x35\x26\x9c\x97\xc6\xfa\xde\x14\xff\xc1\x9b\x0e\xcf\xb0\x62\x9f\xa1\xfe\xd8\x85\xd8\xe9\x55\xe1\xa1\x4b\x6d\x16\x09\xe1\x5c\xc7\x6b\x61\x4e\x39\xb3\xa7\xec\xc9\xd1\x3b\x00\x18\x7b\xec\x87\x1e\x47\x37\x62\x7a\x86\x72\x58\x02\xd5\x29\x18\xda\x81\xa9\x9c\x85\xa0\x2b\x85\xac\x68\xe5\x7a\x0a\x6b\x84\x5e\xf8\xc1\x3d\x2b\xea\x1d\x70\x40\xcf\xd3\x64\x57\xa4\x1f\xc6\xf6\xd5\x41\x3d\xaf\x24\x90\x38\xea\x70\x38\x2f\x50\x8c\xfa\xc1\x4e\xd7\x9a\xcd\x25\x43\x44\xcb\x5d\x20\xc0\x85\x18\x05\x35\x87\x9d\xc3\xd6\xdc\xdc\x0f\x52\x7e\x5e\x83\xf6\x08\x20\x50\x83\xe1\xed\xa4\xdb\x44\x73\x95\x6c\xf0\x41\xcc\x2f\x0c\xeb\x7a\x50\xe7\x45\x81\x19\x64\x0c\x46\xc8\xc6\xaf\x0b\x12\xf8\x93\xa0\x69\xde\x48\xc2\x60\x4d\x89\x58\xdf\x35\x9b\x68\x97\x7a\x8e\xf4\x3b\x4f\xee\x43\x3e\xda\x8e\xa4\x5f\x46\x2d\xcf\x00\x65\xb4\x8d\xbf\x28\xe2\xdb\xe9\xf7\x9a\x48\x14\x68\x84\x97\x3b\x19\xbf\xdf\xcc\xe6\xbd\xd1\xd4\xdd\x6a\xe1\x0c\xa1\x8f\x4d\x44\x77\x33\x86\x23\xa3\x3d\xd0\x08\xfe\x16\x06\xf0\x57\x37\x7e\x6f\x12\x45\xb0\x2c\xc2\x0c\x5e\x47\xf6\xb1\xb8\x01\xf0\xc4\xfe\xa8\x49\xe9\xb9\xbe\xab\x81\x83\xdc\xe7\xce\xd5\x17\xf7\x87\x91\x01\x84\x9d\x09\x7a\xe3\x19\x06\x7e\x54\xdf\xb3\xd4\x83\x0f\x5b\xac\xf0\xe7\xe5\xe5\x6d\x12\xaf\x73\x7c\xd5\xd5\x03\xad\x33\xb4\x01\x12\xfc\x80\x83\xb8\x83\x00\xee\xc4\xe8\xf3\x92\x36\xca\x7b\x48\xed\x1e\xb6\x79\x98\x71\x85\x1e\x66\x14\x5f\xe5\xfa\x28\x7e\xd9\xf1\x7b\xb8\x85\x76\xe5\x58\x15\xb7\x69\x53\x15\x05\x5b\x25\xb3\xa7\x11\xcc\xab\x23\xce\x45\xc5\xd8\xb3\x5e\x09\x3f\xd0\x38\x5f\xad\x26\xd1\xf0\x9f\xe9\xcc\xfb\x0a\x99\x13\xc9\x21\x17\x75\x83\x5d\x36\xe7\xf5\x5a\xf3\x6d\x49\xd9\x7a\xcb\xc9\xba\x48\xe3\x3d\x61\x89\x1c\xb1\xd4\xee\x9f\x28\xce\xf5\x4a\xf5\x71\x17\xfd\x53\x7e\xae\xab\xa6\x23\x5c\xd4\xda\x26\x96\x59\x66\xbe\x1d\xcf\x59\x1c\x96\xc7\xa2\xf3\x01\x9a\x8b\x23\x21\x4b\x4d\x98\x02\xdb\x40\xd1\xef\x02\x19\x74\xcc\x2b\x43\x5d\x55\xdb\x30\xd2\x00\xf6\x1f\xf9\xa3\x57\x28\x1c\x67\x08\x3b\xc3\x81\x3f\x59\xa4\x29\xc9\x9b\xb9\x54\x21\xb1\x17\xf0\x06\x71\x82\xdc\x58\x22\x2f\x71\x46\x9f\xf3\x94\x4a\x25\x5b\x3e\x24\xf5\xcb\x47\x52\x66\xd1\x87\xaa\xc9\x69\xd9\xf1\xe8\x4c\x41\xca\xac\x4d\x49\x4d\x75\xfd\xbb\x07\xa3\xef\x84\xe3\x30\xb0\x3a\x4f\x12\xfd\xbd\x97\xde\xde\x93\xbc\xa4\x4d\x7c\x28\x2e\x79\xf6\x84\xd4\xe4\x02\xe1\x16\x8b\xcd\xe0\x0a\xc4\x8b\xff\x84\xd8\xba\x7b\x3f\x2b\x74\x97\xf6\xbc\xa5\x41\x98\x03\x85\x3e\x61\xa5\xa9\x25\x50\xf7\x5f\xb0\x1b\xfa\xe6\x09\x68\x66\x19\xaf\x33\x68\x46\x15\xc8\xae\xae\x77\xb0\x60\x2a\xf7\x0b\x7e\x57\xd2\xbe\xcb\x68\xa6\x1d\x58\x24\xd7\xf1\x1e\xc2\x48\x78\x83\x24\x86\x75\x0d\x12\x15\x2f\x3a\x20\x7f\x31\x2f\x7f\x62\xe1\x6e\x9d\xea\xcc\x8a\xae\xf5\x54\xf7\x4d\x6f\x10\x90\xe8\xa0\xe9\xca\x0c\x71\xeb\x95\x88\x5b\x87\x1c\xc9\x9a\x27\x56\x3b\x58\x8d\x70\x81\x39\x7c\x1c\x89\x73\x63\x84\x54\xd4\x14\x75\x12\xc3\xba\xf7\x69\x18\x51\x3a\x43\x8a\xbf\x27\x73\xd0\xea\x70\xc0\xd4\xd9\x66\xc3\x52\x02\x78\x15\xc4\x77\x33\x92\xa9\xb1\x26\xfa\x2d\xd8\x87\x87\x2e\xee\x83\xf6\xc9\x70\xc5\x0c\xcd\x90\x3b\xea\xb7\xdf\x22\x7f\xc3\xeb\x4f\x9a\x04\xbc\x39\x46\x74\x59\x4d\xf3\xb4\x2a\x63\xe9\xef\x3a\x53\x2f\xcd\xe7\xfa\x5b\xf6\xf8\xf9\x04\x7b\x68\x99\xb5\x7c\xd2\xeb\x83\xa2\x5e\x5e\x6b\xf6\x40\x6f\x9b\xab\x1e\x4b\x33\xe4\x76\x96\xdc\x58\xd8\x4c\xfb\xb1\x16\x1b\x9b\x44\x02\x12\x6c\x3d\x69\x2f\xb8\xe9\xe3\xd5\x7a\xed\xd4\x35\x3c\x35\xc7\x41\x35\x67\x63\x36\x47\x6d\xb2\xa0\xd7\x9d\x07\x7d\xe6\xd6\xfe\x11\xac\x26\x94\x33\x6a\xfa\xb2\xf6\x43\x93\xa3\xca\xa9\x74\xf0\xed\xbe\xaf\xb3\x41\x66\xba\x80\xc1\x58\xb9\x50\x58\x8f\x0c\xaf\x49\x6a\xa7\x67\xe4\x3d\xa4\xb9\xb2\x09\xa3\x1c\x80\x00\x01\xd2\x69\xe1\x24\x4c\x5b\xeb\x07\x96\xb1\x3d\xde\x08\x57\x0e\xcf\x6b\x57\x97\x52\xb3\xcd\x59\x46\xa9\x7a\x62\xb7\x48\x85\xae\xac\xe5\xe8\x3b\x74\x18\x18\xe3\x40\x98\x3f\x7b\x20\xe0\x56\xf9\x50\x35\x67\xec\x50\xd2\x2a\xd0\xdc\x9a\xae\xa3\x61\x6f\xed\x99\x21\x78\x51\xeb\x8c\x0e\xdd\x6b\xf1\x3b\x91\x00\x2c\xd9\xc0\x1d\x17\xc8\x21\x84\xaf\x74\xc4\xfa\x5e\xfa\x75\xdf\x5b\xb6\x6b\xfa\x55\xde\x5b\x76\x56\x13\xfe\xde\xb2\x46\xe2\x6e\xef\x2d\x3b\xa9\x9a\xa7\x52\xdd\x80\x8e\xf7\x96\xc3\x10\x7c\xef\x2d\xbb\x28\x04\xbe\xb7\xac\xa1\xdf\xe7\xbd\x65\x9d\xe4\xf0\x02\xae\xf6\xfd\xb7\x7b\x6f\x19\x65\x47\xbd\xb7\x8c\x30\x35\xfe\xde\x32\x4e\xd2\x71\xca\x12\xa9\xe1\x4e\xef\x2d\x6b\x94\x6f\x7f\x6f\x39\xd0\xcd\xc1\xed\x8c\xbd\xe5\xe3\x1e\xcd\xe6\x75\xbb\xd1\x4d\x94\x6b\x2c\x20\x1a\x13\xd4\xa6\xbf\xc4\x13\x87\x1b\x8f\x10\xdc\xc7\xc7\xc2\x3c\xd6\x91\x60\xbd\x19\x8c\xbf\x3d\x52\x8f\x07\xb0\x46\xb9\xc0\x16\xd0\x16\x23\x4b\x6b\x47\xe1\xd7\xbb\xbb\x2b\xd7\x99\xfa\x49\x42\xc4\x0f\x01\x0e\x87\x8d\x3b\x05\x19\x79\x21\x89\x19\xbe\x51\x31\x43\x96\xed\x82\x88\xc8\xb0\xab\x11\x59\xe2\x44\x90\x85\x1f\x7d\xe9\x6c\x74\xdc\x71\xba\x22\xe8\x66\x52\x77\x78\x99\xe6\xca\x58\x57\x7a\xc3\x2f\x0c\xac\x73\xc8\xd2\x04\xea\x74\xc7\xb5\x87\xfc\x66\xda\x2a\xdf\x8c\x9f\x23\xae\x25\x4a\xe8\x7f\x23\x74\x8d\xd1\x8d\x0c\x45\xf8\xc2\x2d\x76\x62\xe9\xa1\xff\x87\x9c\x90\xa3\x9b\xfe\x9f\x83\x98\x1d\x50\xc2\x8f\x17\x3a\x71\xcc\x65\x0a\x0e\x84\x9e\xc7\x62\x07\xea\xae\x39\x49\x88\xd1\x57\xda\x13\xce\xb7\xb6\xfc\xb8\x1e\x6d\xac\xc5\xfa\xf9\xcf\xd0\xf7\x7b\xc3\x5b\xdc\xd3\x37\xf6\x88\x47\xc1\xf4\x6d\xf3\x71\x70\xfb\x90\xa8\x38\x3d\x87\x9d\x8b\x0c\xd1\x2f\x46\x5e\xcb\xf0\x18\x06\x18\xc8\xb8\xf7\x7c\xab\xbc\x50\xf3\x16\x2d\xb3\x12\xf5\xa8\xa7\x07\xb4\xd3\x8b\x6e\xdc\x31\xad\x11\x50\x63\xaf\x25\x04\xd6\x66\x84\xde\x10\x4a\x0f\x0f\x0f\x23\x94\xec\x5d\x23\x13\x42\x39\x35\xb7\x58\x1c\xd6\x6f\xf0\x64\xf0\x08\x50\xa0\x26\x58\x27\x89\xaf\x54\xe0\x40\x4f\x13\xa9\x7b\x2c\x1a\xa4\x59\x1a\x6d\x56\xb8\x8a\x98\x71\xec\xe3\x7a\x7c\x70\x1c\xc4\xb0\x4a\x63\x43\xe4\x36\xa6\x07\x5b\x75\x13\xcf\xae\xf3\x2e\x37\x12\x41\x5a\x2f\x34\xc3\xa7\x1a\x37\xb6\x1c\x18\xbc\xdb\xd8\xc6\x0c\xe1\xdb\xc8\x20\xed\x17\xf6\x31\xa4\xf7\xbd\x23\x5a\xa5\x8d\x0a\x9f\x53\x1d\x8f\x67\x80\x77\xb7\x4d\x44\x2d\x3f\x55\x40\x45\xd6\x53\x24\x4e\x80\x9b\xd8\x40\x1e\x1a\x09\x00\xf5\xbe\xfc\x33\xd6\x82\xab\x70\x30\x1f\x04\xbc\x8c\x2e\xf0\xf2\xf2\x99\x36\xe2\x88\x04\xf6\xe0\xf7\x7c\x8e\xf8\x95\xc9\x43\xff\xcf\x41\xc9\xed\x57\x6e\xb3\xfe\x5f\x08\x9a\x29\x51\x1c\xe8\xaa\x53\xad\xee\x19\xdf\x24\x6e\xf9\x95\x41\x7c\xa3\xae\xe5\x55\x98\x63\x8d\xf6\x7a\x97\x77\x68\xb7\xc3\xbb\xf4\x82\xd9\x53\xb3\x1f\xdc\x1e\x69\xee\x63\xc8\x41\x5a\xe6\xf4\x2e\x47\x00\x03\x19\xf7\x7a\x97\x4b\xf1\x2e\xf5\x5b\x74\xcd\xe9\x5d\xda\x16\x08\xc7\x1d\xd3\x9a\x30\xef\x32\xb4\xb6\x71\xef\x12\xbc\xb9\xe5\xa0\x64\x7b\x97\x26\x84\xcb\xbb\x9c\x25\xfd\xbf\x10\x8d\x30\xbd\x4b\x0f\x50\xa0\x26\x38\xbd\xcb\x40\x05\x0e\xf4\x2e\x91\xba\x5d\x33\x3b\x92\x1c\xdd\x65\xa8\x35\x27\x26\xb4\x0a\xfd\x99\x07\x5f\x03\x6f\x22\x8f\xf8\xc7\xd2\x5c\xde\x4e\x0f\xf1\x95\xae\xc3\x47\x9c\x24\xd1\xc1\x57\xb9\xc8\xe1\xdd\x88\xba\xc8\xd7\xa3\xbf\xa5\xe1\x5e\x17\xd9\xdd\xfa\x37\x76\xbf\xcb\x45\xbe\x85\xc0\x9b\x5a\xef\x77\x91\x85\x91\xbf\xda\x45\x36\xeb\xb7\x3c\xd7\x20\xdf\xc0\xe1\x9e\x7a\x8c\x2c\xea\x25\xfb\xeb\x72\x39\xca\x36\xc0\x4d\x9c\xb8\x1d\x65\x1f\x68\x88\xa3\xec\x6c\xc1\x55\x38\x98\x3b\xb5\x5c\x2e\x65\xb3\xf6\x0d\x25\x59\xda\x5c\xce\x7b\xfd\xb4\xc1\x83\x7d\xd8\xc0\xbc\x36\x10\xfa\x4c\x11\x7b\xd0\xc5\x7f\x10\x6b\xe0\x42\x9e\xb2\x70\xec\x34\x23\xe0\x9f\x8a\x7c\xb7\xa7\x87\xaa\xa1\x7a\x0b\x12\x79\x07\xca\x58\x0e\x0e\x6f\x40\x7c\xfe\x4b\x92\x90\xe4\x3d\x42\x15\x5e\xf7\x40\xd6\x62\x35\x39\xe6\x25\x3b\x09\xe8\xe6\xd5\xbe\x76\xa0\xbf\x0a\x95\x18\x59\x80\x11\xa9\x0c\xd5\x38\xa4\x82\x02\x32\xc7\x40\xff\xd2\xd6\x24\xf0\xe9\x83\x47\x57\x1e\x21\x2b\xe7\x81\x75\x78\xcb\xf5\xcc\x90\x7c\x27\xe7\xaa\x47\x80\x7c\xb7\x94\xd1\x56\x6b\x99\x21\x2c\x09\x68\xa5\x4a\x1a\xf6\x26\x63\xd8\x0e\xdb\x48\x0e\x59\xbd\x66\x90\x48\xc2\x66\x0b\x14\x2a\xae\xde\xb2\x8d\xe7\xe2\x02\x2c\xbf\xcc\xef\xf2\x6d\x67\x5b\x63\x80\xeb\x88\x14\xfa\x1e\x3c\x0d\x4e\x72\x80\xf7\x26\x5c\xa6\x61\x9f\xb1\xb6\x18\xb3\xbc\xc9\xb5\x2c\xee\x59\xc7\x11\x41\x8b\xdd\xe5\xd0\x98\xea\x69\x2d\x0d\xcd\x0d\xbb\x8c\x6f\xbd\xc6\x8b\xdf\x51\x85\xdc\x68\x8b\x41\xbc\x00\x6d\x85\xe9\x06\x58\x02\x52\x00\x88\x88\xb4\x32\x5c\x2d\x0c\x18\x67\x32\x8e\xe0\x9c\x1b\xba\x0d\xf0\x6b\x4c\x5c\x1c\x6d\xc3\x27\x3e\x0e\xb6\x2f\x24\xbb\x97\x8b\xb6\xc7\xbc\x20\x00\xd8\x58\xd6\xac\xc5\x7a\xd4\x9e\xac\x3d\xbc\x38\x4d\x8a\x5d\x3e\x6e\x55\x50\x56\x2c\x10\x84\x97\xf6\x8c\xc8\x9c\x7f\xb4\x65\xee\x49\xd9\xe6\x22\xed\x13\xb9\x0d\x30\x2a\xf2\xc5\xa8\xc8\x17\x1e\x5e\xdc\x22\xb7\xca\xc7\x45\x8e\xb2\x62\x81\x00\x5e\xc4\x50\x0a\x72\x27\xf0\x44\x7d\xae\x54\x43\x9c\xf8\xa8\x77\xc1\x60\x64\xcb\xf9\x1f\xaa\x99\x63\xde\x8f\xe8\xfc\xa5\xeb\xa0\x7f\x70\x4a\x12\x75\x60\x7e\x65\x0a\xc7\x9c\xe0\xe4\xa7\x37\x27\x2a\xe2\xb4\xa6\x25\x7d\xe9\x40\xeb\xf9\xdf\x4a\x00\xf0\xe4\x84\x81\x58\x37\xf4\x39\xaf\x2e\x2d\x44\x56\xdf\x4c\x02\x30\xef\x82\x80\x35\xad\xbd\xfe\xcd\x68\xb2\xd3\xc6\x6b\x65\xaa\xd6\xb7\x18\x66\xc9\xe6\x70\x5c\xcf\xd0\x02\xad\xff\xa7\x73\x7a\x8e\xa6\xeb\xfe\x3f\x0b\x7a\x36\x4c\xc0\x66\xf5\xbb\x47\x33\x29\xe5\x66\x2c\x29\x25\x7c\xb0\xd1\xd2\xf5\xc0\x94\x9a\x7b\xd2\x52\xf5\x06\xbb\xae\x61\xd3\xf9\x8a\x9e\x45\x1b\x09\x6f\xa4\x94\xb5\xfc\xd3\x19\x29\x1b\xcd\x36\x25\xd2\x81\x6b\x22\xdc\xd1\x73\xdd\xbd\xea\x82\xb4\xde\x1e\x19\x84\x8d\xbb\xf1\xea\x7a\xb9\x46\x7a\xec\x78\x0d\x58\xd6\x68\xf0\x3f\x9e\x1a\x7a\x18\xd6\xb4\x58\x99\x37\xab\x15\x3f\x05\xa3\x93\xae\x9b\xfc\x4c\x9a\x57\x17\x8a\xee\xf5\x68\x28\x28\x37\x7a\x99\x97\x9b\xf9\xc3\x3a\x19\xde\x1e\xe4\xe8\xed\x25\x4d\x69\xdb\x3a\x1b\x90\xee\x1f\x56\x29\x8a\x82\x72\xa3\x97\x79\xb9\x59\x2e\xb7\xd9\xb0\x04\xe7\xe8\x79\x79\xa8\x9c\xac\xec\xd3\x24\xa3\x36\x3c\xca\x07\x28\xf0\x32\xb1\x98\xed\x93\x6c\xa5\x13\xfd\x4a\x9a\x52\xbe\x13\x8e\x8d\xfc\x84\x64\x4b\x8a\xa2\xa0\xac\xe8\x65\xfe\x24\x68\xe9\x76\x33\x3b\x18\x9a\x48\xca\xa3\x1b\x23\xdb\xae\x16\x4b\x14\x03\x57\x5d\x58\xe4\x65\x25\xdd\x2e\x92\xb9\xea\xf8\x3d\xc9\x8e\xd4\x3f\xd1\xc1\xf7\xa0\xcd\xeb\x89\x8b\xfa\x25\xda\x38\x53\xd5\xfe\x9d\xad\x1e\x6a\x0d\xb0\x19\x17\x9c\xbf\x64\xf2\x08\xb2\x57\x83\xe4\x02\xed\xd5\xf0\xec\xc4\x4b\xfb\x04\x68\x88\x67\x32\x5e\x5a\x48\x73\x38\x9f\x3b\x38\xf6\xda\x3b\x48\x44\xb0\xaa\x0c\x37\xff\xf3\x7e\x86\xbb\x77\xa9\x38\xbb\x79\x47\xcf\x72\x9d\xa8\x58\x1e\x72\x15\xa9\xb5\xe9\x13\xe0\x1f\x59\x03\xfa\xa7\x5a\xbd\x3a\x48\x0a\x73\x40\x70\xf0\x4f\x00\x4b\x3f\x98\xb9\xc2\x53\x33\xe9\x3c\x6b\x01\x13\xe0\xa2\xfe\xf5\x72\xde\x57\x5d\x63\xe6\xa1\x5e\x20\x37\x96\x64\x10\x51\x26\x6e\x17\x2d\xcd\xcb\x13\x6d\x72\xd7\x3a\x19\x78\x64\x43\x55\xd3\xd3\x6c\x12\x81\xbf\x4f\x33\x28\x57\x41\xd0\x46\xab\xb1\xe3\xd5\xc8\xfd\xe1\xf9\x0c\x19\xa2\xf3\x24\xb1\x28\x3e\x9d\x1a\xd3\xdd\x57\x26\x6a\xd5\xff\xb3\x72\x0b\x00\xae\xed\xfb\xf7\x91\x21\x4d\x77\xae\x69\x20\x8a\x81\xf4\x2f\xce\xd7\xb6\xc4\x16\x5d\x9b\x36\x94\x96\x11\xcb\xbb\x30\x18\x2e\x78\x94\x58\xaf\x7f\xe8\xce\xe5\x83\xb8\x3b\xf5\xef\x5a\x66\x81\xab\x5a\x63\xe6\xa9\x90\xcf\xe7\x1b\x6b\x9b\x35\xb8\x53\x38\xda\xe3\xb0\xd7\xd6\x0b\xfd\x36\x5d\x77\xba\x9c\xf7\x25\xc9\x0d\x27\xd5\x5e\xa3\xe0\x67\xc6\xe7\xd8\x2d\x55\x23\xb3\xe4\xdb\x17\x34\xc6\x43\xf9\x6c\xe7\x45\xd8\x4b\x0e\x19\x4d\xe7\x6d\x44\x49\x4b\xe3\xbc\x8c\xab\x0b\xbf\x5e\x57\x05\x02\x8e\x43\xd9\xc2\x62\xd9\x3f\x27\xd1\xf0\x05\x64\x03\x85\x56\x43\x5e\xf6\xd0\x0c\x03\x48\x2e\x43\x06\x0a\xea\xe1\x5a\xf0\x6d\xb0\xcd\xc3\x27\x67\x62\x4d\xdd\x3b\x1c\x78\x9d\xa6\xa4\x56\xa1\x78\x78\x37\xfd\x11\x3f\xf1\x44\x0a\xda\x74\x46\x44\xc8\xbf\xd1\xf1\x86\x1b\xe6\xbc\xb2\xd3\x12\xbf\x59\x82\xdb\x2a\x8e\xc3\xff\x67\xd8\xec\x32\x5d\x05\x0d\xfa\xa9\x9e\x08\x84\xa7\x4b\x81\xde\x1f\x31\xc0\x3f\xd5\x16\x47\x2b\x83\xeb\x38\xcb\xdb\x73\xde\xb2\x65\xa3\xa4\x2e\xbf\xb1\x6c\x39\xbf\xd8\xf9\x96\x16\x3e\x22\xd1\x34\x2d\xaa\x16\xa7\xc5\x8b\x46\x9d\x05\xe1\x36\xc9\x8b\x08\xd2\x46\x7b\xe4\xa8\x79\xf9\x4a\x1b\xd2\xcd\x7a\xe1\x5a\xde\x66\x87\x43\x92\x61\xf7\x0d\xb2\x35\xdd\xa6\x6b\x9c\xba\x7b\x0e\x48\xb7\x74\xbe\x5f\xe0\x58\x66\x1f\xab\xd5\xca\x7e\xb5\x1c\x3c\x50\x0e\xa4\xd6\x07\x83\xff\xbe\x49\x1e\x5c\x87\x33\xb2\x2d\xcd\x0e\x58\x64\x79\x9f\xd2\x87\xc3\x0c\x21\xed\x6e\x01\x59\xd3\x19\xc5\xb8\x71\xb2\xbf\x5c\xcd\xd7\x5b\x1d\x01\xae\x2c\xd4\x51\x6d\xb2\xce\x16\x7b\x97\x11\x4d\x0f\x0f\x74\x81\xb4\xe0\x40\xe8\x3e\x4d\x71\xea\xee\x46\x1c\x36\x74\xb6\x5f\xe1\x58\xae\x76\xac\xd7\xab\x99\xd9\x0d\x60\x4d\xa2\xe4\xb3\x5d\x2e\x97\x73\x57\x33\xe6\x19\xcd\xb0\xad\x8f\xbe\x11\xd9\x0c\x25\xee\x6e\x05\x5d\xee\xb7\x69\x82\x22\xb9\x1a\xf1\xb0\x5c\xac\x16\x72\xad\xf9\xcf\xdf\x7e\x23\x67\x99\x2f\xf4\xf5\xd0\x90\x33\x6d\xa3\xba\xa9\x8e\x0d\x6d\xdb\x78\xcf\xd2\xe2\x34\x79\x4d\xf9\x70\x39\x34\xd5\x39\xfa\x05\x34\x6a\x18\x9a\xcb\x84\xfb\x02\x8c\x6a\x67\x2d\x5c\x07\xc0\x21\xc5\xcb\xbf\xf3\xea\xab\xbf\x57\xcd\x7f\x8f\x6a\xa7\xb2\x2a\x06\x0f\x33\x26\x78\xa6\x9b\xc0\xb4\xdd\xbe\x7d\xf5\xc7\x80\xfb\xf7\x73\xe4\x3d\x5d\xef\xbd\x7a\x14\x41\x05\x2c\x81\x4c\xcd\xa0\xe6\xe3\x90\x12\x85\x4d\x7b\xca\x91\x12\x09\xa2\xc7\x5e\xa3\x9a\xeb\x6b\x05\xff\x3a\xd8\xbb\xcd\xe6\x93\x49\x0c\x72\x07\x80\x16\xba\x1f\x25\xf6\x22\x60\xce\x1c\x3f\x17\x37\x5d\x73\xe7\x0b\x71\xe2\x6c\x00\x77\x29\x26\x78\xa1\xcc\xd9\x24\x1a\x3e\x8b\x4f\x91\xdd\x43\x76\x32\x0d\xc9\x74\x2f\x7d\xd2\xc4\xc7\x5e\xa3\x68\xd9\x7d\x58\xae\x32\x7a\x9c\x38\xd2\x2a\xac\x3e\xf6\x3e\xf8\x7c\xf5\xbb\x09\x74\x8b\x22\xeb\xc3\x2a\xf9\x9d\x9b\x04\x2b\x75\xa7\x65\x58\x7d\x8c\x36\x26\x3d\xf3\xc3\xc7\x47\xbc\x4d\xd5\xb5\xcd\x61\xac\xb3\xdb\xda\xff\x80\xcd\xf9\xbf\xb7\x2d\x6a\xec\x0d\x6d\xe2\x63\x9e\x99\xd6\x65\x62\xed\x0f\x19\xa5\x98\xc2\xab\x45\x85\xfa\x2a\x4f\xee\xd8\xea\x2e\xeb\x27\x65\x7e\x16\x11\x1e\x74\x22\x98\xb7\x42\xc8\x51\x5e\x1e\xf2\x32\xef\xe4\x48\xbd\x0d\xf1\x7a\x2c\x7c\x64\x5f\x13\xac\xf6\x0f\x7e\x17\xad\xff\x34\x02\xff\x98\x03\xe7\x3f\x8a\x11\x40\xf5\x3a\x7c\xdb\x63\x44\xa9\x31\x42\xff\xa9\xd1\xff\x78\x5a\xf0\x1f\x5e\xa3\xaf\xda\x43\x1b\x51\x6a\x07\xad\xff\xd4\xeb\x7f\x3c\x5d\xf8\x0f\xaf\xd7\xd7\xec\xc6\x8e\xa8\x35\x4e\xea\x3f\xb5\xfa\x1f\x4f\x13\xfe\x23\x6a\x35\xdf\x07\x33\xc3\xdf\xf0\x54\x19\x83\xb0\x1e\xec\x44\x1f\x62\x65\xa0\x93\x88\xff\x6f\xbc\xaf\x32\xbe\x2b\x8e\xc5\x70\x7e\xae\xd8\x56\xa3\x86\x39\x60\x0c\x1b\x76\x49\x62\x70\x12\x57\xfb\xbf\xd2\xb4\x43\xb6\xb0\x74\x30\x16\x16\x97\xbc\x3c\x4d\xeb\x4b\x51\x80\x4c\x3c\xc6\x1b\x08\x56\x25\xfd\x77\x03\x59\x65\x13\x32\x9f\x55\xb0\x90\xfb\x66\x28\x29\x40\x4a\x80\x01\xc7\x93\x2f\xe6\x09\x85\xae\xaa\x75\xda\x3c\xa5\x1c\x23\xe1\x7f\x16\x59\xb2\xa2\x52\x52\x5b\x87\x1f\x58\x91\x0e\x7e\xa2\x24\x93\x53\xac\xb5\x41\x83\x65\x58\xd3\x64\x96\xb7\x98\x70\xbd\xaf\x3b\x0e\x3b\xf3\xfe\x43\x9d\x5a\x5c\xd0\xb1\xad\xef\xd9\x30\x09\x79\xea\x11\xa9\x4c\x3d\x4f\x72\xe3\xa5\x0c\x83\x41\xd7\xab\xb7\xb7\xe4\x30\x73\x55\x61\x24\xb5\xf3\x64\x4e\x73\xdd\x99\x18\x39\x18\xbc\x04\x67\x4a\xb0\x0e\x00\xf9\x36\x9c\x70\xe6\x07\x4d\xef\xec\x5d\x4a\x8b\x00\x38\x7f\x68\x14\x38\x33\xc2\x5c\x75\xe1\x86\x05\x93\x5d\x47\x5b\xe4\xe1\xd1\x89\xd5\x0c\x55\x04\x6e\x05\x38\x41\xee\x70\x29\x00\x9c\x04\x71\x55\xe3\x14\xf5\x28\xf7\x6e\xcc\x80\x66\x85\x74\xb0\xb1\x41\x19\xde\x82\xbe\x2b\x6f\x60\x9f\xa1\xdd\xc2\xbb\x2f\xf9\x18\x7e\xee\x09\xe1\x8e\x17\x0c\xc7\xf0\xf0\xe2\xe0\x2b\x35\xb7\xdf\x9f\xc1\x6b\xbe\x46\x4f\x46\x30\x9e\xa6\xed\x99\x14\x05\x2a\xea\x31\xd4\x31\xcc\x5b\x54\x33\x08\x73\x9c\xe9\x31\x02\xa3\xf8\xfe\x91\x71\x3b\x66\x00\xeb\x23\x04\x18\xfe\x15\x43\xd3\xd5\x8b\x8e\x81\xe9\x97\x9f\x73\x58\xfa\x79\xb7\x06\x65\xba\xc9\x32\xea\x3a\x20\x78\xeb\xc1\x07\xd7\x04\xe4\xa1\x37\x8a\x72\xbd\x6d\x74\xd2\x72\xce\x83\x0a\x00\x49\x77\xe4\x6d\x75\x02\x4e\x75\x38\xa9\x82\xd3\x4b\x7e\x88\x61\x1e\x1c\x85\xbc\x26\xd9\x06\x68\x82\x61\xe9\x60\x0f\x58\x35\xde\x72\x68\xc4\x29\x0a\x07\x31\x3f\xfc\x3d\xba\xbe\x27\xe4\xee\x77\x56\x8a\x74\xba\xaf\xa5\xe9\x92\x2e\x0e\x4e\x5f\x8b\x91\xf4\xf4\x38\x28\xf6\xb3\x85\xcd\x71\x01\x7d\x3d\x70\x6e\xf4\x35\x94\xb7\x55\xe1\x8d\x27\x6c\x9c\x42\x70\xd3\x1b\x45\xb9\x47\xa7\x0b\x5a\x6e\x01\x4b\x00\xbb\xeb\xfd\xad\x26\x87\xb9\x3a\x3e\xe4\xa4\xea\xe9\x7d\x1d\xc2\x37\xde\x0d\xc8\x6b\xc6\x3b\x68\x82\xae\x03\x5a\x0f\x58\x35\xde\x76\x3a\xc9\x29\x0c\x27\xb9\x31\x8c\x7b\x28\x00\x27\xe5\xee\x7f\x51\x6e\x4b\xd5\xdb\x62\xba\x4f\x53\x4f\xf7\x73\xa2\x9e\xde\xd7\x00\x7c\x9d\xaf\x03\x5e\xd3\xf7\x80\x7f\xbd\xef\x35\xd9\x7b\x45\x7c\x45\x20\xc3\xe9\x65\x60\xeb\x68\xe3\x1c\xf4\x62\xb8\xae\x58\x52\xf4\xdc\xe9\xdc\xde\xd6\x1f\x0d\x27\x8c\x1e\xae\x75\x9d\xe4\xe1\xc7\x94\x66\xf6\x31\xa5\xc4\x3e\xc4\xe3\x83\xd5\x5a\x35\x44\xe8\xb4\xe3\xc2\x3a\x0c\x94\x3d\x1e\x66\x09\x7d\x35\x25\xec\xfa\x32\x7a\xa7\x18\x65\x09\x7d\xd9\x19\xe4\x65\xc3\xdd\x5f\x4e\xa2\xcb\xbb\x82\x06\xe9\x53\x62\x1e\xe3\x5a\xfb\x0e\xe6\x02\xea\xd2\x93\x8f\x90\x8f\xe2\xd2\xeb\xf0\xd9\xfc\x7b\x58\x04\x58\x5f\xf5\x4c\x85\x68\xfd\x87\xaa\xea\xf4\x8b\xd5\x66\x97\x05\x9c\xb9\x33\x9e\xca\x31\x0e\xf8\xbb\xae\x76\x8f\xc4\x9b\xcc\xbe\x7c\x02\x83\x54\x8a\xe0\x49\xb4\x42\xa6\x9b\x7b\x32\xe3\x8a\xae\x03\xe0\x16\x45\xcb\x58\x07\x55\x61\x22\xc9\xe4\x7b\xf6\x1b\x7f\xc8\x18\x76\x33\xa3\xc5\x0b\x7d\xc1\xc4\x10\x26\x83\x89\xe9\xcc\x8f\xbf\xfc\x70\xed\x60\xd4\x98\x02\xe1\x4a\x4f\x28\x33\xa8\x7d\x61\xa4\xf4\xd6\x05\xc7\x45\xaf\xd7\x53\x69\x73\x3e\xf9\x14\xc5\x17\x11\x96\x87\x44\xed\xb9\xe9\x93\x3d\x68\x3d\x78\x0e\xc9\x75\xe2\x2a\x83\x28\xc6\xfe\x8c\x1b\xda\xd6\x55\xd9\xb2\x9b\x7c\xec\x8b\x7a\xe0\xd6\x3b\x9c\xd0\xaa\x22\x71\x33\xc5\xa8\xc3\xf1\xd9\xae\x5a\x02\x0a\x16\x82\xdf\xb6\x36\x78\x33\xa9\x6b\x79\x33\x78\x29\x3e\xb2\xac\x22\x6b\x9c\xbc\x75\x58\x5c\xc9\xda\x53\xd7\x4f\xc6\xfa\x97\x46\xe3\x5d\x4d\x06\x37\xd0\xee\xb5\xf7\x1a\xda\xd7\x71\xe6\x96\xea\x68\xcd\xff\xf0\x62\x8f\xba\xec\x6e\xbd\x30\x5a\xd5\xe9\xb7\xea\xf0\x7b\xb6\x6a\xb4\x2a\x7f\xab\xee\xda\x1b\x77\x95\xf7\x5d\x25\xfa\x16\x99\x8d\x0f\x92\xdf\x60\x10\x80\xf9\xfb\x57\x1e\x03\x77\xaa\x29\xa0\xc3\x7e\xab\x9a\xbc\x6d\xba\x67\x4f\xdc\x53\xd6\xf7\x94\xe6\x1b\xe4\x65\x2b\xff\xd5\x53\x00\xc8\x60\x25\xd8\xc1\x9c\x51\xb3\x04\xf3\x2d\xef\xb0\xde\xb9\x8a\x3b\xd1\x87\xf0\x43\x13\xaa\xb5\x7e\xba\xbd\xb7\x19\x4e\xf7\x0a\x96\x9c\xf2\x1c\xa9\xf3\xff\x02\x71\x5f\x33\x6b\xbe\xa9\x9a\x70\x3f\xe0\x0d\x9d\x7c\xbf\xd6\x8c\x54\x33\x32\xcb\xde\x4d\xfc\xf7\x93\xf0\xfd\x84\x78\xb3\x9c\xd0\xe1\xf0\x1b\xeb\xfa\x5d\x0c\xcd\x68\x47\xfc\xfa\xe6\xec\x6e\x6d\x19\xed\xc0\xbb\x98\xd0\xb1\xb9\xf4\x5e\xd2\xbd\x9b\x00\x6f\x95\x51\x14\x60\xf0\xd1\x60\x44\xdf\xea\x4f\x66\x90\xc3\x2a\x02\xfd\x6a\xcc\x4a\x9f\x00\xb0\x4f\x1d\x3e\x99\x71\x72\x77\x68\x14\x1b\x8a\x21\xde\x9c\xc1\x59\x88\xd3\x86\x85\xf4\x50\x4b\xc0\x21\xa8\x59\x87\x1d\x8d\x51\x90\xa0\x91\x63\x44\x39\xa7\x4f\x5d\xf3\x64\x98\xc0\x68\x14\x7e\x64\x7a\x1b\x30\x7a\x5d\xba\xa6\x06\x05\x1f\x5c\x43\xef\x8a\x5e\x53\x83\x82\x0f\x9e\xa2\x83\xe5\x76\x1b\x8d\x37\xf0\xe1\x90\xee\x6d\x34\xde\xc0\x87\xa3\x0f\x6e\xa3\x71\x72\x05\x61\xd5\x23\xd7\xa1\x3a\xed\xf4\x69\xf1\x6e\xf0\x4d\x30\xa8\xcc\x43\xe8\x03\xf1\x86\xd1\x07\xb2\x0c\xa1\x0f\xc4\x16\x36\x41\xde\x28\xb1\x40\x55\xbe\x95\x87\x20\xa9\x06\xaa\xf1\xad\x3c\x04\x49\x3e\x50\x85\x5d\xab\xa2\xe1\xa5\xe1\x10\x25\xd6\x67\x91\x71\x2d\x36\x16\xe9\x01\x6a\x16\x5c\x03\x0a\x8f\xd4\x10\xa0\x27\x66\x9d\x6f\xa7\x71\x25\x1f\x8e\xb6\xbf\x9d\xc6\xc9\xf6\x87\xc2\xfb\x1a\x7a\x5c\x01\x5d\x0d\xc1\xbd\x3d\x2d\x46\x46\x28\x7d\x0c\xfc\xc6\x7e\xf6\xd6\x78\x2d\x81\x2b\x79\x08\x6a\xf5\xb5\x04\x4e\x8e\xdd\xca\x91\x55\xdc\xc8\xcd\x0f\x93\x80\x7b\x9f\x1c\x5e\xb6\x81\xa0\xfc\x8f\xb1\x0b\x26\xe8\x3b\x1c\x26\x91\x4f\x36\x2d\x33\x01\x9b\x8d\xa4\x1d\x31\xf1\x0a\x07\x45\xfb\xe4\xd9\x46\x56\xa7\x2a\xc2\x10\x07\x6f\x1f\xf1\xb1\x3d\xfe\xbe\x4e\x1e\xdd\xc8\xf5\x37\x85\xa3\x98\x0c\x45\x8e\xe5\x87\x7d\xd2\xc6\xe6\x48\x4b\x8d\xed\x79\x67\x02\xc0\x3e\x21\xdd\x01\xae\xef\x84\x9e\x1b\xb9\xb2\x1a\x5f\x2f\x38\x93\x8f\x06\xb6\x00\xc9\x49\x0b\xd8\xf5\x3e\xa6\x88\xd2\xc5\xbb\xc9\xc5\xb1\x58\xd2\x3a\x99\xd6\x52\x86\xfb\x2e\x79\x68\xe0\xbe\x5e\x7a\xf3\x75\x12\x5f\x4d\xb7\x74\xd4\x15\xed\x78\x43\xfe\x60\x94\xee\x9b\xfa\x0a\xe3\x5b\x4b\x2d\xe3\x4b\x9f\xa8\x81\x7b\x07\xd5\x1d\x72\x35\xfa\x2a\xbb\x69\x68\x85\x37\x05\xe9\x31\xc0\xb4\xeb\xa0\xbf\x97\xf4\xdb\x06\x18\xc2\xfa\x90\x3a\xc5\x97\x2b\x72\x80\xf5\x76\xd7\x1d\xb2\x52\x3a\x6b\xba\xa5\xaf\x42\x1b\x81\x75\xd4\xc0\xae\xeb\x94\xbe\x9b\xee\x9b\x7a\x09\x63\x5a\xcb\x05\xe2\x4b\x89\xa9\x81\xfb\xfa\xea\x1e\xf9\x37\x7d\x95\xdd\xd2\x5d\x57\x34\x05\x9b\xb8\x06\xa6\x5d\x67\xea\xbd\xa4\xdf\xd4\x69\x18\xeb\x30\xd3\x85\x2f\xff\x27\x84\xf6\x75\xd9\x3d\x72\x8d\x7a\xea\xba\xa5\xc7\xc2\x1b\x82\x75\xd8\xc0\xb2\xeb\x20\xbc\x8f\xf2\x9b\xfa\x4b\x67\x9c\x9e\xf7\x34\x33\x57\x14\xa1\x57\xeb\xe5\x91\x78\xfd\x3d\x82\x04\xcb\xe6\xe9\xac\xcf\xfa\x22\x0f\xe3\x5a\x90\xec\x03\x5b\xab\x59\x45\x39\x4b\x71\x8a\x21\xf1\x1c\x12\x58\xc9\x73\x9e\xd1\x4a\x9e\x31\x54\x0d\x26\xfb\xb6\x2a\x2e\xdd\x90\x7c\x59\xac\x73\xe0\x6d\x80\x21\x65\x01\x48\x37\x8f\x65\xf8\xb4\x56\x61\x56\x5b\x67\xeb\xfd\xeb\x56\x4b\x88\xa0\xee\x2a\xac\xa7\xf3\xd5\xef\x9c\x88\xcb\xfd\xeb\x02\xc5\xdb\x0c\x48\x5f\xa9\xb8\xec\x79\xce\x4b\x2b\xab\xe8\x70\xf8\x7b\xeb\xcf\x02\x3e\xee\xd6\x6b\xab\x0d\xba\xe8\xff\xdd\x9e\x9f\x35\xec\x1e\xc3\x38\x86\x26\x04\xa6\xb1\x7f\xbb\x54\x1d\xfa\x2a\xbb\x7e\x7a\x5d\x7c\xb5\xf3\x9b\x42\x8a\x71\x61\xdc\x7a\x98\xeb\xf9\x14\x90\x77\x0b\x18\x5a\x7b\xd6\xd1\xb6\x28\x16\xd8\xdb\x1a\x12\x84\xc3\xe7\x2e\x1e\x03\x1e\x6d\x18\x7d\x57\x25\x49\x86\x97\xd3\xf4\xfb\x21\x89\x5a\x2e\x1c\xf2\xa2\xeb\x3b\x98\x14\xf5\x89\x7c\xa8\x6a\x92\xe6\xdd\x6b\xf4\x43\x34\x4f\x58\x97\x88\x0f\xbb\x68\x3a\xd7\x18\x56\xb7\xdf\xf9\x5f\xf6\x35\x20\x58\x77\xc0\xe3\x23\x3e\x56\x56\x26\x2b\x32\x9f\xc3\xfe\xd2\x75\x55\x09\x24\xa8\x52\x61\xd6\x35\x25\x0d\x29\x53\xf0\x82\xaf\x6e\xbd\x90\xea\x87\x71\xc0\x92\x1d\xa3\xc3\xfb\x5c\x65\xa4\x88\xd9\x7b\xd4\x58\x36\x1c\x0d\xcc\x30\xb4\x87\xfc\x85\x67\x7f\x18\x8c\x4e\x03\x8c\xab\xcb\x00\xa9\xd4\x01\xb3\x64\x95\x3c\x9a\xef\xd2\x60\x86\x18\x8e\x41\x59\x16\xb7\x69\x53\x15\x05\x6b\x7f\x57\x5d\xd2\x13\x43\xbc\x74\xbd\xee\x98\xcd\x9b\x1e\x48\x46\x23\xd1\xd4\x2c\x27\x45\x75\xd4\x84\x0b\x53\xf7\x6a\xdf\xd8\xfb\xff\xd3\x85\x78\x82\x01\x7f\xce\x41\xfe\x89\xc2\x42\x40\x0f\x45\xb3\x4e\x01\x5c\x90\x8e\xf6\xe3\x39\x9e\xaf\x7e\xc7\x13\xb3\x9e\xdb\x00\xa0\x6a\x1c\xc6\x0b\xa0\xcb\x2e\x2f\xc7\x24\x87\xd0\x49\x46\xd9\x4d\xc6\x78\x4d\xbc\x8c\x26\x1f\x11\x05\x06\x5a\xaa\xd4\xe4\x05\x2a\x91\xfa\xfa\xaa\xbd\x7d\x61\xb7\x0f\xf7\x26\xc4\xd4\xa9\x3f\xa5\x61\xe4\x58\x62\x94\xc4\xc3\xd5\x1e\x52\xee\x5b\x76\x48\xf2\xdd\xb4\xc8\xeb\x5d\x34\xcc\x9a\xd6\x24\x87\x96\xdb\xf3\xdc\x76\xbb\xc5\x4b\x8c\x89\x63\xfe\x11\x9f\x16\xf4\x21\xe6\xbe\xdb\xb7\xa8\x5f\xfa\x59\xc2\x24\x8b\x5d\xed\x73\x82\xea\x02\xed\x1b\x9b\x35\x55\x7d\x77\x0b\xb4\x4c\x1c\xbd\x91\x24\x09\xce\x02\x37\x26\xbf\x78\xac\xbb\x61\xdc\x5d\x74\xf2\xd2\x4b\xc5\x39\x47\x08\x3a\xbd\xab\x2e\x5f\x11\x02\xbe\xd2\x6c\x3d\x5d\x2e\x4c\x77\x69\xec\x66\xe3\x77\xec\x05\x40\xbc\x02\x30\x19\xc1\x10\x78\x3c\x37\x95\xde\xbc\x83\x88\x5f\x44\x95\x0f\xf2\x18\x42\x51\x37\x37\xd1\xd1\x82\xde\xe7\xe4\x98\xe8\xdd\x40\xd1\x5e\x98\x76\x5e\xf9\x20\x8e\x18\x38\x26\x01\x41\x7b\xba\xef\xca\x4f\xec\x91\x33\xd7\x9e\x82\xf6\xa8\x8e\x8b\xc5\xe1\xd1\x34\x9c\xe2\xf0\x60\xbb\x1b\x9d\x39\x85\x9f\x86\x9f\x36\xbe\xa1\x6d\x7c\x96\xdc\x93\x26\x3e\x53\xd2\x5e\x1a\x73\xb1\x64\xad\x1d\xe2\xed\x76\x2b\x3c\x3c\x61\xee\x56\xc2\xab\x96\x7d\xb8\xb2\x1e\x3f\xe0\x95\x88\x8a\xc5\xe3\x55\x1f\x22\xf5\x64\x55\xa4\xbd\x59\x65\xd9\x5a\x59\xcf\x3a\x91\x2f\x4c\x49\xfd\x61\xaf\x92\x71\x3b\xcd\x1f\x98\xb2\xad\xab\xc3\x02\xad\xc4\xe5\x50\xdc\x04\xbd\x0b\x05\xd6\xeb\x15\x8e\xb0\xe4\x77\x91\x24\xda\x0b\x56\x58\xc3\xb7\xdb\xb9\xd1\xf0\x42\x6f\xf4\xd6\x20\x32\xed\xaa\xaa\xe8\x72\xd3\xd0\xc1\x6e\x02\xd6\x6b\x93\xe0\x8b\x5c\xe6\x54\x1f\xc8\x39\x2f\x5e\x77\xd1\xfb\x7f\xa5\xc5\x33\xed\xf2\x94\x44\xff\x46\x2f\xf4\xfd\x24\x52\x1f\x26\xd1\xbf\x34\x39\x29\x26\x51\x4b\xca\x36\x6e\x69\x93\x1f\xcc\xeb\xc1\xd8\xf3\x87\x4b\xcc\x4d\x9f\x2e\x7d\x1e\xaf\xcb\x26\x8a\xe6\x8e\x19\xc3\xad\x69\x0c\xb7\x26\x81\xae\xaa\x75\x23\xb0\x92\x37\x5a\x35\xab\x05\x96\x29\x12\xd3\xca\xbb\x28\x74\xc2\x1a\xd8\x08\x2e\xc8\x60\xe8\xaf\x18\xc1\x35\x53\x36\xba\xaa\x45\x78\x8e\xf3\x12\x79\x41\x6e\x9e\x60\x4f\x5a\x3e\x5c\xf1\x22\xc7\x35\x79\xe8\xc4\x72\xc8\xbd\x9d\x2a\x79\x25\x4d\x53\x7d\xf5\xe8\x33\xf6\xde\x48\x62\x2f\x6e\xf1\xdb\xf7\x22\x6b\x23\x33\xe2\x98\x4a\x20\x5c\x20\x5e\xc1\x8a\xc7\x3e\x74\xb1\xeb\x93\xa6\x34\x86\xfc\xe1\x4a\xeb\xd2\x31\xe2\x36\x00\x36\x78\x7a\x4e\x84\x97\xe1\x49\x47\xcb\x5f\x31\xb3\x3d\xde\x93\x1d\xae\xf2\x81\xb2\xc1\x93\x4f\xde\x8b\x1d\x27\x2b\x7c\xa3\x9d\x77\x8c\x9d\x71\x93\x8f\x66\x2f\x13\x26\x23\xfc\x2c\xae\x87\x15\x57\x27\x41\x4e\xa0\x7b\x19\xc6\x4a\x22\x99\x79\xd4\x0f\xef\xf9\x38\x11\x66\xc5\xc5\xcb\x4d\x9a\x8b\xf1\x61\x84\x59\x9d\x9c\x38\xf5\xd7\xf2\xbb\x75\x6d\xf1\x88\xe6\x4d\xec\xf8\x95\xc6\xa9\xbc\x77\x63\xa7\xae\x6a\x15\x1e\x1a\x8b\xc3\xe2\xeb\x8e\x35\x1e\xf9\x80\xd6\x7c\xb3\x36\xdd\x78\x30\x15\xdf\x67\x72\x5f\x86\x4f\xee\xe0\x1d\x4d\x38\x77\xa8\x47\xa3\xf4\x37\x8d\x9b\x33\x29\xfe\x6e\xcb\xdc\x34\x4d\xdf\xbc\xcc\xf5\xb8\x95\x89\xed\x29\xce\x91\x95\xad\x1b\xd6\xd0\x22\xe5\xba\x68\x5a\x0a\x83\x0a\x12\x70\xf0\x54\xb4\xf1\x8e\x81\x02\xc7\x44\x4b\x9d\x8d\x80\x2a\x3f\xc4\x58\x87\xd8\xa0\x60\x89\xa7\x94\xf2\xa1\x6f\xa6\xf6\x24\x2b\x92\x63\x66\xe9\x8e\xcb\x6f\xfa\x7f\x23\x8b\xd3\x7d\xff\x0f\xe9\x2b\x65\xe5\x23\x73\x64\xea\x11\x18\x10\xb9\x66\xbc\x18\xc0\x4f\x53\x66\x40\x26\x91\xf1\x61\x47\x0e\x9d\x77\x90\xdb\x8e\xf7\xdd\x7d\x19\x9d\xa3\x08\x49\xdc\x32\x73\xb5\x07\xb0\x2f\xa4\xb1\x8b\xde\xbf\xb7\x4d\x1f\xa6\x13\x5d\x55\xeb\x55\xca\x94\xd3\xc2\x06\x79\x26\x1f\x09\x82\x4c\xff\x5a\xfc\x09\x96\x98\x43\x64\xf5\xd1\x36\xc3\x56\xe6\x10\x8b\x55\xd0\x60\xa0\x45\x08\x87\xea\x91\x3a\x29\x95\xe8\xbd\x83\x63\x2d\xf3\xd5\x18\x27\x6c\x78\x42\xb1\xd9\x2e\x8c\x92\x8e\x3e\xd6\x75\x91\xe9\x8e\x8a\x2e\x34\xad\xcc\x2b\x36\xe6\x63\x84\xb0\x8a\x88\x4d\x89\x48\x18\x18\xaf\xbc\x74\x76\x75\x89\x79\x99\xe0\xb5\x59\x02\xbb\x51\xc9\xe0\xd0\xc3\x27\x70\x5d\x92\x7a\xa1\x2d\x4a\x2f\xb7\x40\x66\x32\x90\x74\x93\x9e\x8d\x33\x0d\xcf\x85\x01\x83\xed\x52\x33\xf9\xde\x6e\xb8\x9e\x21\x2c\x68\xee\xa9\x2e\x35\x58\x34\x2e\x33\xc0\x29\x90\x98\xcc\x8a\xa3\x2f\x7a\xc6\xc4\x15\xc6\x2d\x10\x57\x4a\x9a\xea\xd2\x52\x73\xd7\x4a\xc6\x15\x4d\x30\xb0\xa6\xf6\x46\xff\xe5\x46\xb9\x6b\xa7\x4c\xa7\xf7\x34\x0d\x4d\xfe\x2f\x5d\x40\x6c\x53\x4a\xbe\x24\x29\x5e\x01\x57\x5e\x97\xb1\x15\xe5\x02\x1b\x83\xf1\xb1\xfe\x24\x1f\x18\x47\x0b\xe5\x5b\xe3\xba\xb7\xa8\x07\xc4\x48\x51\xf0\x37\xec\xd5\x5e\x4e\xbc\xc8\x3e\x46\x93\xe8\x83\xbd\xd9\x16\x2f\xb2\x48\x84\xcb\x9c\x72\x0c\xdd\xb6\x5b\x5b\xef\xab\xfb\xb7\xee\x10\x78\xc7\xf6\x1d\x46\x19\xb8\xb3\x07\x92\xd2\xf8\x39\x6f\xf3\x7d\x5e\xb0\x68\xd5\xb0\x01\xf5\x6e\xac\x5c\xd2\xa9\x69\xd3\xd6\x94\x67\xa4\x64\x2f\x8d\xb0\x52\xeb\xab\x7a\xe2\x1f\x11\x96\x48\x68\x39\x95\x6f\x8d\xa0\x30\xa5\xcc\x21\x09\xd7\x29\xde\xed\xbd\x45\xf6\xa1\x1f\x02\x7c\xd8\x7f\x1c\xc4\xe4\x05\x0b\xe1\x53\xbc\x45\x82\x82\xd4\x0d\x7d\xbe\x9a\xcd\x38\x90\xcf\xf8\x3a\x46\x7d\xa2\xe4\x8d\xe8\xeb\x72\xb7\x03\xb8\xf1\xd7\xb4\x26\x09\x68\x49\xa2\xb5\x02\x1f\xd4\xce\x46\x94\x3c\x41\xba\xf9\x59\x89\x1e\x7f\xcf\x06\x27\xcf\x8d\x82\xbe\x21\x71\x6d\x7d\x63\x0b\x6b\x60\x8f\x7d\x55\x00\x56\x7c\xa0\xaa\x5a\x35\x79\xfb\xc9\xba\xd4\xd5\xe8\xe1\x11\x19\x00\xd5\x0f\xad\x1c\x8e\xea\xb1\xb6\xf5\x53\x69\x53\x99\x33\xe0\x6d\xe7\xc5\x56\xe6\x03\xd0\x57\xbd\xf5\x8c\x9c\xd8\x41\x1e\xa9\x5e\x33\xed\xbe\x7e\x47\xd4\x6c\xf0\x20\xd0\xf0\x47\xcb\x78\x7f\x5a\x5b\x40\x51\x32\x3c\x66\x05\x0e\x6b\x25\xc9\xec\x23\x93\x79\xf8\x33\x62\x77\xae\x40\x34\x63\x20\xcf\xaa\x9b\xb0\x09\x3d\xea\xaa\x7a\xc2\xb7\x3c\xf9\xcf\x43\x53\x9d\x3f\x58\x55\x7f\xe4\x4f\x7d\x55\x66\x09\xab\xfc\x63\xe0\x8b\x62\x5d\x15\x89\x19\xe6\xb6\xa6\xc9\xde\xae\x9b\xea\x98\x67\xbb\xff\xf2\x3f\xff\xd8\xd7\xf3\x67\x69\xe0\xa6\x7f\xca\xd3\xa6\x6a\xab\x43\x37\x55\x55\xb6\x1d\x69\xba\x3f\xf4\x6a\xd7\x76\xcd\x0f\xdf\x7f\xf7\x90\xf0\xff\xfb\x9e\x55\x47\xcb\x0c\x94\x25\xaa\x2c\xfa\x6f\x02\xff\xcf\xaf\x35\xfd\x61\x66\x36\xaf\xa1\x35\x65\x87\xd5\xd8\xff\xc6\x2f\x4e\xdd\x1a\x46\x1e\x0c\x06\xf3\x11\x23\x8f\x86\xbc\x51\xed\xb8\x88\x50\xe9\xad\xee\xa2\x76\xb7\x57\xf0\x66\xb5\xe3\xca\xe5\xd0\xbc\xd5\xdb\xd5\x2e\xb0\x69\x77\x50\xbb\xc4\xa3\x76\x0f\xf7\x56\xbb\xe1\x78\xa2\x59\xe0\x4c\x58\xee\xdc\xcd\x1b\xdb\x65\xd5\x8e\xf8\x20\x7b\xae\xd6\xfc\x32\x3d\x16\xaf\xf5\x29\x4f\xab\x32\x4e\x4f\xf4\xb9\xa9\xca\xd8\x9c\x1e\x3d\xa0\xbc\x1f\x35\xaf\x4b\x41\x33\x40\xd3\x53\xd0\x4b\x43\x1c\x06\xb1\x3a\x56\x01\xf8\x95\xb6\xf4\xca\x4b\xb6\x7e\xc1\xfd\x9a\x5b\xda\xa8\xf8\x12\x67\xb5\x7d\x91\x0c\x10\x7d\x0b\x17\x96\xb3\xd2\x5e\x54\xa2\x52\xb9\x23\xa3\xd5\xaa\xe2\x03\xde\x6a\xaf\x91\xba\xda\x7c\xd6\x4f\x89\xc8\xbf\xad\xa0\xb6\xb5\x85\xa1\x76\x26\xd0\x45\xa4\xaf\xfe\xdd\x9e\x1e\xaa\x86\xea\x21\xce\xef\xff\x32\x4f\x16\xdb\xef\x03\x1a\xe7\x46\x27\x36\x7a\x5e\x66\x79\x4a\xba\xaa\x69\x3d\xba\xa6\xc2\x8e\x09\x12\xc1\x1a\x76\x7f\x56\xc0\xaf\x5a\xf3\x42\xf7\xdb\x82\xf2\x10\x00\x87\xc3\xbd\x2b\xd7\x03\x86\x18\xf7\x45\xae\x7b\xf3\x50\xf9\x35\xb7\x5a\xef\xcf\x59\xa2\xc7\xf8\x67\xe0\x88\x55\xdf\xae\x5e\x76\xb1\x3a\x3a\xe4\x3d\x8c\x0c\x77\xd4\xa2\xbf\x6c\xf1\x42\xdd\x74\x27\x1f\x1d\x7b\x3d\x7a\xb8\x51\x6e\x0c\xa0\xda\x0d\x64\x00\x57\x29\xb2\xbd\x73\xa3\xbd\x73\x64\x4f\xc3\x7f\x6f\x73\x50\x35\x9e\x0c\xda\xa3\x28\x2a\x31\xf4\xef\xa0\xda\xcc\xf5\xa8\xeb\xca\x50\x1b\x78\x65\x85\x0f\x28\xe3\x62\x84\x75\x11\xe2\xae\xae\xb9\xb3\x99\xea\x20\x9b\x46\x09\xe8\xa1\x08\x04\xb5\x69\x43\x69\xc9\x63\x41\xea\x8c\x94\x76\x36\xec\xd7\x9a\x58\xde\x3a\xb3\x0c\x47\xbe\xc4\x09\x35\xa9\x25\x0b\xfd\xc8\x9a\x34\x73\x62\x1f\x19\xae\x96\x16\xea\x9c\xd7\x1b\x9b\x09\xe7\x16\x66\xe7\xcd\x09\x65\x75\x5d\x45\x61\x13\x8a\x56\x93\x9a\x44\xd0\xaa\x80\xf2\x4b\x3d\x9f\x73\xe3\x25\x14\x5b\xfe\x65\x6a\x2d\x2a\x22\xc3\xee\xbe\xd3\xb3\x3f\x0c\x61\x0e\x75\xb8\x32\x96\x4f\xc9\x3e\x0d\xdf\x78\xf0\x79\x12\x8d\x40\xf1\xf9\x80\x79\x22\xfd\xc7\xae\xaa\x8a\x3d\x69\x34\x64\xf9\x4d\x80\x46\xd3\xb4\xa0\xa4\x39\xe4\x2f\x0a\x4a\x7d\x00\xd4\x7a\x91\x92\xbc\xa4\x4d\x7c\x28\x2e\x79\x36\xc0\x1a\xdf\x07\xaa\xb2\x40\x80\x6a\x44\x06\xb0\xac\x88\x4f\x55\x93\xff\xdc\x97\x14\x51\x36\x10\xb6\x0a\x00\x33\x2c\xce\x0a\x4a\xf9\x07\x5d\x4e\x3e\x18\x40\x0a\x1e\x50\x55\xb8\xda\x47\xc5\x6a\x49\x9e\x15\x44\xff\x1b\x50\x29\xc9\xf3\x9e\x34\xea\x4e\x20\x04\xd3\xbe\x43\x5a\x7d\x01\x3f\xa0\x0c\x24\xa4\x7f\x37\xc0\x0d\xb2\x43\x71\x4d\x8e\x1a\x15\xfe\x37\x28\x96\x17\x14\x15\x05\xf0\x49\x81\xa9\x2d\x0e\xf1\x9b\x17\x08\x57\x4c\x7f\x4f\xd9\xdc\xe4\xb8\x5e\x85\x4d\xcd\x34\x94\x30\x48\xe5\xdc\xba\x32\x10\x09\x51\x15\x54\x07\x86\xde\x0e\xe8\x60\xad\x1f\xad\xee\xb2\xbb\xc7\xea\x0f\x63\xb3\xbb\x17\x06\x7b\x41\xfa\xa4\xa6\x2c\x36\xd9\x81\x23\xd3\xf6\xce\xbd\x6e\xda\xf4\x2b\x1e\xf1\xb0\xb8\x57\x3b\x5c\xfa\x8b\xdd\xf0\xa2\x5b\xf4\x4f\xf9\xb9\xae\x9a\x8e\x94\x9d\x06\xad\x62\x52\x02\x98\xfd\x6d\xc3\x9e\x72\x71\xbd\x40\xdb\x19\x42\x00\xdb\x93\xd8\xff\xd3\x1b\x83\x40\xe6\x25\xdb\x6d\x90\x2f\x73\x5b\x3b\x0f\xea\x94\x55\x3f\x7f\xab\xfa\xfb\xc9\x6b\x17\x25\x9f\x93\x88\x00\x5f\xc2\x38\xba\x60\x4d\xf9\xb8\x9b\x84\x1e\x78\x00\x71\x51\xce\x47\x50\xb3\xc9\xe1\x90\xbf\x60\xf7\x40\xa4\xb3\xf1\xed\x37\xf1\xb9\x8d\x9f\x73\xfa\xb5\xc7\x84\x3e\x5e\x46\x9f\xf3\x94\x72\xbf\x43\x92\x13\x92\x89\x8b\xe3\x24\x52\x7f\x9c\x33\xf0\x47\x7b\x06\x7f\xbc\xb4\x41\x4c\x0e\x54\xb9\xd2\x01\x0a\xc5\x31\xe6\x2e\x37\xf6\x4d\x40\xf7\x7a\x3e\xf0\x62\x91\x38\x67\x36\x09\xf5\x0d\x21\xd1\x9e\x2d\x12\xed\xd9\x26\xa1\xbe\x21\x24\x5e\x5a\x8b\xc4\x4b\x6b\x93\x50\xdf\xb0\xb1\x86\xcb\x6a\x38\x36\x2f\xcf\xbe\x45\xbb\xcd\x7a\xa3\x7c\x42\x43\xf2\x3e\x6d\x67\xae\x03\x33\xb1\x6e\x2c\x56\x2c\x41\x9b\x11\xb8\xb8\xa9\xbe\x22\x35\x64\x00\x6d\x12\x75\xa7\x31\x2a\x29\x2d\x0a\x8b\xcc\x95\x8d\x07\x02\x1d\x13\xc1\xb5\x94\x79\x8f\x19\xa4\xc5\xc7\xfb\xd0\x46\x99\xd7\x8a\x46\xea\x31\xaf\x92\xf0\x35\x84\x3a\x2c\xb9\xdd\xce\xac\xca\xe5\x6d\x8d\xeb\xf4\xc5\xc2\x72\xe8\x0b\x0e\x37\xaa\x2f\xbd\x2d\x01\xfa\xe2\xa0\x12\xa2\x2f\x37\x49\xe4\x76\x25\xba\xad\xba\x37\x68\xd6\x5b\x2a\xbc\xa3\xba\xf1\x0b\x3c\x46\xe5\xb3\xd9\x76\x6b\xd5\x7e\xce\x6e\xd1\x37\x0b\xcb\xa1\x6f\x38\xdc\xa8\xbe\xf5\x13\x19\xd0\x37\x07\x95\xeb\xf4\xed\x1a\x91\xdc\x43\xe1\xae\xaa\xef\x2e\x1a\x77\x43\x8d\x77\x54\xb9\x19\xbb\xc7\x63\x54\x24\xaf\x8d\x5d\xa7\x5d\x16\x96\x43\xbb\x70\xb8\x51\xed\xea\x7d\x26\xa0\x5d\x0e\x2a\xd7\x69\x97\xa3\xf5\xf7\x50\x24\x17\xe9\xbb\xe8\x8c\x9f\xf8\x9b\xd5\x03\x9f\x68\xb9\xdb\x6c\xbb\x1d\x96\xa7\xf5\x36\x03\x2b\xaa\xb1\x66\xab\xeb\xaa\x19\x1f\x55\xa2\x1e\xcb\x4a\x5d\x57\x8f\xd6\x13\x82\xa4\xa5\x9a\x6e\x92\xaa\xf3\xea\x26\x17\x07\xc8\xc3\x3c\xd8\x01\x1e\x21\x71\xe5\xc0\xc5\x10\x1d\x63\xd7\x09\x3a\x3a\x7c\x19\xa6\x36\x82\xdd\xb4\xdc\x83\x58\x47\xbe\xda\xef\x77\x49\xed\xda\x01\x6f\x60\x83\x31\xfd\x46\x3e\xae\xb6\x0e\x28\xfe\xfd\xe4\x72\x0f\x83\x02\x88\x8b\x01\x82\xf5\x3c\x3e\x46\xfe\x4f\x00\x00\x00\xff\xff\x47\x37\xb0\x07\xc9\x28\x02\x00") - -func cssBootstrapMinCssBytes() ([]byte, error) { - return bindataRead( - _cssBootstrapMinCss, - "css/bootstrap.min.css", - ) -} - -func cssBootstrapMinCss() (*asset, error) { - bytes, err := cssBootstrapMinCssBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "css/bootstrap.min.css", size: 141513, mode: os.FileMode(438), modTime: time.Unix(1565946440, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _faviconIco = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\x0b\x70\x55\xc7\x79\xde\x7b\xce\x45\x12\xb2\x90\xc4\xc3\xe6\x61\x3b\x90\xf8\x31\xc4\x19\x6c\x32\xe3\xc4\x34\xe3\xc6\x34\x6d\xed\xd4\x69\x62\x32\x49\x9a\xa6\x75\xea\x36\x33\xee\xd8\x9e\xb4\x75\xdc\x7a\xa6\xc5\x31\x02\xa6\xd3\x84\x47\x28\x6f\x3b\xc6\x3c\xcc\xeb\x9e\xbd\x08\x21\x04\x92\x28\x12\x0e\x08\x5b\x3c\xec\x02\x92\x78\x08\x21\x09\x41\x25\x24\x10\xe8\x71\xb5\xe7\xdc\xd7\xb9\xf7\xef\xfc\xff\x9e\x73\x74\x25\xdd\x97\x24\x82\x33\x1e\xce\xcc\x3f\x7b\xee\x9e\xdd\xff\xff\xf6\xdf\x7f\xff\xfd\xf7\xdf\xcb\x98\x8b\xa9\x2c\x3f\x1f\xcb\x19\xec\x15\x37\x63\x5f\x67\x8c\xcd\x98\x21\x7f\x6b\xf9\x8c\x6d\x72\x33\x36\x7b\xb6\xf5\xfb\x11\xc6\x9e\xbd\x97\xb1\x99\x8c\xb1\x7c\x6c\xc7\x64\x3d\x3d\x6e\x76\xdb\x1f\xe1\x75\xab\x42\x53\x7e\x22\x3c\x6c\x91\xf0\xb0\x02\x22\xae\x14\x08\x8f\xab\x40\xec\x64\x92\xf0\x5d\x53\xfe\x59\xec\x64\x5f\x15\x1e\xa6\x08\x4f\x7f\x7f\xdf\x7a\x96\xa1\x97\x3c\xb8\x3f\x78\xfa\x0d\x08\x9e\x5d\x08\xc1\xda\x5f\x82\x51\xf6\x65\x30\xca\x67\x41\xf0\xcc\xbf\x11\x19\x07\x1e\x07\xbd\x78\x2a\x18\x65\x8f\xb5\x0b\x4d\x7d\xad\x6f\x07\x73\x0b\xcd\x45\xfd\xbb\x17\xb3\x0c\xa3\x62\xce\xfe\xa8\xd1\x0a\xf8\x98\x6d\x25\x10\x38\xfe\x53\x88\xdc\x3a\x01\x66\x6b\x11\x11\xbe\x07\x8e\xfd\x2d\x84\x2e\x2c\x05\xff\xd1\x79\x3d\xc2\xc3\x7e\x20\x78\x06\x13\x5c\x89\xe9\xdf\x06\xd1\x50\x2f\x04\x4e\xfc\x0c\xcc\x6b\xa5\x60\x1c\xfd\x21\x74\x6c\x1e\x47\x84\xef\x58\x17\xf8\xe4\x65\x30\x6f\x54\x81\x71\xe0\x89\xea\xbe\x2d\x6c\xd2\x80\xfe\xfe\x76\x30\x6f\x1c\x81\x60\xed\x7c\x08\x9e\x5d\x0c\x2d\xeb\xc7\x41\xed\xd2\x29\x50\xbb\x74\x32\xbd\x63\x1d\x7e\xc3\x36\xa1\x73\xff\x19\x14\x1e\x36\x4f\x78\xc7\xc4\xf4\xef\x80\x70\xd3\xfb\x10\x6e\x5c\x0f\xdd\x65\x73\xe1\xdc\xf2\x89\xd0\xb1\x25\x0f\x6e\x7c\x90\x07\xe7\x7f\x33\x81\xea\xf0\x5b\xb8\x79\x13\x61\xd0\x8b\xa7\x2c\x09\x7c\xfc\x57\xac\x7b\x11\xf6\x7f\x6a\x5f\xd4\xb8\x06\xa1\xfa\x15\x10\x6e\x7a\x0f\x3a\xb4\xc7\xa0\x61\x55\x3e\x04\x8f\xfc\x39\x84\x3e\xfa\x4b\x68\x5c\x93\x4f\x75\xf8\x2d\x74\x71\x05\x44\x45\x13\xea\x54\xeb\x7c\x85\xa9\x48\xf8\x1e\x15\xcd\xf4\xcd\xee\x7f\x71\x65\x3e\x04\x3e\x7c\x86\x78\x5c\x5a\x1d\xd3\xbf\x7e\x05\xa0\x2c\x94\x89\xb2\x03\xd5\x3f\x66\x88\x05\x31\x21\x36\x1b\xff\xd9\xe5\x13\xe1\xda\xc6\x5c\x68\xdf\x94\x4b\x63\x71\xf0\x37\xbd\x0f\x38\x56\x1c\x33\x8e\x1d\x75\x80\xba\x40\x9d\x0c\xd6\x5f\xcd\x92\x29\x44\x83\xf5\x87\xba\x76\xfa\x73\x85\xe1\x5c\x18\x07\x9e\x38\x86\x18\x68\x8e\xac\xf9\xbb\xbe\x39\x87\xc8\x99\xbf\x13\x3f\xa3\x39\xc6\xb9\x8e\xed\x4f\xb6\xe0\x61\x3f\x40\xdb\x40\x1b\x41\x5b\x19\x62\x3f\xc7\x7f\x4a\xb6\x85\x0f\xda\x9a\xdd\x9f\xd6\x80\xe6\x62\xd2\x26\xd5\xd7\xd0\x46\xc9\x56\x0f\x3c\xde\x6f\xbf\xe5\xb3\xc8\xa6\xd1\xb6\xc9\xc6\x4f\xbf\x01\x68\xf3\x68\xfb\xce\x3a\xf2\x30\x26\x76\x32\x85\xd6\x08\xae\x95\xc1\xeb\x87\xd6\x14\xb3\x69\x11\xad\x39\xaf\x5b\x1d\xed\xfa\x05\x60\x8c\x65\x32\xc6\x54\x8b\x5c\x31\x64\x3d\x0b\x63\xe8\xb0\x45\x2d\x56\xdf\x99\x96\x8f\x99\x1b\xeb\x67\xf2\x47\x8b\xea\xf3\xf9\x08\xae\x22\xe5\x09\xae\x4e\x17\x5c\xfd\xc2\x28\x69\x8a\xe0\xca\x58\xb4\x3d\xdb\x17\xa6\x29\xff\x5f\x04\x57\x5b\x85\xe6\xba\x92\x90\xb8\x1a\x43\x4a\x4c\xbd\x62\xd7\xb7\x08\xae\xd6\x0b\xae\xfe\x8f\xe0\xea\x9b\x38\x1e\x1f\x1f\x4b\xfe\x34\xb5\x7c\xa5\x40\xec\xca\x02\xbd\x64\x3a\xe8\xfb\xbe\x38\x94\x4a\xa6\x83\xf0\x66\x82\xd0\x14\x10\x9a\x0b\x44\xe1\x38\x5c\x2b\x44\xf8\x4e\x75\x5c\x01\xe1\x75\x03\xf2\x11\x9a\x2b\x2a\xb8\x52\x2b\xb8\x3a\x4f\x68\x8a\x92\x0c\x03\xc9\xf7\xb0\x02\xa3\xfc\x2b\x10\xe9\xae\x85\xa8\x7e\x15\xa2\xfa\x95\x18\xba\x0a\xa1\xb3\x8b\x49\xbe\xbe\xe7\x5e\x08\xfe\xef\x3f\x81\xd9\x51\x09\x91\xbe\x4b\x44\xf8\x8e\x75\xf8\x4d\x70\x37\x04\x3e\xfe\x11\xf9\x14\xbd\x68\x3c\xe2\xe8\x14\x5c\x7d\x49\x78\x99\x2b\x11\x06\x47\xfe\x81\xd9\x10\x0d\xde\x82\xc1\x8f\x79\xe3\x30\xe8\x7b\xa7\x81\x51\xfa\x28\x98\xd7\xca\x00\xa2\xa6\xfc\x80\x65\xcc\x3b\x7e\xc3\x36\xfa\xde\x07\x08\x93\xd9\x5a\x0c\xfa\xfe\x87\x41\x68\xac\x43\x70\xf5\x59\x92\xe3\x1d\xea\x1a\x92\xc9\x8f\x06\x3a\xc1\xff\xe1\x5c\xda\x67\x91\x27\x3e\x91\xde\x0b\xe4\xaf\xfc\x47\x5f\x20\xc2\x77\xac\x23\xac\x1d\x95\xd4\xd6\xff\xe1\x9f\x10\x2f\xfa\x5d\xf2\x05\xc4\x70\x4c\x70\xf5\x7e\x94\x35\x1c\xf9\xa1\xc6\x77\x68\x3e\x43\x17\x57\x4a\xfe\xe8\xc3\xcb\xbe\x8c\xfc\xa0\xcf\x23\x09\xdf\xb1\x0e\xbf\x51\x9f\x8b\x2b\x65\x9f\xc6\x77\xe8\x37\xee\x4f\x62\xd7\x58\xb4\x8f\x05\x3e\x9e\x35\xc4\x1e\x13\xc9\x8f\x06\xbb\xc0\xa8\xfc\x23\xf0\x1f\xfa\x63\x88\x86\xba\x21\x72\xeb\x24\x18\xfb\x1f\x82\xde\x1d\x2e\x68\xdd\x30\x0e\x1a\x56\x4f\x24\xc2\x77\xac\xc3\x6f\xd8\x06\xdb\x62\x1f\xec\x8b\xef\x10\xd6\xc1\xff\xd1\xf7\x11\x67\x83\xe0\xea\x97\x06\xeb\x20\x91\x7c\xd2\xdd\xee\x3c\x08\x37\x6f\x04\x30\x0d\x08\x7c\x34\x8f\xe4\x34\xae\x99\x00\xa7\x7f\x3d\x0d\x4e\xfd\xea\x7e\x22\x7c\xc7\x3a\xfc\x86\x6d\xb0\x6d\xb8\x69\x23\xf5\xb5\xe7\xcc\x6c\x3f\x00\x62\x77\x6e\x54\x68\xae\x57\xad\xf5\x96\x52\x7e\xb0\x6e\x01\xe8\xfb\x66\xd0\x1a\x30\xaf\x95\x83\x28\xcc\x81\x2b\xef\xe6\x92\x3c\x24\x8a\x63\x96\x4d\x71\x7e\xe3\x37\x6c\x83\x6d\xb1\x0f\xf6\x0d\xd6\x15\x48\x5d\x86\x7c\x64\x47\xc2\xc3\xf6\x0a\xae\x66\xc6\xea\x20\xae\xfc\x48\x08\xfc\x55\xdf\x05\x7f\xd5\x77\x00\x22\x41\x08\x7e\xfa\x2a\x74\x6d\x53\xa1\x6e\xf9\x64\x92\x75\x69\xcd\x44\xb8\xb9\x35\x13\x6e\x6d\xcb\x80\xe6\x75\xe3\xa9\x0e\xbf\x61\x1b\x6c\x8b\x7d\xb0\xaf\xbf\xea\x7b\xc4\x8b\xec\xe2\xec\x22\x9c\x83\x66\xc1\xd5\x19\xa9\xe4\xd3\xdc\x1f\x98\x0d\xc1\x33\x6f\x42\x34\xec\x03\x7f\xe5\x1c\x68\xdb\x30\x96\xe4\x9c\xfb\xcd\x7d\xd0\xbd\x63\x0c\xe8\x85\x63\x41\x2f\xbc\x07\x7a\x3d\x6e\xa8\x5f\x39\x89\xbe\x61\x1b\x6c\x8b\x7d\xb0\xaf\xe4\xd9\x65\xd9\x6e\x19\x88\x5d\xd9\xba\xd0\x5c\x73\x53\xca\xd7\xff\x0f\xf4\xfd\x0f\x41\xa8\x61\x35\xf9\x1f\x7d\xdf\x74\x68\x5e\x97\x47\xf3\xdd\xf2\x4e\x1e\xc9\x0d\x9f\xfc\x3b\x30\x4f\xbd\x02\xc6\x9e\x09\xd0\xba\x21\x07\x4e\xfd\x6a\x1a\xb5\xc1\xb6\xe4\xb3\x1a\x56\x13\x0f\xe4\x25\xd7\xed\x39\x5c\x9b\x51\xa1\xb1\x17\xe3\xc8\x7f\x0b\x63\x13\x5c\xef\xd4\xb6\xaf\x91\x7c\x6b\xf8\xf2\x16\x5a\xdb\x62\xcf\x64\xb8\xb4\x7a\x3c\xc9\x68\xdb\x90\x0d\xfe\xb2\x87\x01\x2e\x2d\x07\x68\x5a\x05\x81\xca\x27\xe1\xfa\xe6\x4c\x39\x2f\xab\xc7\x53\xdb\x88\xaf\x9e\xfa\x22\x0f\xe4\xe5\xc4\x47\xa5\x8f\xa2\x0d\xfc\x22\x8e\xfc\x5f\xe0\x37\x3b\x5e\x4f\x2e\xff\x1e\xf0\x97\x7e\x11\xa2\x0d\x4b\x00\x9a\x56\x42\xe0\xe0\x13\x70\x7d\x53\x56\x6a\xf9\x81\x4e\x8a\xbf\x70\xac\x43\xe4\x6b\xec\x45\xd4\x0d\xea\x28\xbe\xfe\x67\x38\xfa\x6f\x5e\x97\x2f\xfd\xcb\xd1\xe7\x21\x74\xec\x87\xa0\xef\xce\x81\xab\xbf\x1d\x67\x7d\xcb\xb3\xd6\xcc\x50\xfd\xe3\xdc\xe2\x1c\xcb\xb3\xd0\x60\xf9\xae\xb9\x68\x1b\xe4\xdf\x53\xd8\x1f\xda\x39\xda\xbe\xee\x55\x41\xf7\xba\xc9\x16\xcf\xaf\xb8\x2f\xa5\xfd\x25\x95\x8f\x6b\x42\x63\xcd\xb8\xcf\x25\x5c\x7f\x5b\xe5\xfa\xc3\x39\xb8\xf0\xdf\xf7\x42\xfb\xc6\x7b\xa0\x63\x53\x36\x5c\x5c\x35\x29\xad\xf5\x97\x42\x7e\x26\xfa\x06\xda\x37\xc2\xbe\xb4\xfc\x0f\xd2\x99\x25\xd3\xd2\xf2\x3f\xc9\xe5\x2b\xf6\x1c\xbc\x86\x3e\x12\x7d\xe5\x50\xff\xeb\x8f\xe3\x7f\x25\x0d\xf5\xbf\xfe\x21\xfe\x37\x99\xfc\x18\x1d\x7c\x09\xf7\x08\xdc\x2b\xc0\xd4\x69\xef\x30\x2a\x46\xb9\xff\x58\x73\x9f\x5a\xbe\xc2\x7c\x1a\xed\x8d\x0b\x70\xaf\xc4\x3d\x53\xee\xbf\xef\x8e\x7a\xff\x4d\x47\x7e\x8c\x0e\xee\xc7\x58\x01\x63\x06\xd4\x1d\xf6\x41\x9b\x18\x51\xfc\x61\xf9\xb2\xb4\xe5\x7b\x55\x1b\xc3\xb3\x18\x33\x61\xec\x84\x31\x14\xf1\xdc\xfb\x40\x5a\xf1\x97\x4e\xf1\xd7\x34\x8a\xd9\x06\x3f\xa9\xe4\x3b\xb6\x48\xb1\xa2\xfa\x12\xc6\x8e\x18\x43\x62\x2c\x89\x31\x25\xc6\x96\x29\xe3\x4f\x6f\x26\xc5\xaa\xf1\x62\x58\x8c\x6d\x31\xc6\x4d\x26\xbf\x7f\x3d\x60\xcc\xac\xce\xa3\x18\x1a\x63\x69\x8c\xa9\xb9\x5b\xc6\xd8\x14\x7f\xe7\xc4\xc4\xdf\x39\xb2\x0e\x63\x73\x8c\x91\x93\xc5\xf0\xc4\x47\x49\x2a\x9f\x30\x68\x0a\xf3\x15\x65\x31\x6b\xaf\x7e\xd3\x3a\x53\xd4\x5b\x67\x8c\x44\xe7\x0f\x49\xc9\xcf\x30\xad\xd6\x59\x27\xa9\xfc\x58\x5d\xf4\x69\x14\x2f\x8d\x95\x67\xab\x51\x9f\xcf\xa6\x5b\x67\xbd\xb4\xe4\x7f\xde\x1f\x7b\x6d\x1c\x66\x2a\x1c\x66\x0c\xe9\x99\xc3\x8c\x4d\xb7\x28\xcf\xa2\x4c\x8b\xd4\x74\xa8\xc5\xa2\x1e\x8b\x02\x16\x99\x8c\xa9\xc0\x48\x90\x6a\xcb\x9d\xc9\x18\x9b\xcd\x18\xfb\xfb\xd8\x3c\xc5\xc3\x9f\xb5\x56\xee\x3e\x77\x9f\x3f\xcc\xc7\xda\x1f\x1f\x16\x5c\x7d\x5b\x70\x75\xa1\xe0\x6a\xc1\xef\x89\x6c\xde\xff\x2a\xb8\xfa\x37\x82\x2b\xb3\x05\x57\x72\x7a\x35\xc6\x0c\x2d\x79\x3e\x29\x0d\xfc\xdf\x16\x5c\x0d\x0a\xae\xc2\x1d\x22\x53\x70\xb5\x53\x70\xf5\x20\xed\xeb\x5c\xc9\xc7\x58\xc3\x48\x33\x3f\x97\x18\xbf\x42\xb1\x57\x5a\x84\x6d\x07\x60\x4a\xd2\x37\x6e\x5b\x97\xfd\x1b\xf5\x56\x2a\xb8\xfa\x24\xec\x67\x4c\xe7\xc3\x1b\x83\x83\x5f\x73\x05\x31\xc6\x0b\xd6\xbe\x45\xe7\xf2\x64\x14\x3c\xbb\x08\x8c\x8a\xa7\xfa\x71\x21\xc6\xc2\x1c\x30\x0e\x7e\x0d\x02\x27\xfe\x81\x78\x20\xe1\x3b\xd6\xc9\x78\x84\x39\xd8\xf5\xe2\x29\x60\x94\xcd\x04\xe1\xcd\x8a\x1d\x47\xa3\xe0\xea\x0b\x7e\xce\x5c\x7a\x8a\xfc\x64\x7c\xfc\x2c\x48\xf1\x75\xb8\x6f\x48\x9c\x37\xf8\x31\xdb\x4a\x64\x9c\x84\xb2\xbd\x19\xe0\x3f\xf2\x17\x60\xb6\xee\x85\x68\xe0\x26\x40\x34\x12\x13\x20\x46\xa8\x0e\xbf\x61\x1b\x6c\x8b\x7d\xf4\xe2\xc9\x10\x6a\x58\x0b\xe1\xcb\x5b\xc1\xa8\xfc\x46\xff\x9c\x70\xb5\x0d\xc7\xd0\xa3\x65\x33\x91\xe6\x3c\x0c\x17\x7f\xa4\xeb\x14\xc5\xb4\xc2\xc3\xe8\x3c\x43\xb1\x65\xb0\x3b\xe5\x98\xb1\x0d\xb6\xc5\x3e\xf2\x7c\x30\x13\x22\xdd\x35\x10\xf5\x5f\xa7\x73\xa9\x28\xbc\xc7\x1e\x43\x93\xe0\xca\x53\x14\x73\x16\xa6\x8e\x89\x86\x83\x9f\xce\x41\x55\xdf\x23\xec\x62\x77\x2e\x9d\xc7\xed\xb3\xa8\x1c\x5c\x10\xa2\xa2\x05\x22\xb7\x3e\x21\xc2\x77\xac\xeb\xff\x1e\xa2\x3e\xd8\x17\x79\x20\xaf\x68\xa8\x87\xda\x84\xea\x97\xcb\xbc\xb3\x1c\x43\xa5\xe0\xea\xe4\x74\x62\xba\xe1\xe0\x0f\x35\xac\x91\x36\xc0\xdd\x10\xac\x7b\xbb\x1f\x7b\x34\x0c\x66\x47\x05\xdd\x3d\xe9\xa5\x8f\x80\x5e\x34\x51\x52\xe9\x23\xf2\x3e\xaa\xa3\x82\xda\xd8\x63\x08\xd6\xfe\x52\xc6\xee\xde\x0c\xe2\x69\x8f\x1d\xcf\x4d\x92\xbf\x1a\x45\x7f\xeb\xf3\x32\x57\x5f\x0a\x3b\x4a\x17\x3f\xea\xd2\x28\x9f\x25\xf5\x76\xe4\x3b\xfd\x79\xad\x70\x1f\x84\xce\xff\x17\xe8\x7b\x26\x59\xfe\xc6\xca\xdb\xdb\x3e\x46\x63\xf4\x0d\xdb\xd8\xbc\xe9\x0c\x78\xe4\x79\xe2\x85\x3c\x69\x9e\x68\x7e\x7b\x21\x50\xfd\x63\x7b\x4d\x5f\x13\x5c\xfd\x7a\xca\x73\x45\x9a\xf8\x69\x7e\xad\xb5\x67\xde\xa8\xea\xd7\x59\xdd\x02\x79\x0f\xc1\xa5\x1f\xe9\xd9\x39\x06\x6e\x6e\xcd\x22\xc2\x77\xb9\x36\x5d\xd4\x06\xdb\xda\xf6\x64\xde\x38\x42\xbc\x90\x27\xf2\x76\x4c\xac\xbb\x86\x72\x44\xd6\x18\xde\xd3\xb9\xcb\x9d\xcc\x1f\xa5\x83\x9f\xf2\x5c\x15\x73\x48\x5f\x81\x4f\x5f\x75\xce\xa8\xe1\xcb\x5b\x1c\x9b\x45\xac\x57\xde\xcd\xa3\x5c\x66\xcd\xd2\x29\x44\xf8\x8e\x75\x72\x1c\x0a\xb5\xc5\x3e\x92\xa9\x49\xbc\x68\x0e\x2a\xe6\x0c\x38\x5b\x87\x2e\x2c\xb1\xce\x86\x6a\xbb\xe0\xea\x57\x93\x9f\x2d\x53\xe3\xa7\x5c\xcf\xae\x6c\xb2\x03\xb3\xb3\x5a\xea\xa9\xaf\x51\x9e\x5d\x35\x06\xdd\xdb\x33\x9c\x9c\x53\x3c\xc2\x6f\xd8\x86\xfc\x4e\xf9\x57\x9c\xfc\x9f\xd9\xf9\xb1\xb4\xbb\xc2\x6c\x30\xdb\xcb\xfb\xf5\xa5\x5f\x95\x79\x41\xb9\x67\x2c\x12\xdc\x9d\xf0\xce\x2a\x1d\xfc\xe4\xdf\xc8\x5f\x7c\x97\x72\xf1\x54\x57\xf3\xef\x64\x17\xbd\x1e\x37\xe5\x6c\x12\x61\xb7\x09\xdb\x60\x5b\xec\x83\x7d\xe5\x00\x0c\xe2\x89\xbc\x51\xc6\x00\x99\x75\x0b\x6d\x1b\x3a\x2e\xb8\x32\x61\xa4\xf8\xf1\x37\xe5\xe9\x35\x06\xa1\x86\x55\x96\x7e\x5a\xc0\x28\x9d\x49\x75\xad\xef\x8d\x1b\x82\xb5\x76\xd9\xc0\x7b\x00\x9b\xb0\xad\xed\xfb\xa3\xfa\x15\x69\x2b\x17\x57\x51\x1d\xca\x88\x95\x8d\xfe\x57\xde\x9f\x29\x3e\xc1\xd5\x6f\x26\xce\x8f\x24\xc7\x1f\xf1\x35\x80\x5e\xf2\x00\xe8\xbb\xf3\x21\x72\xf3\x98\x65\xf7\x1f\x80\xf0\x8e\x81\x9e\x1d\x63\xc8\xc6\x6d\x7c\x35\x4b\xa7\x92\xbd\xdf\xda\x96\x09\x5d\xdb\x33\xa1\x6d\x43\x8e\x73\xbf\x60\xe7\xf9\xb1\x0f\xfa\x48\xdc\x7b\x89\xff\xcd\x6a\xe2\x4d\x79\x65\x5f\xc3\x40\xbd\xfd\xee\x5b\xb6\x0d\x51\x7e\x3b\xde\x3a\x4e\x85\xdf\xec\x38\x44\xb6\x6f\x94\x3d\x46\xff\x67\xc0\x27\x70\xf2\x65\xe2\x7b\xed\xfd\x9c\x98\xbc\xe7\x54\xa9\x5f\x27\x16\x50\x40\xe7\x2a\x5c\xdf\x9c\x4d\xf7\x32\x76\x3b\xec\x83\x7d\x03\x9f\xfc\xa3\xc4\xe9\x6f\x27\xde\x28\x03\x65\x0d\xb0\xa1\x9a\xff\xb0\xf1\x6f\xd3\xb9\x2b\xee\x9d\x69\x2a\xfc\xa4\x6b\x9c\xdf\xc3\xcf\x01\x44\x02\x94\xcb\x35\x2a\x9f\xa6\xba\xa6\xb5\x13\x9c\x7c\x29\xae\x51\x9f\x47\xe6\x93\xf4\xc2\x6c\xd0\x77\x8f\x73\xe2\xcd\xcb\xeb\xf3\x9d\xfc\x2a\xf6\x21\x7e\x87\x9e\x96\x79\xe1\x48\x80\x78\x63\x1d\xca\x1a\x20\xfb\x2a\xb7\xf7\xb3\x6a\xc1\x95\xdc\x91\xe0\x0f\x5d\x58\x26\xfd\xe6\xf1\x97\xa4\xbe\xc4\x65\xca\x5d\xf5\xee\x54\x29\xe7\x6d\xeb\xb5\x0d\xf5\xca\x5d\x60\xec\x9d\x4a\x77\x30\x91\xda\x37\xc0\x5f\x3e\x93\xc6\xd3\xf9\xc1\x58\xb2\x2d\x3b\x4f\xee\xdb\xa9\x12\x0f\xe4\x45\xf3\x79\xfc\x25\x92\x81\xb2\x06\xd8\xee\xcd\x13\xf2\xce\x98\x2b\x4d\x82\xab\x0f\x26\xc9\x91\x3e\x97\x08\x3f\xed\x4f\x3b\x19\x04\x4f\xbd\x2e\x79\xf6\xd4\xd2\xbe\xd3\xbd\x7d\x0c\x9c\xb5\x6c\x1b\xb1\xe1\x7e\xa5\x7b\x55\x08\x1d\xfb\x11\x40\xf3\x5a\x22\xf3\xf4\xcf\x69\x2e\xd0\xff\xa3\xed\x23\x7e\xec\xd3\xbd\xdd\x4d\x31\x74\xa4\xa7\x4e\xca\x38\xf5\xba\x94\x81\xfb\x5b\xac\xef\x10\xcd\x74\xf7\x64\xdd\x79\xcf\x4a\x82\xff\x5b\x42\x63\x86\x71\xf0\xc9\x21\xb1\x24\xf9\x4e\xe4\x5d\x3b\xdf\xd2\xc9\x71\xd0\x8b\xf2\xa1\x6b\x5b\x86\xe3\x63\xb0\xec\xda\x9e\x41\xf7\x6f\x66\xcd\xeb\x00\xcd\x6b\x00\x9a\x56\x43\xb4\x7e\x31\x18\x7b\x27\x83\xcf\x23\xe7\x0a\xf1\x3b\x6d\x8b\xf2\xe9\xff\x3a\x24\xa3\x76\xbe\x94\x31\xc8\x87\x62\x6c\x4a\x31\x8b\xc6\xfa\x04\x57\x9f\x4e\x82\xff\x69\x6c\x43\xb1\x88\xff\xfa\xc8\xf0\x6f\xcb\x00\x7d\x57\x16\x98\x67\x7e\xde\x8f\xff\x42\x01\x18\xc5\x93\x08\xff\xf9\x91\xe0\x0f\x76\x03\xea\x14\x75\x4b\x3a\x4e\x8c\x7f\x16\xe5\x96\xf7\xcd\xa0\x39\x4b\x6e\x3f\x75\x34\xf7\x68\x03\xb6\xfd\xa0\xef\xb9\xb1\x85\xee\xd3\x21\x78\xe4\xcf\xe8\x0e\x10\xed\x27\x7c\xe2\x45\xd0\xbd\x19\xd0\xbd\x23\x83\xda\x0e\xdb\x7e\xc2\x7d\x74\x67\x81\xb6\x4d\x36\x9e\x18\xff\x83\xb8\x46\xf4\xa2\x09\x74\xdf\x31\x92\xf5\x7b\xf5\xb7\xb9\x96\xef\xc9\x81\x60\xd5\x73\x10\xaa\xfe\x3e\xe8\xc5\xf7\x82\xce\x15\xba\xd3\xc2\x31\x9e\xfa\xb5\xbd\x7e\x95\xb4\xd6\xef\x20\xfc\xdf\x8e\x8f\x9f\x72\xeb\xb9\xe4\xa3\x70\x5f\xb9\xca\x07\xf0\x48\xd7\x7f\x9e\x5b\x81\x7b\x53\x46\x7f\xec\x6c\x91\x4f\xeb\x8f\x2f\xb0\x6d\xe3\x30\xfc\x67\xba\xf8\xe5\xde\xa0\x6e\x47\x1e\xc1\x9a\xf9\x03\x78\xa4\xbb\x7f\x21\x35\xad\x1b\x0f\xbd\x9e\x31\xd6\x3d\xa6\x0a\x7d\x9a\x9b\xe6\x05\x75\x3f\x64\xff\x3a\xf9\xb2\xb5\x46\x13\xef\x5f\xe9\xe0\xd7\xed\xbb\x3e\xdc\xa3\x51\x2f\xbf\xfb\xd3\x81\x71\x48\xdc\xf8\x61\x6b\xdc\xf8\xc1\xde\xc7\x30\x6e\x40\x9c\xa8\xeb\x58\xec\xc3\x89\x1f\xd2\xc5\x1f\xb3\x06\xbe\x29\xb8\xd2\xa7\xef\xb9\x0f\x22\x5d\x9f\x0e\xe0\xe1\xc4\x6f\x17\xd3\x8b\xdf\x12\xd1\x70\xe2\xb7\xe1\xe1\xa7\x35\x30\x81\x62\x55\xcd\x45\xe7\xd0\xd8\xe7\xb3\x88\x9f\x87\x85\x5f\x53\x18\xfd\x3f\x95\xab\x8b\xe5\x19\xe3\x71\x3a\x43\x38\x6b\xe0\xf7\x76\x7e\xa9\x8e\x7b\x7e\x19\x2e\xfe\x18\x1b\xc2\xb3\x5a\x07\x9e\xdd\xf0\x0c\xe7\xf0\xb9\x23\xe7\xc7\x9b\xa3\xc4\x4f\x7e\xc8\x8d\x67\x66\x3a\xa7\xef\x7f\x88\xce\xd2\xf6\x93\xf6\xf9\x7d\x47\xcc\xf9\x7d\x47\xb2\xf3\x7b\x55\xdc\xf3\xfb\x48\xf1\xc7\xcc\xc1\xd7\x28\x77\x81\x3e\xae\xfa\xaf\x29\xa7\x01\x43\xf2\x27\xcf\x0f\xcc\x9f\x9c\xbb\x3d\xf9\x93\xd1\xe2\xef\xe3\x2e\xe6\xe3\x4c\x91\x67\x66\x35\x8a\x7e\x8e\xd6\xb2\xa5\xb3\xd4\xf9\xab\x17\xc1\x28\x7d\x04\xf4\x3d\x13\x89\x8c\x44\xf9\xab\xba\xb7\x87\xe6\xaf\x6e\x03\xfe\x98\x39\x98\x2c\xb8\x7a\xc8\xb6\xd9\x50\xfd\x32\x99\x1b\x0c\xf5\x38\xfe\xe2\xf6\xe5\x0f\x13\xe7\x4e\x47\x84\xbf\x50\xb5\xfd\xe9\x1c\x2b\x97\x4a\xb9\x55\xfa\xdf\x50\xe0\x3a\x44\xba\xcf\xc8\xdc\x37\xda\x8a\x9d\xbf\x4d\x82\xc1\xc1\x62\xe5\x6f\xb1\x0f\xe5\x7e\x4b\x1f\xa5\x5c\x70\xd2\x3e\x23\xc0\x4f\x63\xf0\xba\x58\x8f\x27\x1b\xe7\xe1\x05\x99\xd3\x56\x68\xbe\x8d\xca\x6f\xd0\xbe\x19\x6a\x58\xeb\xac\x3d\x27\x7f\xde\x56\x92\x7e\xfe\xbc\xe4\x41\x30\xdb\xf6\xa5\x1e\xf3\x08\xf1\xe3\xa3\x7b\x15\x66\xec\xa2\xff\x6d\xbc\x60\xdd\x2d\x48\xbc\xbb\xb2\xe8\xbf\x31\x7a\xf1\xd4\x24\xf7\x17\xf3\x89\x12\xdd\x5f\x18\x15\x4f\xd1\x1d\x48\xca\x7b\x92\xda\xb7\xac\xff\xda\xba\x86\x8d\x9f\xc6\xc0\x5d\x0c\xbc\xe4\x5b\xd1\x27\x95\x39\x77\x64\x8e\x8f\x19\xcd\xfd\xd1\xb0\xee\xa9\x46\x84\x1f\x1f\x43\x73\xd9\x6b\x7a\xbc\xbc\x6b\xa3\x3b\xb7\x4e\xeb\x0e\xee\x4e\xdd\xf7\x8d\x18\xbf\x33\x0e\x8f\xc2\x7a\x8b\x54\x8c\x35\x72\x04\x57\x67\x0b\xae\xfe\xc4\xba\x0b\x2d\xb8\x03\xf7\xae\x6f\x5b\x77\xbc\x23\xc6\x7f\xf7\xb9\xfb\x7c\x9e\x1e\xb9\x43\x24\x2e\x5b\x18\x63\xcf\x58\x65\x9e\x55\x66\x5a\xa5\x6b\x50\xc9\xec\xb2\xc0\x2a\x9f\x19\x54\x4e\x4f\x50\xe6\x25\x28\x33\x6f\x5f\xd9\x93\xa0\x0c\x24\x28\xcd\x41\x65\xd4\x2a\xc1\x2e\x17\x0e\x2a\x5b\xac\xb2\xc7\x2a\x4d\xab\x4c\xa1\xdf\xff\x0f\x00\x00\xff\xff\xc6\xb9\x24\x2f\xee\x3a\x00\x00") - -func faviconIcoBytes() ([]byte, error) { - return bindataRead( - _faviconIco, - "favicon.ico", - ) -} - -func faviconIco() (*asset, error) { - bytes, err := faviconIcoBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "favicon.ico", size: 15086, mode: os.FileMode(438), modTime: time.Unix(1565946440, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _jsJquery211Js = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\xce\xcf\x2b\xce\xcf\x49\xd5\xcb\xc9\x4f\xd7\x50\x4a\xad\x48\xcc\x2d\xc8\x49\x55\xd2\xb4\x06\x04\x00\x00\xff\xff\xc8\x9f\xbd\x5f\x17\x00\x00\x00") - -func jsJquery211JsBytes() ([]byte, error) { - return bindataRead( - _jsJquery211Js, - "js/jquery-2.1.1.js", - ) -} - -func jsJquery211Js() (*asset, error) { - bytes, err := jsJquery211JsBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "js/jquery-2.1.1.js", size: 23, mode: os.FileMode(438), modTime: time.Unix(1591451173, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "css/bootstrap.min.css": cssBootstrapMinCss, - "favicon.ico": faviconIco, - "js/jquery-2.1.1.js": jsJquery211Js, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "css": {nil, map[string]*bintree{ - "bootstrap.min.css": {cssBootstrapMinCss, map[string]*bintree{}}, - }}, - "favicon.ico": {faviconIco, map[string]*bintree{}}, - "js": {nil, map[string]*bintree{ - "jquery-2.1.1.js": {jsJquery211Js, map[string]*bintree{}}, - }}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} diff --git a/_examples/file-server/embedding-files-into-app/main.go b/_examples/file-server/embedding-files-into-app/main.go deleted file mode 100644 index ccb39b25..00000000 --- a/_examples/file-server/embedding-files-into-app/main.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -// Follow these steps first: -// $ go get -u github.com/go-bindata/go-bindata/v3/go-bindata -// $ go-bindata -prefix "assets" -fs ./assets/... -// $ go run . -// "physical" files are not used, you can delete the "assets" folder and run the example. -// -// See `file-server/embedding-gzipped-files-into-app` example as well. -func newApp() *iris.Application { - app := iris.New() - app.Logger().SetLevel("debug") - - app.HandleDir("/static", AssetFile()) - - /* - Or if you need to cache them inside the memory (requires the assets folder - to be located near the executable program): - app.HandleDir("/static", http.Dir("./assets"), iris.DirOptions{ - IndexName: "index.html", - Cache: iris.DirCacheOptions{ - Enable: true, - Encodings: []string{"gzip"}, - CompressIgnore: iris.MatchImagesAssets, - CompressMinSize: 30 * iris.B, - }, - }) - */ - return app -} - -func main() { - app := newApp() - - // http://localhost:8080/static/css/bootstrap.min.css - // http://localhost:8080/static/js/jquery-2.1.1.js - // http://localhost:8080/static/favicon.ico - app.Listen(":8080") -} diff --git a/_examples/file-server/embedding-files-into-app/main_test.go b/_examples/file-server/embedding-files-into-app/main_test.go deleted file mode 100644 index fd8116bb..00000000 --- a/_examples/file-server/embedding-files-into-app/main_test.go +++ /dev/null @@ -1,96 +0,0 @@ -package main - -import ( - "io/ioutil" - "path/filepath" - "runtime" - "strings" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -type resource string - -// content types that are used in the ./assets, -// we could use the detectContentType that iris do but it's better -// to do it manually so we can test if that returns the correct result on embedding files. -func (r resource) contentType() string { - switch filepath.Ext(r.String()) { - case ".js": - return "text/javascript" - case ".css": - return "text/css" - case ".ico": - return "image/x-icon" - case ".html": - return "text/html" - default: - return "text/plain" - } -} - -func (r resource) String() string { - return string(r) -} - -func (r resource) strip(strip string) string { - s := r.String() - return strings.TrimPrefix(s, strip) -} - -func (r resource) loadFromBase(dir string) string { - filename := r.String() - - filename = r.strip("/static") - - fullpath := filepath.Join(dir, filename) - - b, err := ioutil.ReadFile(fullpath) - if err != nil { - panic(fullpath + " failed with error: " + err.Error()) - } - - result := string(b) - - if runtime.GOOS != "windows" { - result = strings.Replace(result, "\n", "\r\n", -1) - result = strings.Replace(result, "\r\r", "", -1) - } - return result -} - -var urls = []resource{ - "/static/css/bootstrap.min.css", - "/static/js/jquery-2.1.1.js", - "/static/favicon.ico", -} - -// if bindata's values matches with the assets/... contents -// and secondly if the HandleDir had successfully registered -// the routes and gave the correct response. -func TestEmbeddingFilesIntoApp(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - route := app.GetRouteReadOnly("GET/static/{file:path}") - if route == nil { - t.Fatalf("expected a route to serve embedded files") - } - - if runtime.GOOS != "windows" { - // remove the embedded static favicon for !windows, - // it should be built for unix-specific in order to be work - urls = urls[0 : len(urls)-1] - } - - for _, u := range urls { - url := u.String() - contents := u.loadFromBase("./assets") - - e.GET(url).Expect(). - Status(httptest.StatusOK). - ContentType(u.contentType(), app.ConfigurationReadOnly().GetCharset()). - Body().Equal(contents) - } -} diff --git a/_examples/file-server/embedding-gzipped-files-into-app/bindata.go b/_examples/file-server/embedding-gzipped-files-into-app/bindata.go deleted file mode 100644 index 6a385285..00000000 --- a/_examples/file-server/embedding-gzipped-files-into-app/bindata.go +++ /dev/null @@ -1,382 +0,0 @@ -// Code generated by go-bindata. (@generated) DO NOT EDIT. - -//Package main generated by go-bindata.// sources: -// ../embedding-files-into-app/assets/css/bootstrap.min.css -// ../embedding-files-into-app/assets/favicon.ico -// ../embedding-files-into-app/assets/js/jquery-2.1.1.js -package main - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(data []byte, name string) ([]byte, error) { - gz, err := gzip.NewReader(bytes.NewBuffer(data)) - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -// Name return file name -func (fi bindataFileInfo) Name() string { - return fi.name -} - -// Size return file size -func (fi bindataFileInfo) Size() int64 { - return fi.size -} - -// Mode return file mode -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} - -// ModTime return file modify time -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} - -// IsDir return file whether a directory -func (fi bindataFileInfo) IsDir() bool { - return fi.mode&os.ModeDir != 0 -} - -// Sys return file is sys mode -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -type assetFile struct { - *bytes.Reader - name string - childInfos []os.FileInfo - childInfoOffset int -} - -type assetOperator struct{} - -// Open implement http.FileSystem interface -func (f *assetOperator) Open(name string) (http.File, error) { - var err error - if len(name) > 0 && name[0] == '/' { - name = name[1:] - } - content, err := Asset(name) - if err == nil { - return &assetFile{name: name, Reader: bytes.NewReader(content)}, nil - } - children, err := AssetDir(name) - if err == nil { - childInfos := make([]os.FileInfo, 0, len(children)) - for _, child := range children { - childPath := filepath.Join(name, child) - info, errInfo := AssetInfo(filepath.Join(name, child)) - if errInfo == nil { - childInfos = append(childInfos, info) - } else { - childInfos = append(childInfos, newDirFileInfo(childPath)) - } - } - return &assetFile{name: name, childInfos: childInfos}, nil - } else { - // If the error is not found, return an error that will - // result in a 404 error. Otherwise the server returns - // a 500 error for files not found. - if strings.Contains(err.Error(), "not found") { - return nil, os.ErrNotExist - } - return nil, err - } -} - -// Close no need do anything -func (f *assetFile) Close() error { - return nil -} - -// Readdir read dir's children file info -func (f *assetFile) Readdir(count int) ([]os.FileInfo, error) { - if len(f.childInfos) == 0 { - return nil, os.ErrNotExist - } - if count <= 0 { - return f.childInfos, nil - } - if f.childInfoOffset+count > len(f.childInfos) { - count = len(f.childInfos) - f.childInfoOffset - } - offset := f.childInfoOffset - f.childInfoOffset += count - return f.childInfos[offset : offset+count], nil -} - -// Stat read file info from asset item -func (f *assetFile) Stat() (os.FileInfo, error) { - if len(f.childInfos) != 0 { - return newDirFileInfo(f.name), nil - } - return AssetInfo(f.name) -} - -// newDirFileInfo return default dir file info -func newDirFileInfo(name string) os.FileInfo { - return &bindataFileInfo{ - name: name, - size: 0, - mode: os.FileMode(2147484068), // equal os.FileMode(0644)|os.ModeDir - modTime: time.Time{}} -} - -// AssetFile return a http.FileSystem instance that data backend by asset -func AssetFile() http.FileSystem { - return &assetOperator{} -} - -var _cssBootstrapMinCss = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\xef\x8f\xe3\x38\x92\x20\xfa\xb9\x1a\xe8\xff\x41\x5b\x8d\x41\x57\x4d\x59\x2e\xf9\x77\xda\x89\xce\xb7\xfb\xe6\x0e\xb7\x03\xdc\xec\x97\x9b\x0f\x07\xf4\xf4\x7b\xa0\x25\xda\xd6\x94\x2c\x69\x24\x39\x2b\xb3\xfb\xf6\xfe\xf6\x83\xf8\x4b\x41\x32\x48\xd1\x4e\x77\xcf\xdc\x62\xb7\xee\x7a\x9c\x62\x44\x30\x18\x0c\x06\x83\x41\x32\xf8\xf9\xf7\xff\xf4\xed\x37\xd1\xef\xa3\xff\xb7\xaa\xba\xb6\x6b\x48\x1d\x3d\x2f\xa6\x8b\xe9\x32\xfa\x70\xea\xba\x7a\xf7\xf9\xf3\x91\x76\x7b\x59\x36\x4d\xab\xf3\x47\x06\xfe\x87\xaa\x7e\x6d\xf2\xe3\xa9\x8b\xe6\xc9\x6c\x16\xcf\x93\xd9\x2a\xfa\xf3\xd7\xbc\xeb\x68\x33\x89\xfe\x58\xa6\x53\x06\xf5\xdf\xf3\x94\x96\x2d\xcd\xa2\x4b\x99\xd1\x26\xfa\xd3\x1f\xff\xcc\xc9\xb6\x3d\xdd\xbc\x3b\x5d\xf6\x3d\xc5\xcf\xdd\xd7\x7d\xfb\x59\x55\xf2\x79\x5f\x54\xfb\xcf\x67\xd2\x76\xb4\xf9\xfc\xdf\xff\xf8\x87\xff\xfa\x6f\xff\xe3\xbf\xb2\x4a\x3f\x47\x9f\x7f\xff\x4f\x51\x59\x35\x67\x52\xe4\x3f\xd3\x69\xda\xb6\x3d\xb3\xc9\x74\x1e\xfd\x2f\x46\x5b\x54\x17\xfd\xaf\xe8\x98\x77\xd3\xbc\xfa\xac\x60\xa3\xdf\x7f\xfe\xf6\x9b\x53\x77\x2e\xa2\x5f\xbe\xfd\xe6\xdd\xa1\x2a\xbb\xf8\x40\xce\x79\xf1\xba\x8b\x5a\x52\xb6\x71\x4b\x9b\xfc\xf0\xf8\xed\x37\xef\xe2\xaf\x74\xff\x25\xef\xe2\x8e\xbe\x74\x71\x9b\xff\x4c\x63\x92\xfd\xf5\xd2\x76\xbb\x68\x96\x24\xbf\x63\x10\xe7\xd6\x51\xfa\xed\x37\xff\xfe\xed\x37\xdf\x7e\xb3\xaf\xb2\x57\x56\xcd\x99\x34\xc7\xbc\xdc\x45\x89\x28\x20\x4d\x97\xa7\x05\x9d\x44\xa4\xcd\x33\x3a\x89\x32\xda\x91\xbc\x68\x27\xd1\x21\x3f\xa6\xa4\xee\xf2\xaa\x64\xbf\x2f\x0d\x9d\x44\x87\xaa\x62\xb2\x3c\x51\x92\xb1\xff\x3d\x36\xd5\xa5\x9e\x30\xb2\x79\x39\x89\xce\xb4\xbc\x4c\xa2\x92\x3c\x4f\xa2\x96\xa6\x1c\xb7\xbd\x9c\xcf\xa4\xe1\x95\x67\x79\x5b\x17\xe4\x75\x17\xed\x8b\x2a\xfd\x22\x39\xb8\x64\x79\x35\x89\x52\x52\x3e\x93\x76\x12\xd5\x4d\x75\x6c\x68\xdb\x4e\xa2\xe7\x3c\xa3\x95\x8e\x97\x97\x45\x5e\xd2\x98\xa1\xf7\xed\x7e\xa6\x3d\xfb\xa4\x88\x49\x91\x1f\xcb\x5d\xb4\x27\x2d\xed\x21\x20\xe9\x5d\x59\x75\xd1\x87\x1f\xd3\xaa\xec\x9a\xaa\x68\x7f\x8a\x3e\x6a\x24\xcb\xaa\xa4\x3d\xa9\x13\xed\x35\x67\x10\xcc\x8f\xa7\x3c\xcb\x68\xf9\xd3\x24\xea\xe8\xb9\x2e\x48\x47\x23\x0b\x4f\x56\xc3\x4a\xf6\x24\xfd\xd2\xcb\xa3\xcc\xe2\xb4\x2a\xaa\x66\x17\x75\x0d\x29\xdb\x9a\x34\xb4\xec\x24\xe4\x8e\xa4\x5d\xfe\xdc\x8b\x7b\x77\xaa\x9e\x69\xc3\x30\xab\x4b\xd7\x33\x0d\x3a\x65\xbf\x6f\x7e\xec\xf2\xae\xa0\x3f\x71\xd2\x55\x93\xd1\x26\xde\x57\x5d\x57\x9d\x77\xd1\xac\x7e\x89\xb2\xaa\xeb\x68\x26\x7b\x77\x12\xb5\x5d\x53\x95\xc7\x41\x93\xbe\x8a\xe6\x6c\x12\x49\x34\x3b\x94\x43\x71\xdb\xbd\x16\x74\x17\xe5\x1d\x29\xf2\x54\x00\x9c\x66\x9a\x86\x4c\xd7\x1b\x7a\x8e\x92\x47\x85\x92\xff\x4c\x77\xd1\x9c\x9e\x05\xf8\x99\x34\x5f\x18\x82\x68\xed\x77\x49\xc2\x80\x07\x39\xec\xa2\xef\x0e\x07\x59\x7d\x7b\x26\x05\xd0\x74\x4e\xed\x41\x29\x68\x7b\xe9\x1b\x71\xa9\x19\x44\x5d\xb5\x79\xaf\x3d\xbb\xa8\xa1\x05\xe9\x05\x66\x70\xb1\x59\x31\xb5\x67\xca\xa0\x3a\x2e\x40\x21\x64\x05\x5d\x55\xef\xa2\x78\xba\x52\x8d\x69\x2f\x7b\x21\x69\x2e\xe2\x78\x3a\x1f\x0a\xf3\xf3\x11\x74\xc3\xd0\x4d\xed\xf3\x91\x2b\xd7\xae\xa9\xaa\x8e\xeb\x55\xdf\xa9\x87\xa2\xfa\xba\x8b\xb8\xfe\x08\x50\x3e\x82\x34\xf9\xce\xe8\x39\x5a\x26\xf5\x8b\x94\x3e\xd7\x05\xad\x35\x72\xe0\xef\xab\x97\xbe\xe1\x79\x79\xdc\x45\xbd\x1e\xd3\x92\x7d\xe3\x23\xbf\xfa\xd9\x57\xee\x28\x12\x95\xd6\x82\xa7\x81\x6b\x72\xe9\x2a\x51\x98\x56\xbd\x41\xf8\xb2\xcf\xfa\x41\x49\x27\x51\x4b\xce\xb5\x6d\xaa\xce\x55\x59\xb5\x35\x49\xe9\x64\xf8\x69\xf4\xd6\x4c\x49\x72\x7f\xe9\xba\xde\x28\xe4\x65\x7d\xe9\x26\x51\x55\x77\xdc\x82\x44\x2d\x2d\x68\xda\xf5\x63\xed\xa5\x23\x0d\x25\xba\xad\x92\xf4\x7a\x03\x70\xa2\x4d\xde\x3d\x0e\x6a\x27\xbe\x68\x15\x18\x6d\x7a\xce\xdb\x7c\x5f\x50\x83\x07\x5e\x25\x57\x87\xde\x74\xb2\xd1\x7a\xa8\x9a\xb3\x36\xb6\x25\x34\xb3\xd3\x8c\xed\x1f\xbb\xd7\x9a\xfe\xc0\xbf\xff\x34\x81\xdf\x1a\xda\xd2\x4e\xff\xd4\x5e\xf6\xe7\xbc\xe3\xa3\x58\xf6\x26\xa9\x6b\x4a\x1a\x52\xa6\x74\x17\x71\x32\xac\x39\x97\xa6\xed\xdb\x53\x57\x79\xd9\xd1\x46\xab\xfe\xc7\x2c\x6f\xc9\xbe\xa0\xd9\x4f\x1a\x23\xea\x2b\x1f\x86\x82\x40\x46\x0f\xe4\x52\xe8\x02\xd9\xed\x98\x9e\x1c\xaa\xf4\xd2\xc6\x79\x59\xf6\xc6\x9b\xd1\xb0\x0b\xf8\x00\x24\x59\xc6\x54\x86\x8f\x68\x43\xef\x19\x26\x83\xd3\x06\x20\x9f\xd8\x20\x0c\x97\x41\x7a\xa2\xe9\x97\x7d\xf5\x62\x08\x8b\x64\x79\xa5\x0b\x06\xea\xaa\x32\x79\xb8\x96\xeb\xc5\xee\x92\xa1\x21\x36\x5f\xe5\xe5\xbc\xa7\xcd\x4f\xbb\x9d\xac\x9f\xb5\x3f\x6e\xeb\xbc\x8c\x35\x45\x75\x80\x57\x97\x4e\x07\xff\xf6\x9b\x77\x70\x08\x83\xa1\x04\x35\x82\x92\x26\x3d\xb9\x1b\x7e\x9f\xf1\xfd\xe8\xd0\xb7\x5e\xd3\x0f\x39\x2d\x32\x27\x63\x43\xfb\xf8\x87\x38\xed\x31\x0b\x4c\x22\x2e\x8c\x8c\xa6\x55\x43\x7a\x03\x2e\x24\x82\x71\x02\xc6\x18\x63\xa8\xa5\x9d\xae\x7a\xd3\xc5\x8a\x9e\xa3\xe9\x7a\xce\xfe\x67\xb3\xa2\xe7\x47\x68\x13\xa2\x79\xfd\x02\x95\xb3\x9f\x14\xdb\xaa\xc8\xb3\xa8\xcd\x8b\x67\x35\x80\x0a\x7a\xa4\x65\x16\xa0\xd4\x9a\xe5\x41\xed\xa1\xb4\x56\xbe\x49\xb6\xeb\x07\x24\x9c\xb3\x7b\x7b\x68\x56\xda\xfb\x07\x05\xa9\x5b\xda\x77\x19\xff\x25\xd1\xb3\x49\xd4\x9d\x0c\x6e\x59\xd9\xbb\xde\xcd\xfc\x1f\xd5\xa5\xe9\x65\x87\xb8\xab\xa7\xd5\xbe\xfe\xdc\xdb\x86\x55\xbc\xaf\xf2\x82\x36\xcc\x65\xd1\xdc\xd6\xb6\x49\x3f\xa7\x6d\xfb\xb9\xf7\xd5\x98\x9f\xda\xfb\x9f\xff\x7c\xa6\x59\x4e\xa2\xba\xc9\x4b\x2e\xff\xdf\x4f\xa2\x1d\x39\x30\x37\x6f\xb7\xa7\x87\x4a\xcc\x10\x70\x96\x8f\xfe\x29\x3f\xd7\x55\xd3\x91\x92\x19\x62\x6e\x3e\xdb\x13\xc9\x7a\x81\xf5\xfd\x6a\x02\x40\x97\x20\x89\x2c\x7c\x6d\x18\xf8\xc8\xb8\xcb\xbf\xfd\xe6\x5d\x2f\x24\xd2\x3b\x56\xbd\xb9\xef\x28\xef\x73\xce\xdb\xa0\x90\x3b\xee\xf5\x73\x97\x80\xa3\xfc\x78\x6a\xe8\xe1\x27\xde\x66\xd9\x54\x36\x8e\x76\xd1\xfb\xe8\xc3\xfb\x88\x74\x5d\xf3\xa1\x87\xf9\x18\xbd\xff\xf8\x5e\x62\x0d\x1e\xda\x08\x26\x03\xd2\x50\x59\x85\xff\xdf\x0f\xef\xff\x4a\x9e\x49\x9b\x36\x79\xdd\xed\xde\xff\x24\x65\xae\x4a\xbf\x7b\xef\xa0\x2c\xe9\x30\x27\xf8\x6f\x97\xaa\xa3\x6c\x7e\xe6\x60\xf6\x68\xf8\x6e\xbb\xdd\x32\xe9\xd5\xe4\x48\xe3\x7d\x43\xc9\x97\x38\x2f\x7b\x67\x7f\x17\x91\xe7\x2a\xcf\x04\xb9\xae\x77\xea\x39\x11\xe5\xe3\x32\x6d\x8e\xb9\xb7\x1f\x33\xdd\x17\xc0\xf9\xf9\x38\x89\x3a\xc1\xda\x08\x61\xe9\x3d\xbd\x3b\x93\x97\xf8\x6b\x9e\x75\x27\xbe\x32\xb1\x7b\xef\x34\x9f\x44\xa7\xc5\x24\xe2\x23\xec\x5d\xd5\xd4\x27\x52\xb6\xbb\x68\xc1\xf8\xff\x9a\x67\xd5\xd7\xfe\x2f\x0d\xda\x62\x81\xc9\x4c\xe7\x00\xcc\xf4\xa6\x77\x7a\xb0\xb9\x98\x96\xe4\x79\x4f\x1a\x43\x14\xdc\x5c\x71\x80\x7d\x57\x3e\x4d\x53\xd2\xd0\x6e\x12\x4d\xb3\xa6\xaa\x2f\xf5\x13\xf8\x08\x7b\x22\xee\xaa\x3a\xc6\x87\x8e\xa4\x56\x90\x3d\x2d\x9c\xbd\x97\xf4\xa6\x85\x03\x0e\xb6\xc5\x6d\x47\x10\xfa\x1c\xad\xb7\x2c\xf2\xe7\xc9\x14\x85\xe2\x10\x17\x08\x57\x03\x5e\x27\xcd\x00\x29\xf0\xed\xe4\x6c\x41\x96\x65\x16\x4d\x66\xec\xfe\x59\xf8\x91\x29\xb5\xbd\xca\xef\xff\x5b\xf1\x5a\x9f\xf2\xb4\x2a\xdb\xe8\x5f\x49\x71\x28\xf2\xf2\xd8\x7e\xdf\xeb\x41\xdb\xa4\xbb\xe8\xd2\x14\x1f\xa6\xd3\xcf\x3d\x4a\xfb\xf9\xa8\x40\xe3\x93\x04\x8d\x1b\x7a\xbc\x14\xa4\x99\xd2\xaa\xfb\x78\x1b\xda\xff\xf3\x5d\x4e\x0f\xf9\xcb\xc7\xbe\x59\xbd\x5b\x48\xba\x0f\xdf\xd3\xf3\x9e\x66\x19\xcd\xe2\xaa\xa6\x65\x3f\x07\x7e\xff\xb1\x5f\xfd\xbe\x0b\x27\xfc\xb5\x3a\x1c\xe6\x1f\x23\x49\x90\xfd\x79\x13\x11\x9d\xc6\xd5\x24\xba\x0e\x50\xe8\x9a\x0b\xbd\xa9\x35\xed\xf3\xf1\xbb\x01\xe0\xff\x57\x00\xa2\x5c\x93\x5d\xfb\x7c\xfc\xfe\xa3\xe8\xfa\xa9\x42\xf2\xac\xf7\xd8\x22\x6d\xc6\x67\x79\x67\x04\x20\x50\x6b\xe0\xa2\x97\xfb\xa9\x8f\xe6\x24\xbe\xe4\xcb\x57\xcd\xa5\x9d\x41\x3f\x8a\xd3\x38\x57\x55\x77\x62\x13\x33\x29\xbb\x9c\x14\x39\x69\x69\xa6\x3c\xb5\xaa\x7d\xb1\xe0\x8e\x0d\x79\x6d\x53\xa2\x16\x20\x43\xe3\x63\x36\x31\xe7\xed\x17\x38\xd3\x0e\x96\xfe\x2f\x73\xf2\xde\xc6\xa9\x8b\x4b\xeb\x82\xdf\x23\xf0\xf4\xd2\x08\xf0\x49\xa4\x7f\xae\x5c\x64\x12\x92\x22\x84\xce\x79\xe9\xae\x79\x3e\x9b\x23\x28\x69\x51\x5d\x32\x17\xca\x3a\x99\x61\xec\x96\xcf\xb4\xa8\x6a\xea\xc2\xda\x24\x5b\x4c\x28\xb4\x4c\xf3\xc2\x8d\x73\x40\x70\x8e\x05\x69\x5d\xed\xa1\x09\xca\xdc\xf9\xd2\xe6\xa9\x1b\x05\x13\x01\xf7\x89\xdd\x38\x0b\x04\xe7\x44\x49\xd3\xb9\x51\x56\x58\x35\x1d\x69\xdc\x18\x6b\x07\x46\x4c\xcf\x75\xf7\xea\xc6\xdb\x20\x78\x97\x96\x7a\x6a\x7a\x40\x30\x0e\x79\x71\x76\x63\x60\xdd\xd9\x9d\xe2\x82\x34\x47\x97\x12\xd0\x64\x96\xa0\x58\x6e\x78\xac\x37\xfb\x5a\xf2\xd6\x2d\x68\x54\xa5\x2b\xd7\x60\xa5\xc9\x0c\xeb\xcb\x86\x9e\xab\x67\x4f\x43\x96\x08\xce\xcf\x55\x75\x8e\xf3\xd2\x8d\x84\x69\x00\x43\xaa\x2e\x9e\xe6\x60\x5a\x50\x1d\x0e\x6e\x04\xac\xfb\xdb\xfc\x58\x12\xd7\x48\xa3\xc9\x0c\x53\x80\xb4\x3a\xba\x11\xd0\xfe\x6f\x48\xeb\xee\xcc\x39\xd6\xf9\xa7\xea\xec\x96\xf2\x1c\xeb\xfe\x43\x5e\x78\x30\xb0\xbe\xef\x72\x5f\x1d\x68\xef\x57\xc4\x65\xff\x68\x32\xc7\xfa\x3e\xab\xbe\x96\x45\x45\xb2\x98\x14\xee\xae\x9c\x63\x0a\x20\x31\xdd\x58\x98\x02\x5c\x6a\x3f\x0e\xa6\x03\x79\xb9\xaf\x5e\xdc\x28\x98\x0a\xf4\xb3\x77\x9c\xe6\x4d\xea\x93\x39\xa6\x0a\x0d\xad\x29\x71\x4b\x62\x81\xe9\x42\x43\x0f\x0d\xf5\x28\xd0\x02\x53\x87\xde\x14\x78\x85\xbe\xc0\x54\xa2\xf7\x43\xdc\x18\x98\x4a\x1c\x0a\xe2\x1e\x0d\x0b\x4c\x25\xfa\x05\x58\x7d\xaa\x4a\xea\x9e\xad\x16\x98\x42\x3c\x57\xc5\xe5\x4c\xbd\x43\x7c\x81\xa9\x84\xc0\xeb\xf5\xc9\x8d\x88\xe9\x85\x40\xbc\xd4\x6e\x34\x4c\x37\xfe\xd6\xa4\x55\xe6\x56\x8b\x05\xa6\x16\x7b\xe2\x47\x5a\xa2\x13\x84\x47\xf2\x4b\x74\x86\x20\x47\xb7\xcc\x97\x98\x3e\xec\x2b\xcf\x04\xb1\xc4\xf4\xa1\xc7\x38\x93\xc6\x83\x85\xe9\x04\x0b\xd8\xb8\x51\x30\x75\x48\xc9\x99\x36\xc4\x8d\x83\xa9\x02\x8b\xba\x3b\x31\x30\x1d\xd8\x57\x85\xdb\x9a\x2c\xb1\xee\xe7\x9b\x50\x6e\x1c\x74\x82\xa0\x2f\x9d\xf4\xd2\x5d\x88\x2b\x54\x05\x7a\x44\x1e\x85\x70\xe2\x61\x9a\xc0\xf6\x93\xe2\x82\x1e\x3c\xf5\x61\xfa\xc0\xf1\x52\x5a\x76\x1e\xaf\x69\x85\xe9\x05\xc7\x6c\xfc\x4d\xc4\x54\x83\x23\xfe\xf5\xd2\x76\xf9\xc1\xed\xdb\xad\x30\x15\xf1\xba\x43\x2b\x4c\x41\xf2\x32\xa3\x65\x37\x22\x18\x7c\x0e\x61\x88\x23\xed\x43\xdd\x49\x92\xd2\x7e\x26\x8e\xd9\x06\xb1\x1b\x17\x5d\x27\xe4\x69\x77\x69\xdc\x66\x63\x8d\xe9\xcc\x99\xd4\x71\x3f\x42\x3d\x3d\xb8\x46\xfb\x9e\xef\xc3\x3b\x71\xb0\x5e\xef\x7c\xc3\x7a\x8d\x75\x37\xcd\x72\x0f\x06\xba\x56\x38\x11\x9f\x08\xb0\x6e\x66\x7b\x38\x6e\x14\xac\x83\xbd\x6e\xef\x1a\xeb\xd8\xb6\xa3\x75\xbc\x27\xe9\x97\xaf\xa4\x71\xdb\x90\x35\xd6\xaf\x07\xd2\x76\xe3\xa8\x1b\xac\x77\xc7\xb1\x30\x7b\xc0\xa2\x11\x4e\x0c\x4c\x1b\x6a\x72\x69\xdd\x02\xd9\x60\xca\xd0\x76\x95\x7b\x2a\xdd\x60\xca\x70\xa8\x1a\x7f\x5b\x30\x7d\x60\xc2\x1b\xc5\xc4\xd7\x90\xb4\x1e\xc7\xc4\xb4\x83\xfe\x95\xa6\x6e\xb5\xdd\xa0\xab\x88\x13\x7d\x6e\xaa\x11\x23\xbc\xc1\xb4\x43\x62\xfa\x8d\xcd\x03\xa6\x1d\x75\x71\x69\xd9\x9a\xc7\x8d\x86\x06\x0a\xf2\x72\x14\x0f\x53\x12\xbe\x5a\x1c\x41\xc4\x54\xa5\xfa\x32\x82\x84\x69\xcb\xdf\x2e\xb4\xed\x72\xb1\xa8\x73\xa3\x62\x3a\x93\x97\x87\x6a\x04\x0d\x55\x98\xb4\xa1\xb4\x6c\x4f\x95\xa7\x1b\x30\x75\x11\x72\x19\x59\x40\x3c\x60\x6a\x53\x7d\x19\x45\xc3\x1d\xcc\x72\x0c\x6f\x8b\x29\x0c\x69\x9a\xea\xab\x5f\x47\xb7\xa8\x83\xc1\xf0\xfc\x1a\xba\x45\x67\x19\x86\xe8\xf1\xb9\xb7\xa8\x77\xc1\xb0\xbc\x2e\xfe\x16\x53\x19\x36\x77\x78\x97\x49\x5b\x4c\x5d\x1a\xca\x4e\xa6\x1d\x2e\x85\x3b\x74\xb0\xc5\x14\x46\x20\xb2\xd3\x43\x6e\x4c\xd4\xc2\xbc\xa4\x05\x39\x93\x51\xfd\x9e\xa1\x91\xbe\x63\xee\xee\xc0\x19\x1a\xe8\x2b\x28\x71\xae\xb3\x66\x68\x98\xef\x90\xbb\xa7\xe1\x59\x82\xce\xf5\xaf\x94\x6d\x3d\xb8\xb1\x30\xe1\xf7\x58\x69\x51\xb9\x67\x9f\x19\x1a\x20\xfc\x4a\x9a\x32\x2f\x8f\x23\xc2\xc3\x44\x5f\x17\xa4\xf4\x54\x86\x1a\x77\x52\xd0\x32\x73\xc7\x30\x67\x68\x9c\xb0\x21\x65\x56\x39\x63\x8b\x33\x34\x4a\x98\x56\xe7\x33\x75\x3b\x59\x33\x34\x54\x78\x26\xc7\x92\x7a\x70\xd0\xe0\xb7\x98\x75\xdc\x43\x73\x86\x46\x0c\x25\x9e\x6f\x70\xce\xd0\xb8\x61\x43\xbb\xaf\xd4\xc7\x26\xee\x0d\x56\x75\xdd\xf7\x73\xea\x09\x3a\xcf\xd0\xe0\xe1\xa1\x2a\xd8\x36\xa4\x57\xb7\xd0\x28\xa2\xc0\xf4\xea\x32\x1a\x4a\x14\xf6\x40\x9e\xf3\x73\x23\xe3\xb1\x24\x86\x7c\xaa\x9a\xfc\xe7\xaa\xec\x3c\xe8\x78\x88\x31\x73\x3a\x39\x33\x34\xc2\xb8\xbf\x14\xc5\xa9\x6a\xdc\x4d\x44\xa3\x8c\x7b\xea\x36\x75\x33\x34\xca\x98\xf6\xd2\x38\xe4\x29\xe9\xdc\xdd\x80\x06\x1b\xbb\xd3\xe5\xbc\x6f\x7d\x1a\x8a\x46\x1a\x05\x9a\x57\x41\xd1\x60\xe3\x89\x94\x99\x7f\x8e\x9b\xa1\x01\x47\x86\xe7\x9b\x53\x67\x68\xd0\x91\xa1\xf9\x1a\x87\x29\x09\x43\xf2\x36\x0d\x8d\x39\x72\x5f\x21\x64\x1a\x9f\xa1\xe1\x47\x0d\xdf\xdb\x54\x34\x0e\xa9\xa1\x7b\x9a\x8c\x86\x24\x35\x64\x7f\xd3\x31\x2d\x3a\x16\xd5\xde\xad\x78\x68\x68\xf2\x6b\x43\x4b\xf7\xae\xd8\x0c\x0d\x4b\x76\xa4\xfd\xe2\x8c\xc6\xcd\xd0\x80\xe4\x21\x2f\x3c\x71\x97\x19\x1a\x8d\xdc\x37\x39\x3d\xa4\xc4\x63\xd1\xd0\x80\x64\xef\xda\x70\xef\xd6\x89\x87\xc6\x24\x33\xd2\x9e\xf6\x95\x67\xfd\x34\x43\x23\x93\x35\xa9\x69\x93\x16\xb9\xbb\xa7\xd1\xf0\x24\xdb\x59\xf4\xef\xfa\xcd\xd0\x28\x65\x91\x97\xce\xf5\xff\x0c\x8f\x50\x9e\x2a\x8f\x13\x80\x46\x28\xeb\x4b\x7b\xaa\xdd\xfb\x5e\x33\x34\x44\x79\x69\x3d\xa2\xc3\x3a\xf8\xb8\xf7\x08\x0d\xeb\xda\xb6\xf2\x4c\x8c\x68\x94\xb1\xc7\x88\xf7\xaf\x31\x29\xea\x13\xd9\x7b\x66\x64\x34\xd6\x68\x62\xfb\xdc\xed\x19\x1a\x75\x94\x14\xf8\x69\x1c\x27\x2a\x1a\x73\x80\xa8\xfe\x9a\xd1\xf5\x81\xe4\xbd\xeb\x9a\x7c\x7f\xe9\xdc\x7b\x16\x33\x34\x02\x69\xe3\xfb\x79\x40\x35\xa2\x64\xe1\x2a\xea\xd6\x0b\x34\x22\x49\x5f\x6a\x52\x7a\x70\xf0\x9d\x4d\x7e\xee\xca\x6f\x35\xd1\x50\xa4\x42\xf5\x58\x6b\x34\x1c\x59\x54\x47\xcf\xe6\xf0\x6c\x8d\xee\x75\x16\x9e\x0d\xd5\x19\x1a\xbd\xec\xab\xf1\x6c\x27\xcf\xd0\xf0\x65\x49\xbf\xc6\x5f\xf3\x32\xab\xbe\xba\xf1\x70\xcf\x35\xad\x3c\x26\x10\x0f\x63\x12\x77\x80\x71\x86\x46\x31\xbd\xee\x26\x1a\xc4\xec\xeb\xf0\xb0\x85\x6e\x67\xb0\xa3\x6e\x6e\x1c\x4c\x17\xe8\x8b\x17\x07\x8d\x5b\xb6\xd4\xa3\xac\x68\xcc\xf2\x50\x54\x75\xfd\x1a\x67\xee\x03\x47\x74\x86\x86\x2e\x05\xa2\x5f\x18\x68\x04\x53\x60\xfa\x0f\x41\xcc\xf0\x50\xe6\x50\xa9\x1b\x11\x0d\x67\x72\x44\x6f\x67\xa3\xd1\xcc\xb4\xa1\x59\xde\xf5\xeb\x20\x4f\x2b\x31\x2d\xe1\x57\x47\x3c\x96\x16\x8f\x67\x5e\xba\x82\x36\xee\x79\x18\x0d\x65\xf2\xc3\xb8\x4e\x1c\x34\x86\x99\x56\xe7\xba\xa1\x6d\xeb\xe9\x3c\x34\x88\x49\x49\xe3\x9f\xc4\xd1\x10\x26\x43\xf1\x1a\x6d\x34\x80\xd9\x55\x5f\x7d\xed\x42\xe7\x9a\x8e\x74\xee\xe9\x05\x0d\x5b\xb6\x99\x7f\xd7\x68\x86\x46\x2d\x4f\xa3\x58\xa8\xed\xb8\xec\xd9\xe1\x6f\x0f\x8b\xe8\x2e\x08\x3b\x91\xdb\x76\xb4\xf1\x55\x88\xfb\x29\x17\xb6\x74\x29\xf6\x6e\xa5\x42\x63\x96\x1c\x71\x15\xcf\xdc\x68\xb8\x9f\xd2\xa3\xad\x7d\x68\xb8\x73\xd2\xa3\x6d\x7c\x68\xe8\x22\x45\xde\xee\x8d\x7d\xbb\xe5\x33\x34\x6a\xd9\xd0\x63\xde\x76\xfc\x0a\xc0\x08\x3a\xba\x73\x5e\x54\x97\x6c\xf4\x7c\xcd\x0c\x0d\x43\x72\x5c\xff\x29\x9b\xd9\x16\x53\x84\xae\xa1\x34\x4e\xab\x32\xf7\x59\x96\x2d\x7e\x7c\x8a\xd2\x38\xa3\x69\x9e\x5d\x2a\xe7\x91\x4d\x3a\x4f\x50\x63\xe1\xe4\x72\x8e\x06\x4a\x7b\xfb\xec\x3d\x4a\x35\x47\xa3\xa5\xbd\x75\x1e\x41\x43\x97\x21\xf4\x99\x16\x1e\x8f\x69\x8e\x86\x4d\x7b\xd5\x71\x63\xa0\x2b\x11\xd2\xba\x63\x29\x73\x34\x5c\x4a\x0a\xea\x9e\xc2\xe7\x68\xf8\x92\xfe\xed\xc2\x6e\x82\x3b\xbb\x77\x8e\x46\x30\xbf\xe4\xa5\xf3\x1c\xcb\x1c\x0d\x5f\xfe\xed\xe2\x59\x97\xe2\x47\x77\x6b\xe2\x76\x68\xe7\x68\xdc\x72\x9f\xb7\x27\xf7\x7e\xe5\x1c\x8d\x58\x7e\x29\x7d\x91\x92\x39\x1a\xb0\xdc\x93\xfd\x6b\x7c\xa8\x9a\xf3\xa5\x70\x9e\x66\x99\xa3\xf1\xca\xce\x1d\xf7\x9d\xaf\x0f\xd8\x61\xeb\x7d\x41\xd2\x2f\xde\xe5\xf9\x1c\x0d\x53\xee\xdd\x73\xed\x1c\x0d\x4d\x92\xba\x76\x8e\x85\xc3\xc3\x01\x3b\xbf\x4c\x1b\x4f\x90\x62\x8e\x06\x24\x4f\xd5\xa5\xf1\x1d\x7b\x9e\x2f\x66\xd8\x11\xf2\x82\x9c\xdd\xfd\x8a\x46\x24\xb3\x4b\x5d\x78\xe3\x91\x73\x34\x1e\x59\xe7\xc7\xe3\x6b\xbc\x27\xee\x58\xc3\x1c\x0d\x48\xb6\x69\xde\xb6\x55\xe3\x36\x75\x68\x34\x72\x9f\x77\x69\xe5\x5e\x49\xcd\xd1\x50\xe4\xbe\x73\x1e\x55\xc2\x11\x5e\xf6\x6e\xfd\x46\x11\x5e\x9d\x43\x35\x49\x08\xd6\xfa\xbf\x3a\xad\x9b\x03\xa1\xb9\xec\x9d\xca\x36\x4f\xf6\x19\x8e\x72\x1d\x02\xbb\xf1\xe0\x6c\x38\x1a\x42\xcd\x53\x1a\x17\x55\x51\xb8\x6d\x35\x1a\x39\x55\x68\x71\xd7\x5b\x6d\xf7\xc0\x43\x03\xa7\x34\xbb\xa4\xfc\x6a\xa0\x13\x0d\xdd\x6f\x67\xa9\x31\x02\xb6\x12\xe6\x68\xc8\x54\xa0\x8f\x6d\x63\xcc\xd1\xe0\xe9\x99\x96\x97\xf8\x44\xce\xfb\x4b\x73\xf4\xcc\x1d\x68\x10\xf5\x5c\x65\xa4\x18\x59\xa2\xcf\xd1\x58\x6a\xe5\xbc\x5f\x41\xe7\x68\x20\xf5\xd8\x10\xcf\xe0\x42\x83\xa8\xed\xa5\x64\xe6\xc9\xed\x33\xcf\xf1\x83\x9d\x32\xf7\x89\x1b\x0d\x3d\xde\xd9\xa3\xf1\xbb\x6f\x4e\x3c\xf4\x1c\x78\x8f\x07\x6e\x12\x3a\x91\x51\xcd\xd9\xff\x95\xa6\x9d\x38\xa5\xe7\x39\xe0\x33\x47\xa3\xaa\x1a\xb6\xc8\x56\xe1\x24\x80\x29\x8f\x46\x20\x40\x7d\xd1\x98\xab\x46\xc4\xb7\x59\x31\x47\xcf\x88\x6a\xe8\xa3\x63\x00\x0d\xe2\x6a\x24\xbc\xdb\x2d\x73\xfc\x00\x69\x93\x93\xf2\x58\xd0\x11\x5c\xfc\x0c\xa9\xc4\xf5\xb6\x1c\x0d\xed\x2a\xd4\x91\xae\x43\xa3\xba\x0a\xd9\xa7\x35\x68\x50\x37\xad\xca\xb6\xf2\x98\x63\x3c\x94\x7b\xa9\x69\x23\x2e\x28\x3b\x11\xd1\xd9\xf8\xb2\x1f\x43\x43\x4d\x53\x6f\xd6\xfc\x22\x45\xcf\x19\xf6\x68\x23\xbd\x88\x69\x10\xc3\xf3\x85\x6d\xe7\x68\xd8\x96\xa1\x79\x16\x20\x43\xc8\xf6\xf7\xac\xf0\x57\x4a\x6e\x21\xea\xc0\xae\xea\xff\xba\x35\xea\x09\xab\x44\x82\x97\xa4\xd6\x32\x4e\x74\xa4\x8e\x4f\xf9\xf1\x54\xb0\xe5\xba\xb8\x5c\xdc\x1c\xf7\xe4\x43\x32\x89\xc4\xff\x93\x57\x41\x55\x66\x2a\xed\x26\xe7\xfb\x7f\xa5\xc5\x33\xed\xed\x42\xf4\x6f\xf4\x42\xdf\x4f\x22\xf5\x61\x12\xfd\x4b\x93\x93\x62\x62\x24\xc9\x82\xec\x2c\x39\x3b\xfa\x55\xce\xe9\x72\xfe\xb0\xda\xcc\x96\x0b\x90\x3c\xe6\xbb\xc5\x62\xf1\x88\xe6\x6e\xfa\xee\x70\x38\x48\x0e\xf5\xa4\x35\x68\xaa\x1a\x8d\x79\x90\xa4\x06\x70\x05\xbe\x6a\x8c\xe9\x09\x6c\x88\xd0\x28\xc9\xde\x86\xec\x37\x8f\x32\x45\x0d\xcc\x63\x00\xf3\x4f\xed\x58\xfe\x16\x3d\xa9\x94\x24\x31\x5f\xac\xe6\x9b\x14\x25\x01\x52\x21\x40\x3a\x0c\x5d\xe5\xa4\xea\x4e\x79\x29\xb2\x4d\x3d\xc2\xef\xab\xfa\x85\x25\xc7\x88\x86\xeb\xb1\xe9\xa5\x8d\x1b\x76\x92\xa4\xaf\x1b\x40\xc7\xd5\xe1\xd0\xd2\x6e\x17\xc5\x73\x95\xef\x08\xc9\x88\xa4\x72\xb4\x88\x8c\x01\x66\x32\xa7\x73\x9e\x65\xc3\x2d\xda\x94\x34\xd5\xa5\xa5\x05\x4f\xdb\xf2\x34\xcd\x3b\x7a\x7e\x22\x4f\x2c\x35\x01\x5e\xc8\x8b\xf2\xf3\x31\x6e\x68\x5b\x57\x65\x9b\x3f\xd3\x09\xbb\xe0\x7e\xba\x9c\xf7\x25\xc9\x8b\x48\xe2\xab\x2f\x4f\x92\x19\x3d\x77\x19\x4f\x45\xa2\xe5\x33\x78\xc4\x53\xbf\xf0\xfa\x7a\xd5\x12\x29\x29\xc4\x88\x6a\x48\x96\x5f\xda\x5d\xb4\x56\x12\x61\x90\x03\x2b\xbf\xf8\xae\x3d\x8f\xd4\xad\xa5\xbe\x19\x1f\x0d\xb8\xfa\xe3\xd9\x55\xbe\xcb\xb2\xec\xd1\x6e\xc6\xd2\xb0\x00\x0d\x29\xe5\x9d\x6e\x52\x14\xd1\x74\xde\x46\x94\xb4\x34\xce\xcb\xb8\xba\xb0\x41\x10\x57\x21\x50\x23\x20\x50\x74\xfc\x14\x03\x26\xe3\x95\x4a\x33\x26\xb2\x6c\x71\x8d\x63\xf3\x68\x34\x17\xc6\x4b\x7c\x93\x19\xc0\xe4\x67\x95\x27\x06\x34\x5a\xde\x4c\x97\x22\xa1\x54\x69\x65\xdb\xc4\x55\x59\x70\x8b\x36\x5c\x6b\x27\xfb\xb6\x2a\x2e\x1d\xbb\xd6\x2e\xbb\x8d\x93\x57\x1d\x52\x1b\xf9\x8a\x60\xb2\x9b\x58\x94\x9a\xc9\xc5\x98\x25\x2b\xf2\x7a\x17\x35\x34\xed\xa0\x71\xc5\x32\xdc\x48\xde\xf8\x48\x25\xfd\x12\x50\x66\xa3\x43\x8a\x06\x53\x30\x34\xa3\xed\x48\x97\xa7\xa0\x11\x52\xd7\x4c\xdd\xd3\x32\x77\x59\x89\xb8\x06\xb6\xc1\x38\xf9\xb1\xa9\x0a\x95\x56\x8b\x5b\x30\x34\x23\xd6\xf4\x34\x9b\x44\xd3\xd3\xbc\xff\xcf\xa2\xff\xcf\xb2\xff\xcf\xaa\xff\xcf\x7a\x12\xf5\x85\x32\x8d\x48\x5f\xd2\x17\x9c\xd6\xe3\x26\x5a\x26\x01\x58\x61\x49\x00\xa6\x33\x67\xbe\xb1\xe9\x69\x16\x4d\xd9\xe1\xd4\x9e\x81\x59\xa4\x7e\xce\xc1\xe7\xf9\xf0\x79\x01\x3e\x2f\x86\xcf\x4b\xf9\xb9\xb7\x46\xa7\xe5\x50\xb0\x02\xf0\xab\xe1\xf3\x1a\x7c\x5e\xcb\xcf\x80\x15\xc5\x09\xcb\x93\x32\x7c\x56\x9c\x00\x46\x06\x3e\x06\x36\xa2\x81\x87\x81\x85\x9e\x96\xe2\x01\xb0\x20\x39\x18\xa4\x3c\x9a\x52\x41\x5a\x99\xcd\x66\x83\x77\xeb\xd0\x8f\xa1\xe3\x75\x36\xa4\xd2\xbb\x4b\xa7\x0c\x34\xfa\x76\x2b\x22\xa1\xd2\x34\x5d\xa4\xf5\xea\x77\x8a\x3b\x5d\x63\x75\x2d\x85\x2d\x9d\x05\xb4\x74\x09\x78\xbf\x55\x6f\xa0\xf6\x61\x1d\x1f\x05\x76\xbb\xca\xcd\x08\xfb\x54\x64\x95\x04\x00\x0b\x30\xe5\xb1\x3e\x9e\x5b\x10\xb0\x85\x0b\xa5\x05\x30\x0d\xe5\x12\xca\x80\xb5\xc1\xf4\x49\x1f\x00\xc4\x8a\xb5\xc1\x84\x80\x34\xd6\xba\x9d\x10\x10\x83\xbb\x52\xeb\x9e\x4a\x94\x68\xdd\x50\xc8\xdc\x49\x8e\x49\x04\xd2\x5c\x83\x4f\x72\xa0\x2c\x50\xb3\xb3\x14\xe4\x45\x8e\xae\x0f\xd1\x39\x2f\xf9\xac\x1f\xed\x36\xeb\x87\xfa\xe5\x23\xab\x73\xa8\x5d\x93\xd0\xac\x67\x4f\x25\xdb\x91\xbd\x86\xa7\xe1\x1c\xba\xec\x4c\x9a\x2f\x93\x48\xe5\xf6\x1c\xb2\xb1\xcd\x79\xfe\x35\xcc\x55\x48\x0f\x0f\x74\x21\x09\x30\x2f\xb3\x5f\xc5\x31\x7c\xf6\x97\x70\xdf\xfa\x8f\x1a\x14\xcf\xd5\x6b\x82\xb1\xaf\x1a\x1c\xbf\x3d\x69\x01\xf2\xcf\x1a\xa4\xb8\xf4\x68\x81\x8a\xef\x1a\x6c\x59\x7d\x6d\x08\xef\xd6\xaf\xa7\xbc\xa3\x2c\x55\x1b\x4b\x0f\xd3\x7f\xd7\x9b\x53\x7d\xa5\x4d\x4a\x5a\x3a\x10\x06\xd9\x22\x55\xa9\x86\x73\xa9\x6b\x0f\x8e\x2a\xd5\x1b\x4a\x6a\x76\x19\xf6\x67\x1c\x69\x28\xd6\xb0\xce\x17\x99\xed\x0c\x31\xab\x0c\xa2\x6e\x72\x95\x83\x57\x5f\x5a\x48\xcf\x5f\x83\xc3\x56\x11\x0f\xeb\x64\x9b\x68\x44\xdb\x4b\x9a\xd2\xb6\xd5\x89\xa6\x9b\xf5\x22\xd3\x89\x0a\x38\x8c\xe8\x7e\xb5\x9c\xa7\x1a\xd1\xbc\x3c\x54\x3a\xc5\xd9\x26\x79\x38\xe8\x14\x7b\x20\x8c\xdc\x72\x35\x5f\x6f\x35\x72\xe2\x0a\x83\x06\xf6\x40\xd6\xd9\x62\xaf\x53\x14\x70\x08\xd1\xf5\x7a\x35\x33\x78\xcc\x48\x79\x34\xa0\xc8\x76\xb9\x5c\xce\x75\x9a\x1c\x0c\x21\xf9\xb0\x5c\xac\x16\x72\x6c\x4f\xf7\x47\xb4\x7b\xa4\xff\x6d\x0f\x37\xa3\xe3\x06\x7c\x50\x15\x82\xa6\xf7\xe0\xfe\xa8\xf5\x1f\x02\x9f\x1d\x0e\x49\xf6\x00\xab\xb1\x3b\x12\x41\x4b\x67\x74\xbe\x5f\x80\x6a\x54\x8f\x62\x75\x6c\x69\x76\xd0\x9a\x62\x74\x2d\x82\x43\x0e\xd9\x76\x70\xb7\xf7\x47\xad\x8f\xc7\xac\x13\x01\x08\xfe\x6a\x0e\x1b\x9a\xee\x57\xa0\x1a\xd0\xeb\x18\xf8\x3c\xa3\x19\x85\xb5\x58\xdd\x8f\x60\xd1\xe5\x7e\xbb\x57\x1a\xcb\x92\xd8\xf1\xf3\x3d\xd0\xf6\xaa\xc9\x64\x0b\xbd\x81\x1d\xcb\x1d\x1c\x25\xc6\x3a\x45\xcb\x11\x6d\xad\x4e\xaa\x62\x12\x5d\x0a\xcb\xcf\x48\xfc\x4e\x46\x55\x44\x3d\x62\x55\x44\x17\x8e\x2f\xc8\xe8\x94\x24\xa2\x52\x31\x96\x4f\xe3\x52\xb2\xa4\x5b\x5a\x02\x4e\x1e\xe3\x8b\xc4\x8c\xd7\x82\xbc\x5c\x2a\x12\xc1\x91\xf9\xa2\xd7\x85\x2a\xea\xe5\x5f\xe2\x95\x5c\xe4\x8e\xd2\x7b\x2a\x72\xff\xda\x5a\xd6\xd5\x88\x25\x81\xb6\x32\x13\xf5\xad\x94\x74\xb2\x30\x79\xce\x07\x79\x66\xd9\x24\xca\x90\xfc\xb9\xc3\x9a\x5c\x02\x76\xb6\x4b\x0d\xf2\x79\x6b\x1e\x87\x10\x4c\xa0\xc7\x90\x15\x20\xf4\x2f\x99\x79\x77\x28\x2a\xd2\xf1\x79\x5a\x66\x5c\x64\x2b\xd5\xb5\x50\x31\x74\xfd\xf9\x2e\x2d\x28\x69\x00\x96\x35\x97\x0f\x5f\x07\x7c\x5a\x14\x79\xdd\xe6\x2d\xaf\x07\x9b\x7e\x79\xea\x41\x83\x51\xe1\xe6\x68\x6d\x9e\x3d\x24\x9a\xa7\xc3\x52\x73\x66\xa4\x23\x71\xd5\xe4\xc7\xbc\x24\x45\xcc\x13\x75\x4e\x22\x33\xaf\xba\x5c\x61\x9e\x68\x51\x3b\xc6\x10\x8f\x7c\x69\x53\x6a\x5e\xe6\x2c\xf1\x5b\x7b\x36\xfd\xa8\x2d\x8f\xc4\x8c\x4d\xf6\x43\xe6\x4e\xdd\xc7\xea\xc7\x9c\xb1\xbc\xe1\xae\x26\xe6\x46\x6e\xa6\x2b\x6d\xe0\x2b\xbd\xb4\x87\x3d\xa8\xaf\x2a\x76\x05\x69\xbb\x38\x3d\xe5\x45\x36\x89\x40\x49\xed\x2a\xb8\x40\x14\x91\xd0\xd7\x31\xe6\x01\x96\xf4\x37\xc1\x27\xf9\x7a\x00\xf8\x34\x78\xa3\x76\x78\x4d\x4f\x13\x1f\x18\xcf\x1d\xba\xc9\xe2\x45\x84\xc8\x11\x96\xb0\x12\x88\x22\x1a\xad\xc2\xfc\xdf\xff\x65\x9e\xcc\x96\xd1\x5f\x92\xe4\x5f\x92\xef\xd5\x14\xa1\x70\xe3\x86\x3e\xd3\xa6\xd5\xe8\x4d\xeb\x4b\x51\x00\x87\xd7\xb0\x31\x33\xd4\xc8\x24\x8f\x98\x6b\x0c\x83\x6f\xca\x42\x81\x4e\xb7\x74\x22\x71\xb3\x68\x8a\x06\x03\xd1\x65\xc4\xf2\x9f\xda\x40\x2e\x09\xc3\x76\xeb\x75\x69\x19\x6c\x21\x98\xb3\x4f\x20\x90\xb7\x7b\x3c\x7d\x22\x99\x10\xdb\x26\x9e\xf6\x72\x08\x6f\x73\x05\x11\x6f\x6b\x15\x19\x6f\x63\xbd\x94\x00\xa1\xc8\xd0\xc3\x5e\x03\x23\xa6\x8d\xb2\xcd\x24\xcb\x1a\xe9\xd5\x79\x17\xa3\x66\x2e\x4c\xff\x54\x14\xf6\x16\xc0\x9f\x68\x59\x54\x93\xe8\x4f\x55\x49\xd2\x6a\x12\xfd\x81\xed\x3a\x92\x76\x12\xbd\xff\x43\x75\x69\x72\xda\x44\xff\x46\xbf\xbe\x07\x0f\x05\x00\xea\xba\x29\x9c\xd7\x2f\x32\xa4\x6c\xdb\x57\xe5\x6b\x6e\xe6\xab\x25\x75\xad\x4a\xb7\x87\xf9\x61\x89\x47\xaa\x45\xb5\x5f\xf6\xd9\x0d\xb5\xfa\x3c\xf3\x05\x52\xdf\x42\x8f\x8c\xc3\x24\xd6\x79\xd9\xd2\x2e\x4a\x58\x7c\x37\x4a\x8c\x1d\xb2\xe9\x7c\xf5\x51\xed\xc6\x85\x22\x80\x96\x59\xad\x33\x9f\xf2\x90\x1b\x07\xa6\x7f\xe1\xe2\x56\xbe\x94\x62\x7e\x93\x11\x12\xb1\x9b\x63\x5b\x72\xc5\xc1\x56\xce\x59\x66\x1c\xc5\xe4\x6c\x71\xed\x06\xde\xd7\xaa\xc9\x78\x02\xe8\x5d\x24\xf2\x40\x17\x85\x2a\xe8\x3d\x0a\xf9\xbd\xff\xe0\x52\x99\x55\xff\xcf\xb1\xed\x91\xa6\xa9\x57\x99\xfa\xe6\xdb\x7a\x6c\xca\xdc\xf9\x7e\xc5\xa3\x19\x86\xa8\x1b\xca\xf8\xc6\x79\x05\x4f\xcb\x20\x5c\x29\x8b\xdf\x13\x69\xd3\xa6\x2a\x0a\x95\x3b\xfa\x4c\x5e\x94\x48\x17\xcb\x44\xdf\x58\x88\x5f\x77\x11\x87\x57\xbb\x6c\xbd\xe7\x95\x1b\xef\x42\xf8\xa7\xad\x99\xd6\xc9\x12\x56\xdf\x1a\x10\xa0\x20\xfe\x3f\xe6\xb2\xea\x8c\x48\xdf\x74\xb3\xd2\x9d\x3f\x8c\xca\x76\x3b\x1f\xa1\xb2\xdd\x8c\x53\x99\xcd\x93\x64\x84\xcc\x6c\x66\xd0\x19\xe0\xe2\x43\x71\xc9\xb3\x5f\x5b\x86\xd3\xa6\xfa\x0a\x2d\xbf\x40\x8b\x0d\x6a\x62\xc9\x34\x1b\x16\x31\xd3\xb4\x2a\xe2\xe2\x18\xcf\x26\x91\xfa\x99\x80\xdf\xf0\xfb\x7c\xf8\x0d\x7e\x2e\x26\x5c\x2e\xec\x8f\xe5\xf0\x7d\x35\xfc\x5c\x0f\x3f\x37\xc3\xcf\x87\xe1\xe7\x56\xd1\x38\x67\x8a\x95\xfe\x67\x02\x7e\xc3\xef\xf3\xe1\x37\xf8\xb9\x80\x64\x96\xc3\xf7\xd5\xf0\x73\x3d\xfc\xdc\x0c\x3f\x1f\x86\x9f\x03\x2b\xed\x59\xb1\xd2\xff\x4c\xc0\x6f\xf8\x7d\x3e\xfc\x06\x3f\x17\x90\xcc\x72\xf8\xbe\x1a\x7e\xae\x87\x9f\x9b\xe1\xe7\xc3\xf0\x73\x60\xe5\xa5\x55\xac\xf4\x3f\x13\xf0\x1b\x7e\x9f\x0f\xbf\xc1\xcf\x05\x24\xb3\x1c\xbe\xaf\x86\x9f\xeb\xe1\xe7\x66\xf8\xf9\x30\xfc\xdc\x1a\xfb\x81\x30\x5b\x77\x3f\x54\xf0\xcd\xcc\x71\x4d\x87\x5a\xf8\x0f\xd2\x48\xb0\x16\x36\xb9\xe3\xdb\x15\x60\xf7\xdd\x04\x98\x41\x80\xed\x6c\xba\xe6\xff\xb7\xb1\x00\x13\x08\xf8\xb0\x98\x2e\xc4\xff\x99\x80\x5b\x08\x07\xf6\x57\x24\xf3\xb0\x78\xbd\x76\xd6\xb7\x81\x70\xab\x07\x67\x75\x6b\x0d\xce\x6a\xdf\x0a\x16\x2f\xdd\xcd\x5b\x42\xb8\x85\xbb\x75\x0b\x08\x37\xb7\x5a\xa7\x8b\xdb\xdd\x3a\x4d\xea\xee\xc6\x31\xc7\x5a\xf4\xa1\x54\x4c\xbb\x0f\x39\xd4\x0c\x42\x79\x3a\x92\x43\x27\x10\xda\xd3\x9b\x0c\x7a\x0b\x81\xed\x2e\x65\x30\x0f\x10\xc6\xd3\xaf\x0c\x78\x03\x81\x3d\x9d\xcb\x80\xd7\x1a\x30\xde\xfa\x15\x84\xf1\x74\x33\x03\x5e\x42\x60\x4f\x5f\x33\xe0\x05\x04\xb6\x3b\x9c\xc1\xe8\x1d\x34\xd2\x76\xad\x9f\x46\x9a\xae\xf5\x12\x9c\x3b\x15\x50\x7b\x92\xfa\x21\x2c\x14\xa6\x1e\x3d\xd0\x0c\x00\x79\xb5\xa3\x07\x4e\x00\xb0\x57\x39\xda\x93\x50\x0e\x0e\x8b\xe9\x46\x7b\x12\xba\xc1\x41\xbc\xaa\xd1\x9e\x84\x6a\x88\x00\x91\x4f\x3c\xed\x49\x68\x86\x80\xc5\xdb\xbd\x02\x20\x5e\xbd\x68\x4f\x42\x2f\x38\xac\x57\x2d\xda\x93\x50\x0b\x0e\x8b\x69\x45\x7b\x8a\xb5\x6e\x19\x69\x35\xec\x9d\x91\x46\xc3\xbe\x41\x54\x82\x9f\x5e\x93\x4a\xa1\x07\x1f\x6d\xdd\x90\xd0\x33\x1b\xda\xa3\x24\x12\x2b\xb1\xb1\x3c\xda\x22\xb0\xb6\x36\x92\xad\x36\x02\xf6\xc1\x86\xf5\xe8\x8f\x40\xda\xd8\x48\x1e\x45\x12\x48\x6b\x04\xc9\x25\xad\x95\x0d\xeb\x51\x2d\x81\xb4\xb4\x91\x3c\x3a\x26\x90\x16\x36\x92\xad\x6c\x02\x16\xeb\xf0\x51\x59\x21\xfd\x3e\x2a\x2a\xa4\xd7\x43\x43\xf9\xf7\xf1\x51\xdf\xec\xa4\x5a\x3b\x08\x32\x82\xaf\x2a\xd7\x97\x4a\x6c\xdc\xe8\x10\x33\x7d\x4d\xa6\x75\xbf\x0e\x99\x68\x90\xfa\xf8\xd0\x20\xb7\xc6\x62\xd1\x2c\x7f\xd0\xca\xf5\x71\xa0\x01\x6e\x34\x40\x5d\xf7\x35\xc0\xb5\x0e\x68\xb5\x72\xa5\x95\x2f\xdd\x8d\x5c\x6a\x80\x0b\x77\x1b\x17\x1a\xe0\xdc\x6a\xa3\x21\x78\x77\x1b\x75\xf9\xbb\x9b\x08\x3d\x28\xdd\x85\x42\xc0\x66\x1a\x98\xa7\x53\xa1\x0f\x85\x3b\x51\x36\xf8\x56\x83\xb6\xbb\x17\x78\x51\xb8\x1b\x65\x43\x6f\x34\x68\x4f\x47\x03\x3f\x4a\x73\xa4\x6c\xa0\x95\x06\xe4\xe9\x72\xe0\x49\xe1\xae\x94\x0d\xbd\xd0\xa0\xed\xce\x07\xbe\x14\xee\x4c\x21\x7d\xa0\x77\x81\xbf\x7e\xbd\xbf\xf8\xdc\x69\x40\x0d\xee\x94\xe6\x4f\x21\x50\x33\x08\xe5\x55\x95\xc1\xa1\x42\x3d\x2a\x1b\x7a\x0b\x81\x31\x45\x51\x2e\x15\xea\x53\xd9\xc0\x1b\x08\xec\x55\x13\xe5\x54\x41\xaf\xca\x86\x59\x41\x18\xaf\x92\x28\xb7\x0a\xf5\xab\x6c\xe0\x05\x04\xc6\x54\x44\x39\x56\xa8\x67\x85\x88\x5e\x93\xbc\xbf\x72\xad\x97\x10\xfd\xd0\x7d\x2b\xcc\xb9\x42\xc1\x67\x08\xb8\x47\x63\x74\xef\xca\xe7\x5e\x61\x68\x5b\x04\xcb\xd6\x21\xcd\xbf\xf2\x39\x58\x18\xd6\x06\xc1\xf2\x68\x95\xe6\x61\x21\x2e\x16\x06\xbc\x42\x80\x3d\x7a\xa6\xf9\x58\x3e\x27\x0b\xc3\x5a\x20\x58\xb6\xe6\x69\x5e\x96\xcf\xcd\x42\xfb\x12\xeb\xca\x31\xbe\xb0\xfe\x4f\xae\x0a\x1f\xdf\x23\x36\xf9\xe6\xe0\xa4\xd7\xd9\x62\x95\x7b\x9d\x2d\xc6\x6a\x90\xb3\xc5\x1a\x18\xe4\x6c\x0d\x6c\xe1\xce\x56\xdf\x82\x20\x67\xab\x6f\x75\x90\xb3\xd5\x4b\xca\xe7\x6c\xf5\x42\x0d\x72\xb6\xfa\x8e\x08\x72\xb6\xfa\xfe\xf3\x39\x5b\x7d\x57\x07\x39\x5b\xbd\x58\x43\x9c\xad\x73\x16\xe4\x6c\x29\xb0\x30\x67\x4b\x81\x87\x39\x5b\x12\xdc\xeb\x6c\x49\xa0\x30\x67\x4b\x42\x87\x39\x5b\x12\xda\xeb\x6c\x49\xa0\x30\x67\x4b\x42\x87\x39\x5b\x12\xda\xeb\x6c\x49\xa0\x30\x67\x4b\xf5\x41\x88\xb3\x25\x81\xfd\xce\x16\x83\x1a\x75\xb6\x14\x54\x90\xb3\xa5\xa0\x83\x9c\x2d\x09\xed\x73\xb6\x24\x4c\x90\xb3\x25\x81\x83\x9c\x2d\x09\xec\x73\xb6\x24\x4c\x90\xb3\x25\x81\x83\x9c\x2d\x09\xec\x73\xb6\x24\x4c\x90\xb3\xa5\x44\x1f\xe0\x6c\x49\x58\xaf\xb3\x75\xce\xae\x72\xb6\x00\xf8\x35\xce\x16\x40\xbb\xc6\xd9\x1a\xd0\x02\x9c\xad\x01\xf8\x1a\x67\x6b\xc0\xba\xc6\xd9\x1a\xb0\x02\x9c\xad\x01\xf8\x1a\x67\x6b\xc0\xba\xc6\xd9\x1a\xb0\x02\x9c\xad\x01\xf8\x1a\x67\x0b\xf4\x65\xb8\xb3\x35\x20\xdd\xe2\x6c\x19\xbb\xec\xf7\xd8\x94\x7e\xf3\xae\xb4\xd7\xdb\x62\x95\x7b\xbd\x2d\xc6\x6a\x90\xb7\xc5\x1a\x18\xe4\x6d\x0d\x6c\xe1\xde\x56\xdf\x82\x20\x6f\xab\x6f\x75\x90\xb7\xd5\x4b\xca\xe7\x6d\xf5\x42\x0d\xf2\xb6\xfa\x8e\x08\xf2\xb6\xfa\xfe\xf3\x79\x5b\x7d\x57\x07\x79\x5b\xbd\x58\x43\xbc\xad\xe2\x18\xe4\x6d\x29\xb0\x30\x6f\x4b\x81\x87\x79\x5b\x12\xdc\xeb\x6d\x49\xa0\x30\x6f\x4b\x42\x87\x79\x5b\x12\xda\xeb\x6d\x49\xa0\x30\x6f\x4b\x42\x87\x79\x5b\x12\xda\xeb\x6d\x49\xa0\x30\x6f\x4b\xf5\x41\x88\xb7\x25\x81\xfd\xde\x16\x83\x1a\xf5\xb6\x14\x54\x90\xb7\xa5\xa0\x83\xbc\x2d\x09\xed\xf3\xb6\x24\x4c\x90\xb7\x25\x81\x83\xbc\x2d\x09\xec\xf3\xb6\x24\x4c\x90\xb7\x25\x81\x83\xbc\x2d\x09\xec\xf3\xb6\x24\x4c\x90\xb7\xa5\x44\x1f\xe0\x6d\x49\x58\xaf\xb7\x55\x1c\xaf\xf2\xb6\x00\xf8\x35\xde\x16\x40\xbb\xc6\xdb\x1a\xd0\x02\xbc\xad\x01\xf8\x1a\x6f\x6b\xc0\xba\xc6\xdb\x1a\xb0\x02\xbc\xad\x01\xf8\x1a\x6f\x6b\xc0\xba\xc6\xdb\x1a\xb0\x02\xbc\xad\x01\xf8\x1a\x6f\x0b\xf4\x65\xb8\xb7\x35\x20\x8d\x79\x5b\x9d\x3a\x01\xea\x3d\x4d\x2a\x4f\x64\x13\x96\xa0\x8e\xc1\xcb\xf3\x5a\xec\x6e\xd3\x83\x7e\x86\x4b\x9e\x2d\x17\x9f\xc1\x35\x0c\xf3\xee\x02\x38\x49\xd5\x9d\x18\x5d\xe7\xdd\x60\xc5\xa9\x91\xe1\x04\x49\x7a\xe2\xbe\x65\xc5\xc9\x3c\x75\xfb\x2a\x7b\x7d\xea\x9a\xa7\x2e\x9b\x44\xd6\xb7\xd3\xf0\xed\x50\x55\x9d\x09\xa7\xbe\x9d\x78\x9a\x18\xfe\xf5\x44\x49\x66\x42\xaa\x6f\x27\x28\x32\x25\x17\xcf\x41\x66\x33\xc9\x4d\x57\xd5\x9e\x4c\x23\x59\x96\x19\xed\x33\x6a\x36\xc9\x71\xc9\x20\x97\x9b\xe6\x1e\xa2\xa2\xf7\x3f\x49\xe2\xbb\x43\xde\xc8\x1b\x40\xb0\xd9\x7e\x38\x28\xb4\xb4\x2a\x7a\x95\xab\xc7\x49\xfa\x01\xad\x8e\xd0\x8b\x9d\x64\xc7\x61\x4f\xe2\x1a\x09\x14\x7c\x82\xe8\xd2\xa7\x4e\x65\xac\x82\xa0\x1e\x71\x46\x53\xdf\xd8\x03\x89\xa6\x38\x5c\x9c\x56\x65\x46\xcb\x96\x66\x98\xf2\xa2\xa5\x40\x2a\xb0\xdc\x56\x69\xb4\xd4\x81\x6d\xab\x39\x5a\x6a\x28\xfc\xca\x18\x80\x31\x17\x92\x96\xfb\xc8\xab\xd1\x0a\x01\x6d\x3d\x52\x08\xd9\x1f\x8a\x91\xb6\x23\x85\x38\x2e\xd2\x72\xa4\xf0\x74\x43\x8b\xae\xa7\x2c\xc6\xab\xb4\x7b\x73\x53\xbc\x6d\xd7\xe4\x35\x90\xc7\xae\xec\x4e\x71\x75\x88\xbb\xd7\x9a\x7e\xa8\xb2\xec\xa3\x53\xed\xb6\xfd\x3f\x9d\x18\xbb\xac\x3c\x90\xf2\x5f\x90\x66\x97\x25\xb4\xc9\x25\xad\x8a\x1f\xd3\x82\xb4\xed\xef\x7f\xe8\xe7\x26\x7e\xc7\x12\xcb\x1e\xa4\xae\x88\x48\xb5\x2a\x2e\x67\x76\x99\x54\x2c\xb2\xc1\xad\x12\x4e\xb9\xcb\x34\xc2\x93\x48\x7c\x3e\xdd\x56\x1f\xe5\x77\x43\xec\xda\x8c\x09\x62\xca\xf3\x23\x61\x73\x87\x2a\x3a\x21\xd3\x4a\x26\x4a\xa1\xb1\x1a\xf4\x75\xaa\xb2\x2e\xe9\xd3\x0c\x56\x9b\x59\xa4\xd9\xbf\x41\xc7\x5d\x24\xb1\xda\x84\x9a\x81\xda\xec\xb9\x0d\x6b\xdd\xa0\xbb\x2e\x92\x43\x6d\xd2\x96\x8e\xa8\x0d\xaa\x76\x82\xc4\x4e\x7c\x1d\x46\x8a\x17\x0c\x8e\x64\x4c\x8d\x9f\x0c\xa6\x0d\xa0\xa1\x55\x1c\xdc\x49\x6d\x68\xe3\xc8\xd5\xfe\x87\xfe\x9f\x43\xad\x44\x26\x05\x54\xaf\x54\x19\xae\x58\xa2\xd8\xa1\x59\xb2\xd4\xd2\x1f\xac\x46\xab\xcc\xa5\x5c\x2e\xaa\x68\x8d\x52\x83\x40\x8d\x88\x7e\x61\xad\x04\x0a\xe6\xa2\x0a\x6a\x74\xab\x98\x96\xb9\x02\xd7\x1d\x2d\x95\x85\x47\xc7\x0c\xb8\x71\x25\x33\x18\x47\xb4\x4c\x23\xe9\x55\xb3\xa0\x7c\x1b\x59\x42\xb7\xe9\xda\xa1\x67\x79\x79\xa8\x50\x25\xe3\x05\xb8\x86\xf5\x65\x0e\xf5\x62\x45\x96\xfe\x58\xb5\xe8\x05\x2e\xad\x42\x89\xd9\xb5\x48\x8d\x91\xb5\x20\xca\x64\xb5\x06\x68\x12\x4a\x4c\xd6\xe2\xd1\x21\x98\x99\x04\xd7\x8d\x21\x55\x89\x47\x81\x20\xd0\xb8\xf6\x40\x66\x11\xd5\x19\x88\x79\xf5\x66\x3c\x87\x4a\xba\xa4\x8b\xc3\xc2\xa1\x34\x22\x3d\x0a\xaa\x37\xaa\x0c\x57\x1d\x51\xec\xd0\x1e\x59\x6a\xe9\x09\x56\xa3\x55\xe6\x52\x23\x17\x55\xb4\x46\xa9\x31\xa0\x46\x44\x9f\xb0\x56\x02\x95\x72\x51\x05\x35\x7a\xe6\x3f\x3d\x59\x16\xa6\x33\x5a\x7e\x1a\x8f\x6e\x19\x70\xe3\xea\x65\x30\x8e\x68\x98\x46\xd2\xab\x64\x61\x49\x74\xc8\x61\x9e\xa6\x0e\x3d\xe3\x09\x72\x50\x35\x93\x45\xb8\x96\xf1\x52\x87\x92\x89\x42\x4b\x8f\x90\xda\xcc\x22\x97\x86\x39\x48\x62\xb5\x49\x0d\x1a\x6a\x43\xd4\x0b\x69\x1d\xd0\x2e\x07\xc9\xa1\x36\x8f\x6e\xc1\x24\x44\xb8\xce\xc0\xac\x44\x1e\xd5\xd2\xc1\xc6\x35\x4b\x67\x1a\x51\x2c\x48\xd0\xab\x57\x41\x69\x93\xf6\x69\x6a\xa8\x15\xc8\xe8\xcb\xb0\xe0\x6d\xc4\x69\x32\xfb\x9d\x76\xc9\xf9\x05\xbb\x78\xcc\xdf\x6e\x8d\x48\x99\x45\x1f\x86\x40\xd3\x66\xbd\x51\xdb\x91\x68\x45\x66\x8c\xca\xca\xa3\xb4\x32\x72\xe7\xc4\xaf\x5a\xf6\x9c\xf8\xdc\xaa\xb4\x38\x32\x29\x43\xff\xad\x67\xf0\x94\xb3\x18\x1b\xbf\x90\xbd\x27\x2c\xa3\xb2\x73\xc1\xc9\x63\x82\x26\x8f\x4f\x20\xf6\x80\x64\x6d\xf1\x22\xa1\x0b\x70\x1f\xd4\x89\x6f\xb7\x3a\x01\x91\x35\xb9\x0f\x6a\x8c\x1c\xb2\x98\xf6\x41\x9d\x7a\x6a\xbc\xcb\xdc\xf9\x86\x1c\x64\xf4\x28\x06\xcc\xac\x1b\x86\x06\x45\x09\xc3\x4e\xde\x16\xa2\xc1\x8e\x5b\xb0\x07\xb9\xbf\x09\xfb\xa6\xba\x87\x4e\x7a\x13\xb6\x56\x37\xec\x04\x3d\xd2\x7d\x65\x4f\x80\x8c\x47\xd7\x77\xc4\xf5\xc8\xa0\x1f\xde\x80\x7c\x4b\xcd\xa0\x17\xde\x80\x0c\x6b\xd6\xfa\x40\xec\x91\x5e\xdf\x09\x80\xa0\x98\x2c\x6f\x45\xf6\x1b\x0b\x5b\x8e\xb7\xd5\x8c\x21\x9f\x34\x51\x18\xc6\x95\xcd\x30\x87\x9c\x16\x59\x4b\x3b\x35\x33\x89\x39\x23\x71\x67\xfc\x4e\xb0\x04\xde\x05\x3d\xd2\x92\x4b\xde\x4e\xb2\x62\xcc\x43\x18\x59\x5f\x5a\xda\xf9\x0c\xd9\xa9\xb0\xb3\x95\xe8\x39\x6e\xf4\xac\xe8\x58\xea\xc1\x55\xff\x4f\xb2\x4f\xf6\xf4\xfa\xb4\xf6\x06\xeb\x2b\x24\x7b\xee\x90\x13\x8f\x3d\xd1\xf0\x63\xf7\x5a\xd3\x1f\x5a\x4a\x9a\xf4\xc4\x63\x82\xbf\xee\x8b\x18\xa0\x52\xf6\xee\xf4\xbe\x7a\xf9\x49\xbc\x16\xc1\xbf\x36\x24\xcb\x2b\xce\x89\x4a\xde\xc8\xf2\xf7\xc0\xbe\x51\x3b\x3d\x7f\xd9\x5a\xfd\xc0\xb3\x34\xd9\xd5\x1d\x72\x99\xc9\x4e\xd7\x07\x1b\xb2\xe9\xdd\x2a\x0c\xf4\x11\x4d\x65\xc0\xdf\xb8\xf8\xf1\x7c\x29\xba\xbc\x66\xa9\xf3\xc4\x97\x5e\x59\x38\x19\xe4\xa9\x03\x93\x33\xf9\x2c\x05\x26\x20\xa4\x8c\x8b\x89\x17\x08\x27\xf7\x57\x7f\x85\xa2\xba\x74\xf5\xa5\x73\xc8\x45\xdb\xf8\xdc\xd8\x59\x8a\xc2\x9f\x19\x59\xad\x54\xc8\xf3\x50\x35\xe7\x38\xad\xca\xae\xa9\x5c\x99\xef\x1c\x0f\x3b\x2c\x96\xc6\x1b\x01\xeb\xfa\x85\xa5\xa8\x7e\x13\x5f\xae\x5c\x48\x56\x96\xab\xfc\x4c\x8e\x14\x66\x81\x0a\x4f\x91\x34\x96\xff\xaa\xa7\xd1\xff\x7f\x23\x9f\x55\xb2\x71\x67\xc0\x1a\x41\xc1\xde\xa1\x10\x7c\xb1\x16\xc2\x37\x24\xa2\xe9\x6c\xd5\x4e\x22\x9b\xc1\xde\xac\x9b\x70\x8f\xf6\xcb\x15\x23\x74\x07\x7a\xfa\xc3\x15\xef\xde\x49\x7a\x6f\x26\xc6\x0a\x31\x05\x03\xaf\x38\x40\xc2\x2c\xaf\x31\x39\xd0\xad\x36\x96\x9c\x89\xbf\x02\x64\x3e\x61\xa9\xbc\x58\xca\xf5\x77\xef\x58\xf9\x2c\x99\x4f\xa2\xd9\x66\x35\x89\xe6\x8b\xc5\x24\x9a\xae\x6f\xe9\xca\x10\xb2\x68\xbb\x77\xcc\xa0\xd7\x05\x49\xe9\xa9\x2a\x32\x23\x03\xf3\x76\xcb\x5b\x5e\x93\x34\xef\x5e\x77\xd1\x0c\xa5\xd1\x2f\xc3\x98\x79\xf2\xd1\x71\xd4\x2e\xa4\x78\x13\xfa\x8f\x59\xce\x9e\xe0\xc8\x7e\x9a\x44\x7a\x41\x43\x49\x56\x95\xc5\xeb\x4f\x93\x48\xfa\x14\x03\xb0\x0e\xeb\x8e\x12\x88\x14\x91\xfe\xc6\x43\x1e\xc6\xaa\xe2\x6d\x12\xa9\x54\xcb\xaa\x8b\x49\x51\x54\x5f\xa9\xdc\x04\x95\xef\x24\xd9\x38\xfe\x29\x04\x9b\xc0\x49\x5d\x53\xd2\x90\x32\xd5\xd3\xfb\x22\x4b\x78\x89\xd1\xbb\x5b\x19\x7d\xce\x53\x1a\xd7\xf9\x0b\x2d\x62\xf6\xf8\xd1\x2e\xe1\x6b\x7a\x50\x5d\x46\x3a\xaa\x4f\xdb\x5d\x7e\x36\xbe\xf4\x30\xfd\xd7\xb8\xa8\x52\x52\xe8\x65\xe7\xaa\xec\x4e\x3f\xa9\x35\xa6\x66\x7c\x17\x4b\x99\x16\xec\xdd\x94\xab\x04\x3b\xe3\x10\xb7\x67\x93\x7a\xdf\xe5\x6e\x08\xce\x11\x33\x1d\x7e\x32\x1a\x93\x1e\x58\xce\x34\xa3\x68\x32\x22\xb0\xda\xb3\x2d\x13\xbc\xc8\xa8\x77\x00\x32\xa8\xf3\x3a\x55\x71\x84\x88\x2b\xc1\xc5\x55\x1c\xc7\xc4\xa5\x43\x38\xc4\x65\x93\x71\x8b\x4b\x87\x1d\x17\x57\x71\x74\x8a\xcb\x28\xc2\xc5\x55\x1c\xbd\xe2\x2a\x8e\x88\xb8\x96\x6b\x3d\xe9\x1c\x1b\x67\x8c\x7d\xe0\x72\x6a\x01\x29\x95\x84\x42\x78\x63\x93\x68\xca\x9c\x2f\x63\x03\x1d\xa6\xf7\xc2\x9e\xbf\xba\xea\xa5\x12\x59\x57\xc4\x96\x01\xaa\xc6\x61\x51\x00\x43\x76\x72\x81\xa2\xa7\x0a\x73\xbc\xfc\x92\x58\x0b\x02\xf1\xee\x8c\xe3\x01\x21\xc5\x09\xee\xb8\xab\x72\x99\x7f\x1c\x05\xeb\x75\x93\xb7\xc0\xf2\x60\x65\xdb\x10\x7c\xb0\x12\xc0\x1f\x87\x82\x42\x5d\xaa\xc5\x80\x9e\xb7\x6f\x8e\x48\xf5\x93\xd5\x97\x9f\x40\x97\x42\xaa\x31\xd2\xff\x82\x53\x93\xf1\x00\x6d\x70\xe5\x4e\xbf\xad\xc3\xf0\x07\xdf\x02\xba\x52\x70\xfc\x69\xa4\x45\x9f\xec\xf6\xb9\xf2\xb6\xcb\x63\xba\xe0\xbd\x3a\x6b\x16\xc4\xf5\xc7\x0f\x28\x54\x44\x9f\x7b\x14\xf6\x54\xe2\xe0\x8b\x26\x38\x2b\x5b\x34\x07\x5c\x9d\x38\x2f\x05\xdc\xf8\xa7\x6b\x53\x84\x80\x25\x4d\x7a\xe0\x3b\xe6\x20\x98\x1d\xd1\xf7\x38\x02\x66\xf5\x47\x00\x63\xaa\x66\xdd\x94\x58\x9f\x7d\x6c\x09\x18\x1f\x57\xc0\x34\x79\x98\x82\x4e\x4d\xcc\x4f\x1c\x59\xd6\xcc\x58\xb8\x69\xeb\x49\xf3\x20\xed\x06\x1f\x31\x9e\xea\xc0\xf4\xe2\x29\x16\x13\xad\x91\x92\x31\x41\x92\x8e\xcb\xaa\x34\x3c\x38\x35\x3f\x1a\xe7\xfd\xd0\x0c\xbe\x73\x74\x0d\xba\xc2\xf3\x23\x6b\x51\x07\x7f\xc5\x88\xa3\x80\x46\x2c\x80\x8f\xa2\x1c\x50\x94\x30\xcc\xf7\x35\xcc\x9c\x3d\x94\xdb\x61\xfd\x2d\xa4\x70\x2d\x2f\xc1\x82\xf1\x10\x06\xb2\xf2\x40\x89\xa5\xc5\x95\x02\x84\x83\xc3\xe4\x5d\x1b\x2c\xf3\xb7\xc9\x56\x57\x5f\xe1\x30\x41\x57\xe9\xd1\x7a\x72\x41\x7b\x92\x6b\x78\x3d\x0c\xa1\x2e\x8e\xe0\x23\xfd\xb7\xc6\xb5\xd8\x51\x3f\xe2\xbf\xf9\xb4\xb8\x1f\xdb\x86\x16\x1b\x84\x1d\x9d\x50\x1c\x3d\x9a\xf3\x1b\x0a\xe3\x5a\x96\x82\xe5\xe3\x21\x8c\x2b\xb3\x09\x15\xa6\xcc\x26\x16\xa6\xcc\x92\x77\x4d\x99\x1f\xee\x22\x62\xc9\xd1\x89\xb4\xf1\x81\xd2\xac\x5f\xd5\x3b\xbc\x33\x14\xd4\x16\xb8\x31\x0f\x2c\xe7\x53\xe0\x16\x6a\x2d\x75\xd4\x07\x9d\xd6\xc1\x79\x82\xd3\xca\xcf\x71\x5e\x66\xf4\x65\x17\xcd\xf1\xf5\x83\xbc\xfe\xb9\xd4\x1f\x42\x5d\x60\xd1\x4b\xf9\xd1\x7e\xfe\x8d\x49\x97\x3b\x85\x31\x7d\xa6\x65\xd7\xea\x07\x7a\xe5\x68\xf9\xe4\x69\x95\xbc\xb1\xba\xd6\x39\x19\x53\x46\x35\x9f\x04\xd0\x96\x96\x2e\xd4\x6a\xb3\xfe\x93\x2f\x74\x41\xdf\x1e\xfd\x3e\x78\xbb\x7a\xb1\x60\x48\xf9\x3a\x7a\xf1\x89\x16\x35\xf7\xdc\x4d\x44\xe6\xff\xa0\x1f\x81\x3b\x07\x4b\xed\xd5\x1d\x56\x28\xfd\x3c\x94\x1f\xe8\x74\x19\xf8\x9a\x93\x08\xbc\x32\xec\xd1\x39\x9d\x67\x4b\xef\x8d\x28\x28\x47\xfd\x6d\xc3\xd3\xa3\x8c\xba\x83\xb6\xfc\xc1\xbc\x37\x87\x69\xd7\xf5\x4b\xf4\xdd\x7a\xb3\x9f\xad\x1f\x6e\x8e\xc9\x02\x1a\x68\x83\x60\x10\x85\x64\x99\xb8\x4a\x66\xcb\xdd\x79\x7e\xf7\xd1\xd5\x5b\xa3\xf2\xd3\x07\xa0\x1b\x59\x3e\x1c\x67\x0e\x2f\xeb\xbb\x3e\xbc\x86\x62\x74\x78\xa9\x62\x6b\x78\xa9\x12\x38\xbc\xf4\x8f\xe6\xf0\x12\xa5\xf8\xf0\x32\x0b\xf1\xe1\x25\xa1\xec\xe1\xa5\x95\xb8\x87\x97\xf6\x5e\xa2\xce\xf3\xd8\xf0\xe2\xa8\x7f\xbf\xe1\x85\x32\xea\xdb\x13\x59\xcd\xee\x35\xbc\xd2\x84\xcc\xd6\xfb\xb7\x0d\x2f\x4e\x03\x6d\x90\x7f\x78\x0d\x72\x77\x9e\x40\x45\x86\x57\x60\x47\xe3\xc3\xcb\x46\xa6\x4d\x53\x35\xd6\xe0\x32\xbe\xea\x43\x4b\x16\xa2\x03\x4b\x14\x5a\xc3\x4a\x7c\x87\x83\x0a\x7e\x32\x87\x14\x2b\xc3\x07\x94\x5e\xa4\x0f\x27\x08\x01\x87\x92\x4e\x76\x64\x28\x69\xcf\x84\x42\x4e\xc7\x06\x12\x47\xfc\xfb\x0d\x24\x84\x4d\xf7\x30\xe2\xef\x9b\xde\x69\x18\xd1\x87\xe5\xc3\xe2\x8d\xc3\x88\xd1\x40\x9a\xe3\x1f\x44\x83\xcc\x9d\x47\x6d\x91\x41\x14\xd4\xc5\xf8\x10\xb2\x51\x15\x18\x57\xa5\xff\xed\x21\xc2\x2f\xa1\xae\x74\x07\x52\xc7\x97\x8f\xfc\x8f\xd3\x51\x31\xa0\x61\xb0\x39\x8e\x2a\xc0\xf0\xe9\xca\xb9\x07\x00\x8f\x1c\x6c\x16\xfd\xbf\xc0\xe4\xd6\x8c\x4f\x31\x9c\xcc\x7d\x0d\x77\x10\x1a\x8d\x37\x3b\x82\xcb\x72\x9f\xc9\xae\x09\x0e\x47\x4f\x5d\xc2\xc1\x97\x4f\xf3\xdc\x5a\x0d\x5c\x51\xe2\xb5\xa1\x24\x80\x0a\xe3\xa8\xec\x04\xdb\xb5\x8c\x41\xaa\xc6\x9a\xda\x03\x68\x0d\x27\xbe\xf5\x16\x86\xb0\xef\x4a\xed\x3c\x35\xcc\xa7\xe1\xa2\xf0\x84\x74\x14\x92\x84\x49\x43\xd7\xe6\x16\xfc\x58\xf4\xb5\xd2\x02\x33\x9c\xf6\x7d\xd8\x7f\x19\x57\xd5\x61\x09\x7d\x37\x76\xd4\xc4\x85\x30\x05\x5a\x6f\x45\x7f\x7d\x24\x1d\x3b\x66\x48\x0d\xd6\x06\x84\xda\x19\xc7\x77\x94\xd0\xc4\x15\x06\x1b\xee\x98\x86\x6e\xc3\x94\x11\x33\xf6\x44\xc1\x4b\xb2\x56\xa7\x61\x65\xd0\x75\xb0\x80\xa4\xbf\x81\x17\x60\x6f\x17\xc3\xb0\xff\xd8\x73\xc1\xc9\x4d\x8c\x83\x1d\x3f\xb8\x99\xba\x31\x42\x3b\x10\x05\xdf\x2c\x0e\x7e\x38\x2c\xc8\x80\x6b\xec\xdb\xe3\x0f\x93\x0f\x3e\x0a\xac\xb7\x50\xbd\x5d\x1c\xaa\x2e\xe0\x79\xaa\x5b\x5b\x65\x84\x0a\xc7\x1a\x39\x5b\x4e\x17\x8b\xd1\x17\xe7\x42\x6b\x6c\xcf\xe3\x35\x1a\x47\x04\xa4\xb5\x1d\xdb\xc7\xd5\xcf\x18\x3a\xb7\x71\xf5\x73\x87\xd8\xce\xae\xe7\x2c\x22\x1e\xd3\x43\xee\x68\xf8\x77\x88\xe3\x73\x1b\x77\xd5\x25\x3d\xc5\x24\xe5\xe6\xe5\x4c\xca\xbc\xbe\xf4\x26\xa6\x2a\x79\x98\xd2\x57\x6a\xec\x30\x43\xf7\xf5\xd2\xd2\x26\xe6\xa1\xe7\xe1\xfc\x23\x3b\x60\xe6\x28\x69\xf1\x02\xf4\xe3\x35\x27\x2c\xfd\xaf\x3e\x0e\x6f\x51\xf6\xfd\x2b\x6e\xa9\x4f\xc5\x39\x5b\xf0\x69\x07\x3f\x81\xdf\x3b\x0d\xa3\xd7\xba\xe1\x23\xc4\x01\x9e\xff\xaf\x7e\x3e\xd7\xe2\x11\xfe\x1e\x2e\x89\x19\xa7\xd3\x99\x4a\x65\x34\xad\xd8\x61\xaf\x52\x8f\x08\x0f\x82\xd0\x9a\x6d\x5e\x36\x33\x3a\x23\xfc\x94\xe4\xa2\x7e\x61\xcd\x36\x16\x25\x33\xcf\x73\xae\x1e\x14\xc8\x35\xd8\x89\xdf\x77\xe5\xd8\x11\x3d\x39\xc6\xb1\xe8\xf8\x23\xbe\xa9\xcd\x46\x6f\x5e\x74\xbd\xd6\x91\xa2\x3e\x91\x0f\xe2\x94\x60\xf4\x43\xb4\xd6\x0f\xd6\x86\x3c\x0c\xab\x1d\x33\x9c\xae\x57\xa0\x2d\x71\x46\x0f\xe4\x52\x74\x58\xef\x79\x4e\x23\xeb\x6b\x2d\x70\x09\x10\x90\xd4\x3a\x57\x7d\x04\x7a\x23\xbf\xed\x40\x92\x0e\xf8\x19\x03\xe5\x17\x17\xa3\x69\x55\xd3\xf2\x69\x9a\x35\x55\x9d\x55\x5f\xfb\xf9\xfb\x78\x2c\x28\x84\x54\x8f\x51\x8f\x35\x89\xae\xfb\x7f\xd8\x0a\x32\xeb\xff\x85\x36\x6c\xa7\x3e\x86\xb2\x86\xeb\x38\x56\x9f\xae\x6f\xd6\x67\x5c\xd0\xaa\x54\x33\x23\x56\xf1\xce\x8b\x8c\xf5\xc1\x50\x38\xdc\x22\x05\xc5\xda\xa9\x59\xf4\x3b\xca\x2f\x28\x46\x19\x1e\xca\x51\x8e\x41\xf1\x18\xba\x50\x21\xc7\x50\x95\x08\xa3\x00\x20\xb5\xcc\x18\xa4\x10\xe2\x08\xd8\x2e\x98\xe0\x2e\x90\x20\x6b\xa9\xe7\x9a\xf2\x15\x83\x39\x9a\xee\x49\x76\xa4\x9a\x99\xf0\x3e\xc0\x0d\x69\xd4\x4d\x7e\x26\xcd\x6b\x30\xf2\x86\xec\x37\x08\x67\x73\xba\xce\xc8\x12\x21\xac\x2b\x94\xfc\x08\x55\x57\x7c\x33\x2d\x8d\xfc\x8c\x81\x8e\x5b\x1a\x01\x69\x58\x1a\x77\xc3\xe6\x0f\xeb\x64\x9b\x60\x0d\x4b\x96\xd9\x26\xb8\x61\x21\x96\x46\x67\x6d\xdc\xd2\xc8\xfa\x0c\x4b\x63\x7e\xc6\x05\xed\xb0\x34\x66\xf1\xce\x8b\x8c\xf5\x81\xcb\xd2\x88\x62\xcb\xd2\x58\xdf\x51\x7e\x9d\x96\xc6\x2a\x47\x39\x76\x5a\x1a\xbb\x7c\xc4\xd2\x08\x84\x51\x80\x00\x4b\x63\xe8\xfc\x08\x58\x80\xa5\x31\x46\xc6\x18\xd8\x88\xa5\xb9\x7e\x48\x63\xf6\x06\x50\xf1\x66\xef\xeb\xc9\xc8\x0d\xc9\xb0\x91\xb9\x4a\xf7\x0f\xab\x14\xe1\x6f\x99\x12\xba\x4c\x11\xc2\xba\x66\xc9\x8f\x50\x87\x65\xd6\x20\xc3\xe4\xc8\xcf\x18\xe8\xb8\xc9\xd1\x73\x2e\x8d\x37\x6c\xb9\xdc\x66\xcb\x25\xb6\x85\xbb\x7d\x58\x2e\xb6\xa1\x0d\x0b\x31\x39\xce\x74\x50\x0e\x93\x23\xeb\x33\x4c\x8e\xf9\x19\x17\xb4\xc3\xe4\x98\xc5\x3b\x2f\x32\xd6\x07\x2e\x93\x23\x8a\x2d\x93\x63\x7d\x47\xf9\x75\x9a\x1c\xab\x1c\xe5\xd8\x69\x72\xec\xf2\x11\x93\xa3\xd2\x62\x8d\x00\x04\x98\x1c\x43\xe7\x47\xc0\x02\x4c\x8e\x31\x32\xc6\xc0\x46\x4c\xce\xf5\x43\x1a\x33\x39\x80\xca\xa8\xc9\xc9\xcb\x43\x15\x6a\x6f\xf6\x69\x82\xee\x5a\x2d\xd7\xfb\x87\x8c\x98\x54\x75\x9d\x62\x5f\xa0\xea\xb2\x3c\x53\x16\x88\xa1\x2a\x20\x67\x95\x6f\x14\x5f\xd1\x88\xc5\x6c\x9f\x64\x2b\xcc\xa8\xaf\xb7\x64\x9f\x8e\x37\x22\xc4\xaa\x28\x7e\xc6\x0d\x0a\xab\xc4\xb0\x26\xda\x37\x44\x8c\x0e\x3b\xa2\x95\xd9\xa2\xc5\x2d\x88\x5e\xa2\x9b\x8f\xbe\xcc\xb2\x1d\xfa\x47\x9b\x3b\xa7\xd5\xd0\x0b\x6d\xfe\x2c\x7b\x81\x16\x29\x0e\x5d\x23\x8d\x67\x41\xf3\x95\x06\x98\x09\xa8\xad\x3e\x98\x00\x03\x01\xb4\xda\x4f\x6a\xcc\x34\x5c\x37\xfa\x50\xbb\x30\x90\x18\xb5\x0b\xf2\xf0\x46\xd8\xa8\x3a\x24\x24\x5b\x62\xcc\x51\x4a\xe6\x8b\x35\x42\x58\x57\x1c\xf9\x11\x76\xbc\xcc\x11\x66\xb8\x22\xf2\x33\x06\x3a\x6e\x29\xf4\x0c\x6b\xe3\x0d\xa3\xe9\x76\x33\xc3\x16\x9c\xd9\xea\x61\x35\x9b\x87\x36\x2c\xc4\x68\x38\x93\xbf\x39\x2c\x87\xac\xcf\x30\x1e\xe6\x67\x5c\xd0\x0e\x13\x62\x16\xef\xbc\xc8\x58\x1f\xb8\x6c\x89\x28\xb6\xcc\x89\xf5\x1d\xe5\xd7\x69\x54\xac\x72\x94\x63\xa7\x2b\x62\x97\x8f\xb8\x22\x2a\x09\xde\x08\x40\x80\x8d\x31\x74\x7e\x04\x2c\xc0\xd2\x18\x23\x63\x0c\x6c\x2c\xce\x72\xf5\x90\x46\xa3\x2d\x03\x95\x51\x93\xc3\x93\xb7\x05\x5a\x9c\x6c\xbb\x5a\x2c\xd1\x81\xb9\x5c\x1c\x16\xc4\xa6\x6b\xc4\xef\xf8\x37\x2d\x50\xc8\x73\xc7\x21\x60\x66\x70\x0e\x66\xa3\xf3\x46\x4e\xaf\x69\x50\xba\x5d\x24\x73\xcc\xf5\x23\xe9\x7c\x3b\x5f\x85\x35\x28\x28\x9e\xeb\xc8\x03\xe8\x0a\xe7\xf2\xca\xcc\x68\xae\xfe\x15\x15\xae\x2b\x96\xab\x97\x62\x02\x77\x44\x72\x8d\x32\x23\x90\xcb\x4a\xed\x38\xae\xf1\x19\xe3\xd4\x1d\xc5\x35\x8a\x31\x5e\x1d\x6e\x8b\x55\x38\xea\xb8\xc8\x2c\x88\xfe\xf2\x90\x00\xae\xa6\xdb\x7e\xa8\x90\xf0\x2d\x1c\x03\x63\xe4\x46\x8c\xca\xd5\xa3\x16\xb3\x29\x80\xc8\xa8\x4d\x29\xf2\x92\x6f\xd3\xa3\x37\xbc\x5d\x81\x1e\xb9\x27\x9a\x98\xa4\x44\xe7\xf6\x3f\x75\x45\xea\xbf\xec\xac\x2f\x40\x1b\x3d\x02\x56\x3c\x7a\x9f\x56\xb9\x76\xfb\xcc\xc3\xba\xcd\xa8\xa6\xba\xec\x03\x48\xa1\xa9\xf5\x94\xfd\xd8\x4b\x10\x11\xb5\xca\x5a\xac\xe6\x9b\x14\xdd\x65\xbd\x94\x19\x6d\x8a\xdc\xda\xd7\x1e\xaf\xd8\x31\x04\x8d\xa2\x91\x99\x1d\xb4\x60\xa4\xaf\x90\x66\xc1\x17\x6b\x3c\x3b\xc7\xea\x90\xc7\x53\xff\x97\x64\xf3\x08\xcf\xf9\xfc\x2a\xf7\xe8\x40\xdd\xed\x19\xd6\xad\xdf\xeb\xbd\xef\x4d\x54\x50\xe9\x4b\x0b\x2b\x7d\x69\x8d\x06\xf3\xfd\xeb\xbb\xd5\xe9\x3b\x71\x6a\x27\x2b\x1b\x50\x3e\x19\xd8\xc6\xe9\x54\x3b\xc7\xcc\xfe\xd2\x75\x55\xf9\xd3\x80\xa6\xdf\xab\xa7\x2d\xed\x5c\x85\xed\x65\x7f\xce\x61\xa9\xb0\x99\x08\x7f\x07\x92\x71\xfb\xa7\x36\xc3\xb5\x43\x04\x30\xfd\x93\xdc\x6f\x9f\xce\x56\x6d\xd4\x0b\x8e\x67\x7d\x35\x32\x4e\x39\xa0\x46\x40\x20\x3b\xd3\xbc\xd4\x39\x52\x59\x80\xd2\xaa\x28\x48\xdd\x52\x5d\xfc\x70\x18\x48\x08\x49\x03\xcd\x3d\xd7\x35\x6e\x38\x91\x67\xb1\xfa\x2a\x61\xf7\x55\xf6\x1a\x00\xce\x75\xd1\x60\x43\x2e\x71\xf1\x63\x85\x52\xed\x98\xc0\x65\x9e\x5d\x98\x80\xd7\xee\x84\xb8\xcb\xcf\x79\x79\x8c\x0f\x97\x52\x1c\x15\xa2\xa4\xa5\x56\x2f\xb8\xc1\x82\x48\xd9\xd5\x66\x17\x69\x73\xa6\x0b\x24\xcf\x18\x52\xee\x47\xb6\x6b\xa8\x9b\xaa\xa6\x4d\xdf\xdb\x5c\x2c\x93\xe8\x39\x6f\xf3\x7d\x5e\xe4\xdd\xab\x5d\xdf\x18\x74\x20\xa8\xea\x2e\xd2\xd0\xce\x7f\xe8\x0c\xa6\xc5\xd4\x3a\x4e\x7f\x6c\x8d\x5b\x15\xf7\x49\x30\xf8\x2c\xd3\xb2\x7e\x89\x32\xd2\x9e\xf8\xd9\x16\x3d\x5d\xe9\x72\xe4\x5c\x95\x78\x47\x0e\x83\x92\x8d\x92\xde\xf9\x24\x62\x3f\xc5\x21\x4a\xf7\xad\x5c\xc3\x9b\xc7\x4e\x52\x25\x16\xec\x99\x96\x97\xb1\xdb\xb7\x32\x57\xa0\x38\x3e\xfb\x08\xef\xdf\xce\x12\xee\x2c\x69\x83\xf9\x71\x78\xff\xa6\xc7\x79\xd4\x33\x93\xce\xd6\x58\x86\x03\x2d\x43\xe9\x7c\xc8\x60\x89\x9c\x01\x34\xdf\x76\xe3\xf3\x40\xdb\xc9\x14\xd7\xc8\xe9\x37\x63\x81\xa5\x3c\x25\x00\x51\xe4\xf5\x2e\x1a\x32\x66\xbc\x98\x14\xd0\xf2\x91\x3c\x85\xb0\xc4\x3c\x7f\x25\x4f\x6c\x85\xe6\x33\x4c\xd4\x71\x49\x8b\x14\x72\x07\xc7\x0f\x8d\xaa\xc1\x94\xbd\x4c\xca\xf4\x17\x1e\x5d\x4d\x86\xae\x87\x17\xd8\x75\x0d\x9a\x66\xf9\x73\x2e\x53\xd0\xa9\xe9\x18\x9e\xec\xdc\x45\x5b\xd9\xcb\x98\xa9\xc4\x82\x6b\x30\xbf\xab\x5e\xdf\x53\x91\x3f\x11\x7f\x62\x4d\x36\xef\xab\x24\x41\x69\x41\x49\xc3\x1e\xac\x3b\xdd\x70\x8a\xd4\x38\x70\x85\xa6\xf8\x76\x71\xa9\x7c\x4e\xa4\x08\x71\x80\xd7\xfd\x3f\xa7\xb3\xe8\xd2\x6a\xed\xdd\x23\xbd\x22\xf9\xda\x12\xb1\x58\x50\x25\x0e\x16\x87\x72\xb8\x6c\x33\x46\xd2\x35\x6c\x0e\x0b\xa9\x11\x83\xf4\xa4\x56\xf1\x18\xdb\x43\x19\x88\xbc\xb8\x61\x50\x77\x7c\xb4\x5a\x97\x4c\x50\xc2\x4e\x21\x38\x8e\x41\x8e\xae\xe4\xdc\x47\x45\xe5\x09\xca\xba\xa9\x8e\x79\xb6\xfb\x2f\xff\xf3\x8f\x7d\xf9\x9f\x7b\xf4\x43\xd5\x9c\xa7\x7f\xca\xd3\xa6\x6a\xab\x43\x37\x3d\xf6\x36\x85\x96\xdd\x07\x5a\x32\x8e\x7f\x38\x90\xa2\xa5\x6a\xe8\x1b\x11\x20\x35\x0f\xa0\x0e\x17\x87\x26\x21\x93\xc9\x6d\x06\x84\xcd\x87\x10\x49\x5e\x79\x32\xf2\x06\x29\xa4\x13\x25\xd2\xdc\x04\x9a\x80\xf1\xc5\x03\x36\xe4\xc5\xd2\x2d\x64\xc8\xf7\x9d\xd6\xff\x61\x4c\xa7\x87\xfc\x85\xf7\x3a\x9e\xc9\x42\x3b\xf0\x8e\xcd\xb0\xdb\xad\x6a\xfd\x60\xa0\xb1\x9e\x1b\x17\xf7\xa5\x8e\xb8\xab\x34\x89\xa6\x25\x79\xde\x93\x26\x66\xdc\x89\x53\xf7\x83\xb2\x47\xc0\xa3\x4a\xab\xb2\xa3\x65\xb7\x8b\xde\xbf\x37\x1d\x20\x2c\x41\xb7\x72\x69\xcc\x8a\x35\x86\xc7\x19\xb0\xdb\xc7\xaa\x94\x7a\x31\xdc\x00\xc4\xdf\x6a\x0d\xbe\x6e\x21\xd8\xe0\x5a\x8b\xd4\xaa\x89\x15\x79\x8f\xd9\x83\x3f\x28\xb5\xa9\xd5\xef\xec\x27\x74\x87\xf5\xb0\x58\x07\xf3\xb5\xb1\xf4\x44\x6f\xc9\x97\xe7\xba\xd7\x65\xae\xbf\x25\x1c\x5c\x85\x8b\x3b\x70\xc3\x39\x6f\xac\x66\xe0\xe3\x8d\x50\xd5\xc3\x61\x08\x80\xb9\x8f\x87\x81\xc0\xe8\x0d\x56\xae\x47\x7c\x87\x16\x20\x95\x6b\x75\x5a\xdf\xf5\x30\x2f\x28\x18\x4c\xfe\x90\x80\xc6\x6a\x39\x23\xf7\xc9\x94\xe5\xf0\xd5\xee\x65\xf0\x93\xe3\x69\x55\x9b\xa5\xf6\x8d\x2a\x79\x75\x4a\x0f\x74\x74\x55\x55\xec\x49\x83\x00\xae\x70\x40\x8b\x39\x55\x60\xde\x04\x75\x74\xbc\x80\x87\x7a\x04\x3f\x61\xb4\x9f\x2c\xda\xfa\xab\xdc\x48\xbc\x88\x77\x45\x59\x75\xd1\x07\xed\xe1\x8e\x8f\xe2\x1b\x78\x47\x42\x7c\x32\x97\x46\xdf\x7e\xf3\xee\xe3\x2f\x23\xf1\x5c\xa8\x0e\xc6\xeb\x20\xe6\x6d\xc2\x31\xa4\x60\xbe\x22\xc8\x55\x57\xd5\xdc\xaa\x0c\xfc\x59\xe6\xd6\x04\x70\xf0\x32\xd4\x8c\x89\x4d\xd7\x7f\x73\x15\x59\x56\xdd\xb7\xdf\xbc\x33\x50\x0c\x36\x7b\x49\xf8\xb8\xd4\xcb\x71\x26\xc7\xb5\xcb\x84\x0d\x54\x81\xc1\x88\x85\x75\xb7\x20\xee\xef\x3f\x53\xae\x88\xb1\x08\xa4\x63\xaa\xc0\xaf\xa2\x01\x82\x17\xbf\x1e\xe0\xca\x7e\xbf\x6e\x8e\x2c\xdd\xb2\xed\x2f\x73\x34\x2d\x40\x87\xdf\xa9\xb7\xf1\x13\x8a\x65\xe4\x22\x7b\xc0\x52\xff\x3e\xb8\x8c\x0c\x4b\xed\x15\x40\x75\x36\xc7\xc8\xce\xe6\x08\x5d\x4f\x03\xff\x2e\xf7\xbe\x7c\x5c\xe9\xdb\x4f\x37\xee\x2e\x41\x57\xd2\x6d\x38\xd9\xc5\x56\x05\x27\xd4\x4a\xc4\x8b\x56\xa2\x21\x88\xc6\xc9\xa0\x9e\xe9\x6b\x8e\x91\x4c\x24\xd1\x2b\x9c\x21\xbd\x44\xcc\x65\x1e\x77\xc5\x74\xa1\xec\x65\x0a\x78\x22\xfa\xd1\x7e\x99\xc3\x78\xae\x66\x84\x53\xb3\x36\xe4\xf9\x69\x07\xa6\xe5\xa9\x20\xc5\xa1\xad\x1d\xa1\x65\x39\x31\x22\xa6\xa0\xa5\x90\x9e\x21\xb7\xc2\xed\x21\x6f\xb8\x7e\x61\x53\x41\xd0\x24\x60\x3a\x9d\x5e\xfb\xed\xb5\xd6\x22\x98\xe7\xb5\xd7\x57\x5b\x51\x83\x3d\xbf\x49\x0f\x35\xe0\x41\x33\x8d\x86\xbd\x1c\x1d\x3b\xd7\x4f\xd2\xf2\x60\xc0\x75\x3d\x74\x87\xf9\xfa\x26\x82\xb6\x4f\xf9\xcb\xaf\xdc\xd9\xb7\xcd\xe2\x3a\x63\xd7\xaa\x81\xcd\xd2\x5f\x2f\x6d\x97\x1f\x72\x9a\x21\x1b\x69\x88\x19\xe3\x1b\x6c\x05\x79\xad\x2e\x1d\x08\x86\x0c\xc7\x06\xd8\xbe\xdc\x2e\x6a\x69\x4d\x1a\xd2\x21\xd6\x4a\x55\x68\x9b\x64\xbd\x08\xb8\x90\xe3\x8f\xf2\x43\x56\x11\xe3\x8a\x52\x56\xd6\xd5\x6b\x97\x71\x54\x3b\xb2\x60\xc5\x68\x7e\xcc\x48\x47\x84\x3a\x89\xdd\xe3\xf6\x27\x6e\xd2\xf1\xdc\x28\x61\x08\x43\x56\x78\x37\x3c\x9c\x3e\xae\xad\xcb\x81\xab\x32\xb3\xb8\x77\x97\xf8\x9e\x4a\x43\xd3\x6e\x70\x50\x12\xe6\xd0\x8c\x67\x5d\x1d\xfa\x7a\x24\x2a\xa2\x14\x73\x54\xe5\x00\xe1\x1f\xd3\x82\xb4\xed\xef\x7f\x48\xab\x22\xfe\xc9\x9c\x50\x1f\x6f\xc9\x75\x7e\xb4\x13\x1e\x79\xb8\xd7\xf3\xdb\x1a\x7b\x69\xfe\x47\xec\xb0\x7a\xd9\x99\x12\x23\xd7\x92\x59\x8c\x66\x58\xf2\x42\xed\xbb\x72\x70\x38\xfe\x6e\x59\xb0\x5d\x0d\x74\x00\xa1\xcd\x0c\x80\xf5\x36\xf6\xca\x94\xdb\x7e\x96\x3d\xe0\x1e\xe6\x03\xb1\x64\x33\xac\x9c\xdf\x0e\x9e\xc4\xee\x06\x0a\x68\x73\xe3\x26\x8a\xf1\xe0\x49\x8f\xad\xbf\x2a\xe4\xd5\xdd\xbe\x78\x5c\x77\x4d\x28\xb4\x3b\x7f\xbb\x07\x08\x5c\x2d\x73\x00\x85\x2a\xed\x55\xad\xbc\xf2\xb5\x03\x3f\xcb\x1e\xf0\xeb\x95\xd6\xd5\x0c\x87\x7e\x59\x3c\xb9\x94\x16\xe7\xc6\x4d\xf4\x76\xa5\xb5\x32\xdb\x21\xd5\xa2\x29\xea\x10\xc7\x65\x94\x7c\xa0\x8f\x6d\x8d\x09\xc6\xc7\xad\xc8\xf7\x59\x75\x85\x8a\x45\x79\x6a\x8e\xcd\xb8\xf1\xed\x0e\x3c\x1f\x67\xe8\x73\x97\xe3\x07\x06\x1e\xed\x97\x2f\xf1\xe4\x53\xee\x57\xf3\xae\x79\xf5\xd2\xd9\x2c\xf4\x49\x96\x51\x4b\xe6\x3e\x32\xe9\xaa\xe0\xda\x73\xa9\xee\xd3\xa7\x76\xcf\x38\x32\x01\x7a\x01\x35\x77\x53\xcb\x80\x37\x3e\x7e\xe0\xe3\xe1\x48\x35\xe6\xe3\xe2\xd6\x38\x00\xe5\x72\x8d\x32\x06\x02\x9c\xe6\x71\x92\xc6\x52\x13\x21\x0f\xde\x8c\xd6\xd7\xde\x2c\x76\x6f\xad\x84\xc7\x29\x58\xe3\xf8\xdb\x6f\xde\xfd\xda\xbb\x16\x5e\xc1\x6b\x11\x7c\xf5\x24\xf8\x58\xcf\x82\x15\x3f\xd6\xb1\x46\x40\x20\xac\xd3\x9c\xab\xee\x20\x1a\x8e\x1d\x98\x91\xee\x40\x49\xa3\x9d\x1e\xd2\xbf\xde\xd0\xc5\xed\x91\x7e\x9f\x7c\x61\xf7\xb9\xd7\x47\xf1\xc8\x7e\xf3\x60\x56\x92\x91\x53\x19\x4e\x2f\xc8\x7d\x7e\x12\x43\xf9\xa4\xf0\x9c\x5b\xad\x18\xda\xb0\xb3\x81\x96\x0e\xfb\xcb\x68\xb1\x6f\x97\xf9\x6e\xa6\x47\xb7\x94\x2a\x27\xa7\xb3\x5d\x96\x46\x06\x1a\x21\xbd\x1e\x5b\x7c\x25\x79\xd6\xb6\x54\xc0\x11\x18\x2c\x25\xa4\x79\xce\x13\x90\x79\x2a\xf2\x90\x78\x80\x76\xae\x89\xa3\x89\x93\x4d\xa1\x8f\x53\x1a\x73\xde\x4a\x6b\x8c\x7e\xe8\x4f\x7d\x08\x38\x2c\x86\x3b\x06\x3a\x69\x70\xfe\xcc\x75\xa4\xcd\x02\x34\x98\x19\x3d\x1b\xe7\x3d\xd6\x77\xcb\x89\x36\xd8\xd5\xe2\x24\x19\xe7\x46\xfe\x05\x39\x54\xdf\xc0\x15\xa3\x11\x8f\xc9\x38\x60\xa8\x55\x57\x92\xe7\xf8\x57\x3f\x9b\x2a\x7b\xf9\x29\x3f\x1f\x85\xb1\x50\x7b\x37\x86\x92\xc6\x1d\xd9\x6b\x89\xed\xd5\x41\xa6\xc1\xe9\xcb\xb2\xcc\xc4\x90\xba\x6d\x9e\xaa\xd6\x47\x88\x31\xae\x24\xa6\xd0\x15\x7d\xa8\x8f\x1f\x81\xbb\x21\x45\x28\xfb\xff\xc9\x60\xda\x35\x26\x9c\x97\xc6\xfa\xde\x14\xff\xc1\x9b\x0e\xcf\xb0\x62\x9f\xa1\xfe\xd8\x85\xd8\xe9\x55\xe1\xa1\x4b\x6d\x16\x09\xe1\x5c\xc7\x6b\x61\x4e\x39\xb3\xa7\xec\xc9\xd1\x3b\x00\x18\x7b\xec\x87\x1e\x47\x37\x62\x7a\x86\x72\x58\x02\xd5\x29\x18\xda\x81\xa9\x9c\x85\xa0\x2b\x85\xac\x68\xe5\x7a\x0a\x6b\x84\x5e\xf8\xc1\x3d\x2b\xea\x1d\x70\x40\xcf\xd3\x64\x57\xa4\x1f\xc6\xf6\xd5\x41\x3d\xaf\x24\x90\x38\xea\x70\x38\x2f\x50\x8c\xfa\xc1\x4e\xd7\x9a\xcd\x25\x43\x44\xcb\x5d\x20\xc0\x85\x18\x05\x35\x87\x9d\xc3\xd6\xdc\xdc\x0f\x52\x7e\x5e\x83\xf6\x08\x20\x50\x83\xe1\xed\xa4\xdb\x44\x73\x95\x6c\xf0\x41\xcc\x2f\x0c\xeb\x7a\x50\xe7\x45\x81\x19\x64\x0c\x46\xc8\xc6\xaf\x0b\x12\xf8\x93\xa0\x69\xde\x48\xc2\x60\x4d\x89\x58\xdf\x35\x9b\x68\x97\x7a\x8e\xf4\x3b\x4f\xee\x43\x3e\xda\x8e\xa4\x5f\x46\x2d\xcf\x00\x65\xb4\x8d\xbf\x28\xe2\xdb\xe9\xf7\x9a\x48\x14\x68\x84\x97\x3b\x19\xbf\xdf\xcc\xe6\xbd\xd1\xd4\xdd\x6a\xe1\x0c\xa1\x8f\x4d\x44\x77\x33\x86\x23\xa3\x3d\xd0\x08\xfe\x16\x06\xf0\x57\x37\x7e\x6f\x12\x45\xb0\x2c\xc2\x0c\x5e\x47\xf6\xb1\xb8\x01\xf0\xc4\xfe\xa8\x49\xe9\xb9\xbe\xab\x81\x83\xdc\xe7\xce\xd5\x17\xf7\x87\x91\x01\x84\x9d\x09\x7a\xe3\x19\x06\x7e\x54\xdf\xb3\xd4\x83\x0f\x5b\xac\xf0\xe7\xe5\xe5\x6d\x12\xaf\x73\x7c\xd5\xd5\x03\xad\x33\xb4\x01\x12\xfc\x80\x83\xb8\x83\x00\xee\xc4\xe8\xf3\x92\x36\xca\x7b\x48\xed\x1e\xb6\x79\x98\x71\x85\x1e\x66\x14\x5f\xe5\xfa\x28\x7e\xd9\xf1\x7b\xb8\x85\x76\xe5\x58\x15\xb7\x69\x53\x15\x05\x5b\x25\xb3\xa7\x11\xcc\xab\x23\xce\x45\xc5\xd8\xb3\x5e\x09\x3f\xd0\x38\x5f\xad\x26\xd1\xf0\x9f\xe9\xcc\xfb\x0a\x99\x13\xc9\x21\x17\x75\x83\x5d\x36\xe7\xf5\x5a\xf3\x6d\x49\xd9\x7a\xcb\xc9\xba\x48\xe3\x3d\x61\x89\x1c\xb1\xd4\xee\x9f\x28\xce\xf5\x4a\xf5\x71\x17\xfd\x53\x7e\xae\xab\xa6\x23\x5c\xd4\xda\x26\x96\x59\x66\xbe\x1d\xcf\x59\x1c\x96\xc7\xa2\xf3\x01\x9a\x8b\x23\x21\x4b\x4d\x98\x02\xdb\x40\xd1\xef\x02\x19\x74\xcc\x2b\x43\x5d\x55\xdb\x30\xd2\x00\xf6\x1f\xf9\xa3\x57\x28\x1c\x67\x08\x3b\xc3\x81\x3f\x59\xa4\x29\xc9\x9b\xb9\x54\x21\xb1\x17\xf0\x06\x71\x82\xdc\x58\x22\x2f\x71\x46\x9f\xf3\x94\x4a\x25\x5b\x3e\x24\xf5\xcb\x47\x52\x66\xd1\x87\xaa\xc9\x69\xd9\xf1\xe8\x4c\x41\xca\xac\x4d\x49\x4d\x75\xfd\xbb\x07\xa3\xef\x84\xe3\x30\xb0\x3a\x4f\x12\xfd\xbd\x97\xde\xde\x93\xbc\xa4\x4d\x7c\x28\x2e\x79\xf6\x84\xd4\xe4\x02\xe1\x16\x8b\xcd\xe0\x0a\xc4\x8b\xff\x84\xd8\xba\x7b\x3f\x2b\x74\x97\xf6\xbc\xa5\x41\x98\x03\x85\x3e\x61\xa5\xa9\x25\x50\xf7\x5f\xb0\x1b\xfa\xe6\x09\x68\x66\x19\xaf\x33\x68\x46\x15\xc8\xae\xae\x77\xb0\x60\x2a\xf7\x0b\x7e\x57\xd2\xbe\xcb\x68\xa6\x1d\x58\x24\xd7\xf1\x1e\xc2\x48\x78\x83\x24\x86\x75\x0d\x12\x15\x2f\x3a\x20\x7f\x31\x2f\x7f\x62\xe1\x6e\x9d\xea\xcc\x8a\xae\xf5\x54\xf7\x4d\x6f\x10\x90\xe8\xa0\xe9\xca\x0c\x71\xeb\x95\x88\x5b\x87\x1c\xc9\x9a\x27\x56\x3b\x58\x8d\x70\x81\x39\x7c\x1c\x89\x73\x63\x84\x54\xd4\x14\x75\x12\xc3\xba\xf7\x69\x18\x51\x3a\x43\x8a\xbf\x27\x73\xd0\xea\x70\xc0\xd4\xd9\x66\xc3\x52\x02\x78\x15\xc4\x77\x33\x92\xa9\xb1\x26\xfa\x2d\xd8\x87\x87\x2e\xee\x83\xf6\xc9\x70\xc5\x0c\xcd\x90\x3b\xea\xb7\xdf\x22\x7f\xc3\xeb\x4f\x9a\x04\xbc\x39\x46\x74\x59\x4d\xf3\xb4\x2a\x63\xe9\xef\x3a\x53\x2f\xcd\xe7\xfa\x5b\xf6\xf8\xf9\x04\x7b\x68\x99\xb5\x7c\xd2\xeb\x83\xa2\x5e\x5e\x6b\xf6\x40\x6f\x9b\xab\x1e\x4b\x33\xe4\x76\x96\xdc\x58\xd8\x4c\xfb\xb1\x16\x1b\x9b\x44\x02\x12\x6c\x3d\x69\x2f\xb8\xe9\xe3\xd5\x7a\xed\xd4\x35\x3c\x35\xc7\x41\x35\x67\x63\x36\x47\x6d\xb2\xa0\xd7\x9d\x07\x7d\xe6\xd6\xfe\x11\xac\x26\x94\x33\x6a\xfa\xb2\xf6\x43\x93\xa3\xca\xa9\x74\xf0\xed\xbe\xaf\xb3\x41\x66\xba\x80\xc1\x58\xb9\x50\x58\x8f\x0c\xaf\x49\x6a\xa7\x67\xe4\x3d\xa4\xb9\xb2\x09\xa3\x1c\x80\x00\x01\xd2\x69\xe1\x24\x4c\x5b\xeb\x07\x96\xb1\x3d\xde\x08\x57\x0e\xcf\x6b\x57\x97\x52\xb3\xcd\x59\x46\xa9\x7a\x62\xb7\x48\x85\xae\xac\xe5\xe8\x3b\x74\x18\x18\xe3\x40\x98\x3f\x7b\x20\xe0\x56\xf9\x50\x35\x67\xec\x50\xd2\x2a\xd0\xdc\x9a\xae\xa3\x61\x6f\xed\x99\x21\x78\x51\xeb\x8c\x0e\xdd\x6b\xf1\x3b\x91\x00\x2c\xd9\xc0\x1d\x17\xc8\x21\x84\xaf\x74\xc4\xfa\x5e\xfa\x75\xdf\x5b\xb6\x6b\xfa\x55\xde\x5b\x76\x56\x13\xfe\xde\xb2\x46\xe2\x6e\xef\x2d\x3b\xa9\x9a\xa7\x52\xdd\x80\x8e\xf7\x96\xc3\x10\x7c\xef\x2d\xbb\x28\x04\xbe\xb7\xac\xa1\xdf\xe7\xbd\x65\x9d\xe4\xf0\x02\xae\xf6\xfd\xb7\x7b\x6f\x19\x65\x47\xbd\xb7\x8c\x30\x35\xfe\xde\x32\x4e\xd2\x71\xca\x12\xa9\xe1\x4e\xef\x2d\x6b\x94\x6f\x7f\x6f\x39\xd0\xcd\xc1\xed\x8c\xbd\xe5\xe3\x1e\xcd\xe6\x75\xbb\xd1\x4d\x94\x6b\x2c\x20\x1a\x13\xd4\xa6\xbf\xc4\x13\x87\x1b\x8f\x10\xdc\xc7\xc7\xc2\x3c\xd6\x91\x60\xbd\x19\x8c\xbf\x3d\x52\x8f\x07\xb0\x46\xb9\xc0\x16\xd0\x16\x23\x4b\x6b\x47\xe1\xd7\xbb\xbb\x2b\xd7\x99\xfa\x49\x42\xc4\x0f\x01\x0e\x87\x8d\x3b\x05\x19\x79\x21\x89\x19\xbe\x51\x31\x43\x96\xed\x82\x88\xc8\xb0\xab\x11\x59\xe2\x44\x90\x85\x1f\x7d\xe9\x6c\x74\xdc\x71\xba\x22\xe8\x66\x52\x77\x78\x99\xe6\xca\x58\x57\x7a\xc3\x2f\x0c\xac\x73\xc8\xd2\x04\xea\x74\xc7\xb5\x87\xfc\x66\xda\x2a\xdf\x8c\x9f\x23\xae\x25\x4a\xe8\x7f\x23\x74\x8d\xd1\x8d\x0c\x45\xf8\xc2\x2d\x76\x62\xe9\xa1\xff\x87\x9c\x90\xa3\x9b\xfe\x9f\x83\x98\x1d\x50\xc2\x8f\x17\x3a\x71\xcc\x65\x0a\x0e\x84\x9e\xc7\x62\x07\xea\xae\x39\x49\x88\xd1\x57\xda\x13\xce\xb7\xb6\xfc\xb8\x1e\x6d\xac\xc5\xfa\xf9\xcf\xd0\xf7\x7b\xc3\x5b\xdc\xd3\x37\xf6\x88\x47\xc1\xf4\x6d\xf3\x71\x70\xfb\x90\xa8\x38\x3d\x87\x9d\x8b\x0c\xd1\x2f\x46\x5e\xcb\xf0\x18\x06\x18\xc8\xb8\xf7\x7c\xab\xbc\x50\xf3\x16\x2d\xb3\x12\xf5\xa8\xa7\x07\xb4\xd3\x8b\x6e\xdc\x31\xad\x11\x50\x63\xaf\x25\x04\xd6\x66\x84\xde\x10\x4a\x0f\x0f\x0f\x23\x94\xec\x5d\x23\x13\x42\x39\x35\xb7\x58\x1c\xd6\x6f\xf0\x64\xf0\x08\x50\xa0\x26\x58\x27\x89\xaf\x54\xe0\x40\x4f\x13\xa9\x7b\x2c\x1a\xa4\x59\x1a\x6d\x56\xb8\x8a\x98\x71\xec\xe3\x7a\x7c\x70\x1c\xc4\xb0\x4a\x63\x43\xe4\x36\xa6\x07\x5b\x75\x13\xcf\xae\xf3\x2e\x37\x12\x41\x5a\x2f\x34\xc3\xa7\x1a\x37\xb6\x1c\x18\xbc\xdb\xd8\xc6\x0c\xe1\xdb\xc8\x20\xed\x17\xf6\x31\xa4\xf7\xbd\x23\x5a\xa5\x8d\x0a\x9f\x53\x1d\x8f\x67\x80\x77\xb7\x4d\x44\x2d\x3f\x55\x40\x45\xd6\x53\x24\x4e\x80\x9b\xd8\x40\x1e\x1a\x09\x00\xf5\xbe\xfc\x33\xd6\x82\xab\x70\x30\x1f\x04\xbc\x8c\x2e\xf0\xf2\xf2\x99\x36\xe2\x88\x04\xf6\xe0\xf7\x7c\x8e\xf8\x95\xc9\x43\xff\xcf\x41\xc9\xed\x57\x6e\xb3\xfe\x5f\x08\x9a\x29\x51\x1c\xe8\xaa\x53\xad\xee\x19\xdf\x24\x6e\xf9\x95\x41\x7c\xa3\xae\xe5\x55\x98\x63\x8d\xf6\x7a\x97\x77\x68\xb7\xc3\xbb\xf4\x82\xd9\x53\xb3\x1f\xdc\x1e\x69\xee\x63\xc8\x41\x5a\xe6\xf4\x2e\x47\x00\x03\x19\xf7\x7a\x97\x4b\xf1\x2e\xf5\x5b\x74\xcd\xe9\x5d\xda\x16\x08\xc7\x1d\xd3\x9a\x30\xef\x32\xb4\xb6\x71\xef\x12\xbc\xb9\xe5\xa0\x64\x7b\x97\x26\x84\xcb\xbb\x9c\x25\xfd\xbf\x10\x8d\x30\xbd\x4b\x0f\x50\xa0\x26\x38\xbd\xcb\x40\x05\x0e\xf4\x2e\x91\xba\x5d\x33\x3b\x92\x1c\xdd\x65\xa8\x35\x27\x26\xb4\x0a\xfd\x99\x07\x5f\x03\x6f\x22\x8f\xf8\xc7\xd2\x5c\xde\x4e\x0f\xf1\x95\xae\xc3\x47\x9c\x24\xd1\xc1\x57\xb9\xc8\xe1\xdd\x88\xba\xc8\xd7\xa3\xbf\xa5\xe1\x5e\x17\xd9\xdd\xfa\x37\x76\xbf\xcb\x45\xbe\x85\xc0\x9b\x5a\xef\x77\x91\x85\x91\xbf\xda\x45\x36\xeb\xb7\x3c\xd7\x20\xdf\xc0\xe1\x9e\x7a\x8c\x2c\xea\x25\xfb\xeb\x72\x39\xca\x36\xc0\x4d\x9c\xb8\x1d\x65\x1f\x68\x88\xa3\xec\x6c\xc1\x55\x38\x98\x3b\xb5\x5c\x2e\x65\xb3\xf6\x0d\x25\x59\xda\x5c\xce\x7b\xfd\xb4\xc1\x83\x7d\xd8\xc0\xbc\x36\x10\xfa\x4c\x11\x7b\xd0\xc5\x7f\x10\x6b\xe0\x42\x9e\xb2\x70\xec\x34\x23\xe0\x9f\x8a\x7c\xb7\xa7\x87\xaa\xa1\x7a\x0b\x12\x79\x07\xca\x58\x0e\x0e\x6f\x40\x7c\xfe\x4b\x92\x90\xe4\x3d\x42\x15\x5e\xf7\x40\xd6\x62\x35\x39\xe6\x25\x3b\x09\xe8\xe6\xd5\xbe\x76\xa0\xbf\x0a\x95\x18\x59\x80\x11\xa9\x0c\xd5\x38\xa4\x82\x02\x32\xc7\x40\xff\xd2\xd6\x24\xf0\xe9\x83\x47\x57\x1e\x21\x2b\xe7\x81\x75\x78\xcb\xf5\xcc\x90\x7c\x27\xe7\xaa\x47\x80\x7c\xb7\x94\xd1\x56\x6b\x99\x21\x2c\x09\x68\xa5\x4a\x1a\xf6\x26\x63\xd8\x0e\xdb\x48\x0e\x59\xbd\x66\x90\x48\xc2\x66\x0b\x14\x2a\xae\xde\xb2\x8d\xe7\xe2\x02\x2c\xbf\xcc\xef\xf2\x6d\x67\x5b\x63\x80\xeb\x88\x14\xfa\x1e\x3c\x0d\x4e\x72\x80\xf7\x26\x5c\xa6\x61\x9f\xb1\xb6\x18\xb3\xbc\xc9\xb5\x2c\xee\x59\xc7\x11\x41\x8b\xdd\xe5\xd0\x98\xea\x69\x2d\x0d\xcd\x0d\xbb\x8c\x6f\xbd\xc6\x8b\xdf\x51\x85\xdc\x68\x8b\x41\xbc\x00\x6d\x85\xe9\x06\x58\x02\x52\x00\x88\x88\xb4\x32\x5c\x2d\x0c\x18\x67\x32\x8e\xe0\x9c\x1b\xba\x0d\xf0\x6b\x4c\x5c\x1c\x6d\xc3\x27\x3e\x0e\xb6\x2f\x24\xbb\x97\x8b\xb6\xc7\xbc\x20\x00\xd8\x58\xd6\xac\xc5\x7a\xd4\x9e\xac\x3d\xbc\x38\x4d\x8a\x5d\x3e\x6e\x55\x50\x56\x2c\x10\x84\x97\xf6\x8c\xc8\x9c\x7f\xb4\x65\xee\x49\xd9\xe6\x22\xed\x13\xb9\x0d\x30\x2a\xf2\xc5\xa8\xc8\x17\x1e\x5e\xdc\x22\xb7\xca\xc7\x45\x8e\xb2\x62\x81\x00\x5e\xc4\x50\x0a\x72\x27\xf0\x44\x7d\xae\x54\x43\x9c\xf8\xa8\x77\xc1\x60\x64\xcb\xf9\x1f\xaa\x99\x63\xde\x8f\xe8\xfc\xa5\xeb\xa0\x7f\x70\x4a\x12\x75\x60\x7e\x65\x0a\xc7\x9c\xe0\xe4\xa7\x37\x27\x2a\xe2\xb4\xa6\x25\x7d\xe9\x40\xeb\xf9\xdf\x4a\x00\xf0\xe4\x84\x81\x58\x37\xf4\x39\xaf\x2e\x2d\x44\x56\xdf\x4c\x02\x30\xef\x82\x80\x35\xad\xbd\xfe\xcd\x68\xb2\xd3\xc6\x6b\x65\xaa\xd6\xb7\x18\x66\xc9\xe6\x70\x5c\xcf\xd0\x02\xad\xff\xa7\x73\x7a\x8e\xa6\xeb\xfe\x3f\x0b\x7a\x36\x4c\xc0\x66\xf5\xbb\x47\x33\x29\xe5\x66\x2c\x29\x25\x7c\xb0\xd1\xd2\xf5\xc0\x94\x9a\x7b\xd2\x52\xf5\x06\xbb\xae\x61\xd3\xf9\x8a\x9e\x45\x1b\x09\x6f\xa4\x94\xb5\xfc\xd3\x19\x29\x1b\xcd\x36\x25\xd2\x81\x6b\x22\xdc\xd1\x73\xdd\xbd\xea\x82\xb4\xde\x1e\x19\x84\x8d\xbb\xf1\xea\x7a\xb9\x46\x7a\xec\x78\x0d\x58\xd6\x68\xf0\x3f\x9e\x1a\x7a\x18\xd6\xb4\x58\x99\x37\xab\x15\x3f\x05\xa3\x93\xae\x9b\xfc\x4c\x9a\x57\x17\x8a\xee\xf5\x68\x28\x28\x37\x7a\x99\x97\x9b\xf9\xc3\x3a\x19\xde\x1e\xe4\xe8\xed\x25\x4d\x69\xdb\x3a\x1b\x90\xee\x1f\x56\x29\x8a\x82\x72\xa3\x97\x79\xb9\x59\x2e\xb7\xd9\xb0\x04\xe7\xe8\x79\x79\xa8\x9c\xac\xec\xd3\x24\xa3\x36\x3c\xca\x07\x28\xf0\x32\xb1\x98\xed\x93\x6c\xa5\x13\xfd\x4a\x9a\x52\xbe\x13\x8e\x8d\xfc\x84\x64\x4b\x8a\xa2\xa0\xac\xe8\x65\xfe\x24\x68\xe9\x76\x33\x3b\x18\x9a\x48\xca\xa3\x1b\x23\xdb\xae\x16\x4b\x14\x03\x57\x5d\x58\xe4\x65\x25\xdd\x2e\x92\xb9\xea\xf8\x3d\xc9\x8e\xd4\x3f\xd1\xc1\xf7\xa0\xcd\xeb\x89\x8b\xfa\x25\xda\x38\x53\xd5\xfe\x9d\xad\x1e\x6a\x0d\xb0\x19\x17\x9c\xbf\x64\xf2\x08\xb2\x57\x83\xe4\x02\xed\xd5\xf0\xec\xc4\x4b\xfb\x04\x68\x88\x67\x32\x5e\x5a\x48\x73\x38\x9f\x3b\x38\xf6\xda\x3b\x48\x44\xb0\xaa\x0c\x37\xff\xf3\x7e\x86\xbb\x77\xa9\x38\xbb\x79\x47\xcf\x72\x9d\xa8\x58\x1e\x72\x15\xa9\xb5\xe9\x13\xe0\x1f\x59\x03\xfa\xa7\x5a\xbd\x3a\x48\x0a\x73\x40\x70\xf0\x4f\x00\x4b\x3f\x98\xb9\xc2\x53\x33\xe9\x3c\x6b\x01\x13\xe0\xa2\xfe\xf5\x72\xde\x57\x5d\x63\xe6\xa1\x5e\x20\x37\x96\x64\x10\x51\x26\x6e\x17\x2d\xcd\xcb\x13\x6d\x72\xd7\x3a\x19\x78\x64\x43\x55\xd3\xd3\x6c\x12\x81\xbf\x4f\x33\x28\x57\x41\xd0\x46\xab\xb1\xe3\xd5\xc8\xfd\xe1\xf9\x0c\x19\xa2\xf3\x24\xb1\x28\x3e\x9d\x1a\xd3\xdd\x57\x26\x6a\xd5\xff\xb3\x72\x0b\x00\xae\xed\xfb\xf7\x91\x21\x4d\x77\xae\x69\x20\x8a\x81\xf4\x2f\xce\xd7\xb6\xc4\x16\x5d\x9b\x36\x94\x96\x11\xcb\xbb\x30\x18\x2e\x78\x94\x58\xaf\x7f\xe8\xce\xe5\x83\xb8\x3b\xf5\xef\x5a\x66\x81\xab\x5a\x63\xe6\xa9\x90\xcf\xe7\x1b\x6b\x9b\x35\xb8\x53\x38\xda\xe3\xb0\xd7\xd6\x0b\xfd\x36\x5d\x77\xba\x9c\xf7\x25\xc9\x0d\x27\xd5\x5e\xa3\xe0\x67\xc6\xe7\xd8\x2d\x55\x23\xb3\xe4\xdb\x17\x34\xc6\x43\xf9\x6c\xe7\x45\xd8\x4b\x0e\x19\x4d\xe7\x6d\x44\x49\x4b\xe3\xbc\x8c\xab\x0b\xbf\x5e\x57\x05\x02\x8e\x43\xd9\xc2\x62\xd9\x3f\x27\xd1\xf0\x05\x64\x03\x85\x56\x43\x5e\xf6\xd0\x0c\x03\x48\x2e\x43\x06\x0a\xea\xe1\x5a\xf0\x6d\xb0\xcd\xc3\x27\x67\x62\x4d\xdd\x3b\x1c\x78\x9d\xa6\xa4\x56\xa1\x78\x78\x37\xfd\x11\x3f\xf1\x44\x0a\xda\x74\x46\x44\xc8\xbf\xd1\xf1\x86\x1b\xe6\xbc\xb2\xd3\x12\xbf\x59\x82\xdb\x2a\x8e\xc3\xff\x67\xd8\xec\x32\x5d\x05\x0d\xfa\xa9\x9e\x08\x84\xa7\x4b\x81\xde\x1f\x31\xc0\x3f\xd5\x16\x47\x2b\x83\xeb\x38\xcb\xdb\x73\xde\xb2\x65\xa3\xa4\x2e\xbf\xb1\x6c\x39\xbf\xd8\xf9\x96\x16\x3e\x22\xd1\x34\x2d\xaa\x16\xa7\xc5\x8b\x46\x9d\x05\xe1\x36\xc9\x8b\x08\xd2\x46\x7b\xe4\xa8\x79\xf9\x4a\x1b\xd2\xcd\x7a\xe1\x5a\xde\x66\x87\x43\x92\x61\xf7\x0d\xb2\x35\xdd\xa6\x6b\x9c\xba\x7b\x0e\x48\xb7\x74\xbe\x5f\xe0\x58\x66\x1f\xab\xd5\xca\x7e\xb5\x1c\x3c\x50\x0e\xa4\xd6\x07\x83\xff\xbe\x49\x1e\x5c\x87\x33\xb2\x2d\xcd\x0e\x58\x64\x79\x9f\xd2\x87\xc3\x0c\x21\xed\x6e\x01\x59\xd3\x19\xc5\xb8\x71\xb2\xbf\x5c\xcd\xd7\x5b\x1d\x01\xae\x2c\xd4\x51\x6d\xb2\xce\x16\x7b\x97\x11\x4d\x0f\x0f\x74\x81\xb4\xe0\x40\xe8\x3e\x4d\x71\xea\xee\x46\x1c\x36\x74\xb6\x5f\xe1\x58\xae\x76\xac\xd7\xab\x99\xd9\x0d\x60\x4d\xa2\xe4\xb3\x5d\x2e\x97\x73\x57\x33\xe6\x19\xcd\xb0\xad\x8f\xbe\x11\xd9\x0c\x25\xee\x6e\x05\x5d\xee\xb7\x69\x82\x22\xb9\x1a\xf1\xb0\x5c\xac\x16\x72\xad\xf9\xcf\xdf\x7e\x23\x67\x99\x2f\xf4\xf5\xd0\x90\x33\x6d\xa3\xba\xa9\x8e\x0d\x6d\xdb\x78\xcf\xd2\xe2\x34\x79\x4d\xf9\x70\x39\x34\xd5\x39\xfa\x05\x34\x6a\x18\x9a\xcb\x84\xfb\x02\x8c\x6a\x67\x2d\x5c\x07\xc0\x21\xc5\xcb\xbf\xf3\xea\xab\xbf\x57\xcd\x7f\x8f\x6a\xa7\xb2\x2a\x06\x0f\x33\x26\x78\xa6\x9b\xc0\xb4\xdd\xbe\x7d\xf5\xc7\x80\xfb\xf7\x73\xe4\x3d\x5d\xef\xbd\x7a\x14\x41\x05\x2c\x81\x4c\xcd\xa0\xe6\xe3\x90\x12\x85\x4d\x7b\xca\x91\x12\x09\xa2\xc7\x5e\xa3\x9a\xeb\x6b\x05\xff\x3a\xd8\xbb\xcd\xe6\x93\x49\x0c\x72\x07\x80\x16\xba\x1f\x25\xf6\x22\x60\xce\x1c\x3f\x17\x37\x5d\x73\xe7\x0b\x71\xe2\x6c\x00\x77\x29\x26\x78\xa1\xcc\xd9\x24\x1a\x3e\x8b\x4f\x91\xdd\x43\x76\x32\x0d\xc9\x74\x2f\x7d\xd2\xc4\xc7\x5e\xa3\x68\xd9\x7d\x58\xae\x32\x7a\x9c\x38\xd2\x2a\xac\x3e\xf6\x3e\xf8\x7c\xf5\xbb\x09\x74\x8b\x22\xeb\xc3\x2a\xf9\x9d\x9b\x04\x2b\x75\xa7\x65\x58\x7d\x8c\x36\x26\x3d\xf3\xc3\xc7\x47\xbc\x4d\xd5\xb5\xcd\x61\xac\xb3\xdb\xda\xff\x80\xcd\xf9\xbf\xb7\x2d\x6a\xec\x0d\x6d\xe2\x63\x9e\x99\xd6\x65\x62\xed\x0f\x19\xa5\x98\xc2\xab\x45\x85\xfa\x2a\x4f\xee\xd8\xea\x2e\xeb\x27\x65\x7e\x16\x11\x1e\x74\x22\x98\xb7\x42\xc8\x51\x5e\x1e\xf2\x32\xef\xe4\x48\xbd\x0d\xf1\x7a\x2c\x7c\x64\x5f\x13\xac\xf6\x0f\x7e\x17\xad\xff\x34\x02\xff\x98\x03\xe7\x3f\x8a\x11\x40\xf5\x3a\x7c\xdb\x63\x44\xa9\x31\x42\xff\xa9\xd1\xff\x78\x5a\xf0\x1f\x5e\xa3\xaf\xda\x43\x1b\x51\x6a\x07\xad\xff\xd4\xeb\x7f\x3c\x5d\xf8\x0f\xaf\xd7\xd7\xec\xc6\x8e\xa8\x35\x4e\xea\x3f\xb5\xfa\x1f\x4f\x13\xfe\x23\x6a\x35\xdf\x07\x33\xc3\xdf\xf0\x54\x19\x83\xb0\x1e\xec\x44\x1f\x62\x65\xa0\x93\x88\xff\x6f\xbc\xaf\x32\xbe\x2b\x8e\xc5\x70\x7e\xae\xd8\x56\xa3\x86\x39\x60\x0c\x1b\x76\x49\x62\x70\x12\x57\xfb\xbf\xd2\xb4\x43\xb6\xb0\x74\x30\x16\x16\x97\xbc\x3c\x4d\xeb\x4b\x51\x80\x4c\x3c\xc6\x1b\x08\x56\x25\xfd\x77\x03\x59\x65\x13\x32\x9f\x55\xb0\x90\xfb\x66\x28\x29\x40\x4a\x80\x01\xc7\x93\x2f\xe6\x09\x85\xae\xaa\x75\xda\x3c\xa5\x1c\x23\xe1\x7f\x16\x59\xb2\xa2\x52\x52\x5b\x87\x1f\x58\x91\x0e\x7e\xa2\x24\x93\x53\xac\xb5\x41\x83\x65\x58\xd3\x64\x96\xb7\x98\x70\xbd\xaf\x3b\x0e\x3b\xf3\xfe\x43\x9d\x5a\x5c\xd0\xb1\xad\xef\xd9\x30\x09\x79\xea\x11\xa9\x4c\x3d\x4f\x72\xe3\xa5\x0c\x83\x41\xd7\xab\xb7\xb7\xe4\x30\x73\x55\x61\x24\xb5\xf3\x64\x4e\x73\xdd\x99\x18\x39\x18\xbc\x04\x67\x4a\xb0\x0e\x00\xf9\x36\x9c\x70\xe6\x07\x4d\xef\xec\x5d\x4a\x8b\x00\x38\x7f\x68\x14\x38\x33\xc2\x5c\x75\xe1\x86\x05\x93\x5d\x47\x5b\xe4\xe1\xd1\x89\xd5\x0c\x55\x04\x6e\x05\x38\x41\xee\x70\x29\x00\x9c\x04\x71\x55\xe3\x14\xf5\x28\xf7\x6e\xcc\x80\x66\x85\x74\xb0\xb1\x41\x19\xde\x82\xbe\x2b\x6f\x60\x9f\xa1\xdd\xc2\xbb\x2f\xf9\x18\x7e\xee\x09\xe1\x8e\x17\x0c\xc7\xf0\xf0\xe2\xe0\x2b\x35\xb7\xdf\x9f\xc1\x6b\xbe\x46\x4f\x46\x30\x9e\xa6\xed\x99\x14\x05\x2a\xea\x31\xd4\x31\xcc\x5b\x54\x33\x08\x73\x9c\xe9\x31\x02\xa3\xf8\xfe\x91\x71\x3b\x66\x00\xeb\x23\x04\x18\xfe\x15\x43\xd3\xd5\x8b\x8e\x81\xe9\x97\x9f\x73\x58\xfa\x79\xb7\x06\x65\xba\xc9\x32\xea\x3a\x20\x78\xeb\xc1\x07\xd7\x04\xe4\xa1\x37\x8a\x72\xbd\x6d\x74\xd2\x72\xce\x83\x0a\x00\x49\x77\xe4\x6d\x75\x02\x4e\x75\x38\xa9\x82\xd3\x4b\x7e\x88\x61\x1e\x1c\x85\xbc\x26\xd9\x06\x68\x82\x61\xe9\x60\x0f\x58\x35\xde\x72\x68\xc4\x29\x0a\x07\x31\x3f\xfc\x3d\xba\xbe\x27\xe4\xee\x77\x56\x8a\x74\xba\xaf\xa5\xe9\x92\x2e\x0e\x4e\x5f\x8b\x91\xf4\xf4\x38\x28\xf6\xb3\x85\xcd\x71\x01\x7d\x3d\x70\x6e\xf4\x35\x94\xb7\x55\xe1\x8d\x27\x6c\x9c\x42\x70\xd3\x1b\x45\xb9\x47\xa7\x0b\x5a\x6e\x01\x4b\x00\xbb\xeb\xfd\xad\x26\x87\xb9\x3a\x3e\xe4\xa4\xea\xe9\x7d\x1d\xc2\x37\xde\x0d\xc8\x6b\xc6\x3b\x68\x82\xae\x03\x5a\x0f\x58\x35\xde\x76\x3a\xc9\x29\x0c\x27\xb9\x31\x8c\x7b\x28\x00\x27\xe5\xee\x7f\x51\x6e\x4b\xd5\xdb\x62\xba\x4f\x53\x4f\xf7\x73\xa2\x9e\xde\xd7\x00\x7c\x9d\xaf\x03\x5e\xd3\xf7\x80\x7f\xbd\xef\x35\xd9\x7b\x45\x7c\x45\x20\xc3\xe9\x65\x60\xeb\x68\xe3\x1c\xf4\x62\xb8\xae\x58\x52\xf4\xdc\xe9\xdc\xde\xd6\x1f\x0d\x27\x8c\x1e\xae\x75\x9d\xe4\xe1\xc7\x94\x66\xf6\x31\xa5\xc4\x3e\xc4\xe3\x83\xd5\x5a\x35\x44\xe8\xb4\xe3\xc2\x3a\x0c\x94\x3d\x1e\x66\x09\x7d\x35\x25\xec\xfa\x32\x7a\xa7\x18\x65\x09\x7d\xd9\x19\xe4\x65\xc3\xdd\x5f\x4e\xa2\xcb\xbb\x82\x06\xe9\x53\x62\x1e\xe3\x5a\xfb\x0e\xe6\x02\xea\xd2\x93\x8f\x90\x8f\xe2\xd2\xeb\xf0\xd9\xfc\x7b\x58\x04\x58\x5f\xf5\x4c\x85\x68\xfd\x87\xaa\xea\xf4\x8b\xd5\x66\x97\x05\x9c\xb9\x33\x9e\xca\x31\x0e\xf8\xbb\xae\x76\x8f\xc4\x9b\xcc\xbe\x7c\x02\x83\x54\x8a\xe0\x49\xb4\x42\xa6\x9b\x7b\x32\xe3\x8a\xae\x03\xe0\x16\x45\xcb\x58\x07\x55\x61\x22\xc9\xe4\x7b\xf6\x1b\x7f\xc8\x18\x76\x33\xa3\xc5\x0b\x7d\xc1\xc4\x10\x26\x83\x89\xe9\xcc\x8f\xbf\xfc\x70\xed\x60\xd4\x98\x02\xe1\x4a\x4f\x28\x33\xa8\x7d\x61\xa4\xf4\xd6\x05\xc7\x45\xaf\xd7\x53\x69\x73\x3e\xf9\x14\xc5\x17\x11\x96\x87\x44\xed\xb9\xe9\x93\x3d\x68\x3d\x78\x0e\xc9\x75\xe2\x2a\x83\x28\xc6\xfe\x8c\x1b\xda\xd6\x55\xd9\xb2\x9b\x7c\xec\x8b\x7a\xe0\xd6\x3b\x9c\xd0\xaa\x22\x71\x33\xc5\xa8\xc3\xf1\xd9\xae\x5a\x02\x0a\x16\x82\xdf\xb6\x36\x78\x33\xa9\x6b\x79\x33\x78\x29\x3e\xb2\xac\x22\x6b\x9c\xbc\x75\x58\x5c\xc9\xda\x53\xd7\x4f\xc6\xfa\x97\x46\xe3\x5d\x4d\x06\x37\xd0\xee\xb5\xf7\x1a\xda\xd7\x71\xe6\x96\xea\x68\xcd\xff\xf0\x62\x8f\xba\xec\x6e\xbd\x30\x5a\xd5\xe9\xb7\xea\xf0\x7b\xb6\x6a\xb4\x2a\x7f\xab\xee\xda\x1b\x77\x95\xf7\x5d\x25\xfa\x16\x99\x8d\x0f\x92\xdf\x60\x10\x80\xf9\xfb\x57\x1e\x03\x77\xaa\x29\xa0\xc3\x7e\xab\x9a\xbc\x6d\xba\x67\x4f\xdc\x53\xd6\xf7\x94\xe6\x1b\xe4\x65\x2b\xff\xd5\x53\x00\xc8\x60\x25\xd8\xc1\x9c\x51\xb3\x04\xf3\x2d\xef\xb0\xde\xb9\x8a\x3b\xd1\x87\xf0\x43\x13\xaa\xb5\x7e\xba\xbd\xb7\x19\x4e\xf7\x0a\x96\x9c\xf2\x1c\xa9\xf3\xff\x02\x71\x5f\x33\x6b\xbe\xa9\x9a\x70\x3f\xe0\x0d\x9d\x7c\xbf\xd6\x8c\x54\x33\x32\xcb\xde\x4d\xfc\xf7\x93\xf0\xfd\x84\x78\xb3\x9c\xd0\xe1\xf0\x1b\xeb\xfa\x5d\x0c\xcd\x68\x47\xfc\xfa\xe6\xec\x6e\x6d\x19\xed\xc0\xbb\x98\xd0\xb1\xb9\xf4\x5e\xd2\xbd\x9b\x00\x6f\x95\x51\x14\x60\xf0\xd1\x60\x44\xdf\xea\x4f\x66\x90\xc3\x2a\x02\xfd\x6a\xcc\x4a\x9f\x00\xb0\x4f\x1d\x3e\x99\x71\x72\x77\x68\x14\x1b\x8a\x21\xde\x9c\xc1\x59\x88\xd3\x86\x85\xf4\x50\x4b\xc0\x21\xa8\x59\x87\x1d\x8d\x51\x90\xa0\x91\x63\x44\x39\xa7\x4f\x5d\xf3\x64\x98\xc0\x68\x14\x7e\x64\x7a\x1b\x30\x7a\x5d\xba\xa6\x06\x05\x1f\x5c\x43\xef\x8a\x5e\x53\x83\x82\x0f\x9e\xa2\x83\xe5\x76\x1b\x8d\x37\xf0\xe1\x90\xee\x6d\x34\xde\xc0\x87\xa3\x0f\x6e\xa3\x71\x72\x05\x61\xd5\x23\xd7\xa1\x3a\xed\xf4\x69\xf1\x6e\xf0\x4d\x30\xa8\xcc\x43\xe8\x03\xf1\x86\xd1\x07\xb2\x0c\xa1\x0f\xc4\x16\x36\x41\xde\x28\xb1\x40\x55\xbe\x95\x87\x20\xa9\x06\xaa\xf1\xad\x3c\x04\x49\x3e\x50\x85\x5d\xab\xa2\xe1\xa5\xe1\x10\x25\xd6\x67\x91\x71\x2d\x36\x16\xe9\x01\x6a\x16\x5c\x03\x0a\x8f\xd4\x10\xa0\x27\x66\x9d\x6f\xa7\x71\x25\x1f\x8e\xb6\xbf\x9d\xc6\xc9\xf6\x87\xc2\xfb\x1a\x7a\x5c\x01\x5d\x0d\xc1\xbd\x3d\x2d\x46\x46\x28\x7d\x0c\xfc\xc6\x7e\xf6\xd6\x78\x2d\x81\x2b\x79\x08\x6a\xf5\xb5\x04\x4e\x8e\xdd\xca\x91\x55\xdc\xc8\xcd\x0f\x93\x80\x7b\x9f\x1c\x5e\xb6\x81\xa0\xfc\x8f\xb1\x0b\x26\xe8\x3b\x1c\x26\x91\x4f\x36\x2d\x33\x01\x9b\x8d\xa4\x1d\x31\xf1\x0a\x07\x45\xfb\xe4\xd9\x46\x56\xa7\x2a\xc2\x10\x07\x6f\x1f\xf1\xb1\x3d\xfe\xbe\x4e\x1e\xdd\xc8\xf5\x37\x85\xa3\x98\x0c\x45\x8e\xe5\x87\x7d\xd2\xc6\xe6\x48\x4b\x8d\xed\x79\x67\x02\xc0\x3e\x21\xdd\x01\xae\xef\x84\x9e\x1b\xb9\xb2\x1a\x5f\x2f\x38\x93\x8f\x06\xb6\x00\xc9\x49\x0b\xd8\xf5\x3e\xa6\x88\xd2\xc5\xbb\xc9\xc5\xb1\x58\xd2\x3a\x99\xd6\x52\x86\xfb\x2e\x79\x68\xe0\xbe\x5e\x7a\xf3\x75\x12\x5f\x4d\xb7\x74\xd4\x15\xed\x78\x43\xfe\x60\x94\xee\x9b\xfa\x0a\xe3\x5b\x4b\x2d\xe3\x4b\x9f\xa8\x81\x7b\x07\xd5\x1d\x72\x35\xfa\x2a\xbb\x69\x68\x85\x37\x05\xe9\x31\xc0\xb4\xeb\xa0\xbf\x97\xf4\xdb\x06\x18\xc2\xfa\x90\x3a\xc5\x97\x2b\x72\x80\xf5\x76\xd7\x1d\xb2\x52\x3a\x6b\xba\xa5\xaf\x42\x1b\x81\x75\xd4\xc0\xae\xeb\x94\xbe\x9b\xee\x9b\x7a\x09\x63\x5a\xcb\x05\xe2\x4b\x89\xa9\x81\xfb\xfa\xea\x1e\xf9\x37\x7d\x95\xdd\xd2\x5d\x57\x34\x05\x9b\xb8\x06\xa6\x5d\x67\xea\xbd\xa4\xdf\xd4\x69\x18\xeb\x30\xd3\x85\x2f\xff\x27\x84\xf6\x75\xd9\x3d\x72\x8d\x7a\xea\xba\xa5\xc7\xc2\x1b\x82\x75\xd8\xc0\xb2\xeb\x20\xbc\x8f\xf2\x9b\xfa\x4b\x67\x9c\x9e\xf7\x34\x33\x57\x14\xa1\x57\xeb\xe5\x91\x78\xfd\x3d\x82\x04\xcb\xe6\xe9\xac\xcf\xfa\x22\x0f\xe3\x5a\x90\xec\x03\x5b\xab\x59\x45\x39\x4b\x71\x8a\x21\xf1\x1c\x12\x58\xc9\x73\x9e\xd1\x4a\x9e\x31\x54\x0d\x26\xfb\xb6\x2a\x2e\xdd\x90\x7c\x59\xac\x73\xe0\x6d\x80\x21\x65\x01\x48\x37\x8f\x65\xf8\xb4\x56\x61\x56\x5b\x67\xeb\xfd\xeb\x56\x4b\x88\xa0\xee\x2a\xac\xa7\xf3\xd5\xef\x9c\x88\xcb\xfd\xeb\x02\xc5\xdb\x0c\x48\x5f\xa9\xb8\xec\x79\xce\x4b\x2b\xab\xe8\x70\xf8\x7b\xeb\xcf\x02\x3e\xee\xd6\x6b\xab\x0d\xba\xe8\xff\xdd\x9e\x9f\x35\xec\x1e\xc3\x38\x86\x26\x04\xa6\xb1\x7f\xbb\x54\x1d\xfa\x2a\xbb\x7e\x7a\x5d\x7c\xb5\xf3\x9b\x42\x8a\x71\x61\xdc\x7a\x98\xeb\xf9\x14\x90\x77\x0b\x18\x5a\x7b\xd6\xd1\xb6\x28\x16\xd8\xdb\x1a\x12\x84\xc3\xe7\x2e\x1e\x03\x1e\x6d\x18\x7d\x57\x25\x49\x86\x97\xd3\xf4\xfb\x21\x89\x5a\x2e\x1c\xf2\xa2\xeb\x3b\x98\x14\xf5\x89\x7c\xa8\x6a\x92\xe6\xdd\x6b\xf4\x43\x34\x4f\x58\x97\x88\x0f\xbb\x68\x3a\xd7\x18\x56\xb7\xdf\xf9\x5f\xf6\x35\x20\x58\x77\xc0\xe3\x23\x3e\x56\x56\x26\x2b\x32\x9f\xc3\xfe\xd2\x75\x55\x09\x24\xa8\x52\x61\xd6\x35\x25\x0d\x29\x53\xf0\x82\xaf\x6e\xbd\x90\xea\x87\x71\xc0\x92\x1d\xa3\xc3\xfb\x5c\x65\xa4\x88\xd9\x7b\xd4\x58\x36\x1c\x0d\xcc\x30\xb4\x87\xfc\x85\x67\x7f\x18\x8c\x4e\x03\x8c\xab\xcb\x00\xa9\xd4\x01\xb3\x64\x95\x3c\x9a\xef\xd2\x60\x86\x18\x8e\x41\x59\x16\xb7\x69\x53\x15\x05\x6b\x7f\x57\x5d\xd2\x13\x43\xbc\x74\xbd\xee\x98\xcd\x9b\x1e\x48\x46\x23\xd1\xd4\x2c\x27\x45\x75\xd4\x84\x0b\x53\xf7\x6a\xdf\xd8\xfb\xff\xd3\x85\x78\x82\x01\x7f\xce\x41\xfe\x89\xc2\x42\x40\x0f\x45\xb3\x4e\x01\x5c\x90\x8e\xf6\xe3\x39\x9e\xaf\x7e\xc7\x13\xb3\x9e\xdb\x00\xa0\x6a\x1c\xc6\x0b\xa0\xcb\x2e\x2f\xc7\x24\x87\xd0\x49\x46\xd9\x4d\xc6\x78\x4d\xbc\x8c\x26\x1f\x11\x05\x06\x5a\xaa\xd4\xe4\x05\x2a\x91\xfa\xfa\xaa\xbd\x7d\x61\xb7\x0f\xf7\x26\xc4\xd4\xa9\x3f\xa5\x61\xe4\x58\x62\x94\xc4\xc3\xd5\x1e\x52\xee\x5b\x76\x48\xf2\xdd\xb4\xc8\xeb\x5d\x34\xcc\x9a\xd6\x24\x87\x96\xdb\xf3\xdc\x76\xbb\xc5\x4b\x8c\x89\x63\xfe\x11\x9f\x16\xf4\x21\xe6\xbe\xdb\xb7\xa8\x5f\xfa\x59\xc2\x24\x8b\x5d\xed\x73\x82\xea\x02\xed\x1b\x9b\x35\x55\x7d\x77\x0b\xb4\x4c\x1c\xbd\x91\x24\x09\xce\x02\x37\x26\xbf\x78\xac\xbb\x61\xdc\x5d\x74\xf2\xd2\x4b\xc5\x39\x47\x08\x3a\xbd\xab\x2e\x5f\x11\x02\xbe\xd2\x6c\x3d\x5d\x2e\x4c\x77\x69\xec\x66\xe3\x77\xec\x05\x40\xbc\x02\x30\x19\xc1\x10\x78\x3c\x37\x95\xde\xbc\x83\x88\x5f\x44\x95\x0f\xf2\x18\x42\x51\x37\x37\xd1\xd1\x82\xde\xe7\xe4\x98\xe8\xdd\x40\xd1\x5e\x98\x76\x5e\xf9\x20\x8e\x18\x38\x26\x01\x41\x7b\xba\xef\xca\x4f\xec\x91\x33\xd7\x9e\x82\xf6\xa8\x8e\x8b\xc5\xe1\xd1\x34\x9c\xe2\xf0\x60\xbb\x1b\x9d\x39\x85\x9f\x86\x9f\x36\xbe\xa1\x6d\x7c\x96\xdc\x93\x26\x3e\x53\xd2\x5e\x1a\x73\xb1\x64\xad\x1d\xe2\xed\x76\x2b\x3c\x3c\x61\xee\x56\xc2\xab\x96\x7d\xb8\xb2\x1e\x3f\xe0\x95\x88\x8a\xc5\xe3\x55\x1f\x22\xf5\x64\x55\xa4\xbd\x59\x65\xd9\x5a\x59\xcf\x3a\x91\x2f\x4c\x49\xfd\x61\xaf\x92\x71\x3b\xcd\x1f\x98\xb2\xad\xab\xc3\x02\xad\xc4\xe5\x50\xdc\x04\xbd\x0b\x05\xd6\xeb\x15\x8e\xb0\xe4\x77\x91\x24\xda\x0b\x56\x58\xc3\xb7\xdb\xb9\xd1\xf0\x42\x6f\xf4\xd6\x20\x32\xed\xaa\xaa\xe8\x72\xd3\xd0\xc1\x6e\x02\xd6\x6b\x93\xe0\x8b\x5c\xe6\x54\x1f\xc8\x39\x2f\x5e\x77\xd1\xfb\x7f\xa5\xc5\x33\xed\xf2\x94\x44\xff\x46\x2f\xf4\xfd\x24\x52\x1f\x26\xd1\xbf\x34\x39\x29\x26\x51\x4b\xca\x36\x6e\x69\x93\x1f\xcc\xeb\xc1\xd8\xf3\x87\x4b\xcc\x4d\x9f\x2e\x7d\x1e\xaf\xcb\x26\x8a\xe6\x8e\x19\xc3\xad\x69\x0c\xb7\x26\x81\xae\xaa\x75\x23\xb0\x92\x37\x5a\x35\xab\x05\x96\x29\x12\xd3\xca\xbb\x28\x74\xc2\x1a\xd8\x08\x2e\xc8\x60\xe8\xaf\x18\xc1\x35\x53\x36\xba\xaa\x45\x78\x8e\xf3\x12\x79\x41\x6e\x9e\x60\x4f\x5a\x3e\x5c\xf1\x22\xc7\x35\x79\xe8\xc4\x72\xc8\xbd\x9d\x2a\x79\x25\x4d\x53\x7d\xf5\xe8\x33\xf6\xde\x48\x62\x2f\x6e\xf1\xdb\xf7\x22\x6b\x23\x33\xe2\x98\x4a\x20\x5c\x20\x5e\xc1\x8a\xc7\x3e\x74\xb1\xeb\x93\xa6\x34\x86\xfc\xe1\x4a\xeb\xd2\x31\xe2\x36\x00\x36\x78\x7a\x4e\x84\x97\xe1\x49\x47\xcb\x5f\x31\xb3\x3d\xde\x93\x1d\xae\xf2\x81\xb2\xc1\x93\x4f\xde\x8b\x1d\x27\x2b\x7c\xa3\x9d\x77\x8c\x9d\x71\x93\x8f\x66\x2f\x13\x26\x23\xfc\x2c\xae\x87\x15\x57\x27\x41\x4e\xa0\x7b\x19\xc6\x4a\x22\x99\x79\xd4\x0f\xef\xf9\x38\x11\x66\xc5\xc5\xcb\x4d\x9a\x8b\xf1\x61\x84\x59\x9d\x9c\x38\xf5\xd7\xf2\xbb\x75\x6d\xf1\x88\xe6\x4d\xec\xf8\x95\xc6\xa9\xbc\x77\x63\xa7\xae\x6a\x15\x1e\x1a\x8b\xc3\xe2\xeb\x8e\x35\x1e\xf9\x80\xd6\x7c\xb3\x36\xdd\x78\x30\x15\xdf\x67\x72\x5f\x86\x4f\xee\xe0\x1d\x4d\x38\x77\xa8\x47\xa3\xf4\x37\x8d\x9b\x33\x29\xfe\x6e\xcb\xdc\x34\x4d\xdf\xbc\xcc\xf5\xb8\x95\x89\xed\x29\xce\x91\x95\xad\x1b\xd6\xd0\x22\xe5\xba\x68\x5a\x0a\x83\x0a\x12\x70\xf0\x54\xb4\xf1\x8e\x81\x02\xc7\x44\x4b\x9d\x8d\x80\x2a\x3f\xc4\x58\x87\xd8\xa0\x60\x89\xa7\x94\xf2\xa1\x6f\xa6\xf6\x24\x2b\x92\x63\x66\xe9\x8e\xcb\x6f\xfa\x7f\x23\x8b\xd3\x7d\xff\x0f\xe9\x2b\x65\xe5\x23\x73\x64\xea\x11\x18\x10\xb9\x66\xbc\x18\xc0\x4f\x53\x66\x40\x26\x91\xf1\x61\x47\x0e\x9d\x77\x90\xdb\x8e\xf7\xdd\x7d\x19\x9d\xa3\x08\x49\xdc\x32\x73\xb5\x07\xb0\x2f\xa4\xb1\x8b\xde\xbf\xb7\x4d\x1f\xa6\x13\x5d\x55\xeb\x55\xca\x94\xd3\xc2\x06\x79\x26\x1f\x09\x82\x4c\xff\x5a\xfc\x09\x96\x98\x43\x64\xf5\xd1\x36\xc3\x56\xe6\x10\x8b\x55\xd0\x60\xa0\x45\x08\x87\xea\x91\x3a\x29\x95\xe8\xbd\x83\x63\x2d\xf3\xd5\x18\x27\x6c\x78\x42\xb1\xd9\x2e\x8c\x92\x8e\x3e\xd6\x75\x91\xe9\x8e\x8a\x2e\x34\xad\xcc\x2b\x36\xe6\x63\x84\xb0\x8a\x88\x4d\x89\x48\x18\x18\xaf\xbc\x74\x76\x75\x89\x79\x99\xe0\xb5\x59\x02\xbb\x51\xc9\xe0\xd0\xc3\x27\x70\x5d\x92\x7a\xa1\x2d\x4a\x2f\xb7\x40\x66\x32\x90\x74\x93\x9e\x8d\x33\x0d\xcf\x85\x01\x83\xed\x52\x33\xf9\xde\x6e\xb8\x9e\x21\x2c\x68\xee\xa9\x2e\x35\x58\x34\x2e\x33\xc0\x29\x90\x98\xcc\x8a\xa3\x2f\x7a\xc6\xc4\x15\xc6\x2d\x10\x57\x4a\x9a\xea\xd2\x52\x73\xd7\x4a\xc6\x15\x4d\x30\xb0\xa6\xf6\x46\xff\xe5\x46\xb9\x6b\xa7\x4c\xa7\xf7\x34\x0d\x4d\xfe\x2f\x5d\x40\x6c\x53\x4a\xbe\x24\x29\x5e\x01\x57\x5e\x97\xb1\x15\xe5\x02\x1b\x83\xf1\xb1\xfe\x24\x1f\x18\x47\x0b\xe5\x5b\xe3\xba\xb7\xa8\x07\xc4\x48\x51\xf0\x37\xec\xd5\x5e\x4e\xbc\xc8\x3e\x46\x93\xe8\x83\xbd\xd9\x16\x2f\xb2\x48\x84\xcb\x9c\x72\x0c\xdd\xb6\x5b\x5b\xef\xab\xfb\xb7\xee\x10\x78\xc7\xf6\x1d\x46\x19\xb8\xb3\x07\x92\xd2\xf8\x39\x6f\xf3\x7d\x5e\xb0\x68\xd5\xb0\x01\xf5\x6e\xac\x5c\xd2\xa9\x69\xd3\xd6\x94\x67\xa4\x64\x2f\x8d\xb0\x52\xeb\xab\x7a\xe2\x1f\x11\x96\x48\x68\x39\x95\x6f\x8d\xa0\x30\xa5\xcc\x21\x09\xd7\x29\xde\xed\xbd\x45\xf6\xa1\x1f\x02\x7c\xd8\x7f\x1c\xc4\xe4\x05\x0b\xe1\x53\xbc\x45\x82\x82\xd4\x0d\x7d\xbe\x9a\xcd\x38\x90\xcf\xf8\x3a\x46\x7d\xa2\xe4\x8d\xe8\xeb\x72\xb7\x03\xb8\xf1\xd7\xb4\x26\x09\x68\x49\xa2\xb5\x02\x1f\xd4\xce\x46\x94\x3c\x41\xba\xf9\x59\x89\x1e\x7f\xcf\x06\x27\xcf\x8d\x82\xbe\x21\x71\x6d\x7d\x63\x0b\x6b\x60\x8f\x7d\x55\x00\x56\x7c\xa0\xaa\x5a\x35\x79\xfb\xc9\xba\xd4\xd5\xe8\xe1\x11\x19\x00\xd5\x0f\xad\x1c\x8e\xea\xb1\xb6\xf5\x53\x69\x53\x99\x33\xe0\x6d\xe7\xc5\x56\xe6\x03\xd0\x57\xbd\xf5\x8c\x9c\xd8\x41\x1e\xa9\x5e\x33\xed\xbe\x7e\x47\xd4\x6c\xf0\x20\xd0\xf0\x47\xcb\x78\x7f\x5a\x5b\x40\x51\x32\x3c\x66\x05\x0e\x6b\x25\xc9\xec\x23\x93\x79\xf8\x33\x62\x77\xae\x40\x34\x63\x20\xcf\xaa\x9b\xb0\x09\x3d\xea\xaa\x7a\xc2\xb7\x3c\xf9\xcf\x43\x53\x9d\x3f\x58\x55\x7f\xe4\x4f\x7d\x55\x66\x09\xab\xfc\x63\xe0\x8b\x62\x5d\x15\x89\x19\xe6\xb6\xa6\xc9\xde\xae\x9b\xea\x98\x67\xbb\xff\xf2\x3f\xff\xd8\xd7\xf3\x67\x69\xe0\xa6\x7f\xca\xd3\xa6\x6a\xab\x43\x37\x55\x55\xb6\x1d\x69\xba\x3f\xf4\x6a\xd7\x76\xcd\x0f\xdf\x7f\xf7\x90\xf0\xff\xfb\x9e\x55\x47\xcb\x0c\x94\x25\xaa\x2c\xfa\x6f\x02\xff\xcf\xaf\x35\xfd\x61\x66\x36\xaf\xa1\x35\x65\x87\xd5\xd8\xff\xc6\x2f\x4e\xdd\x1a\x46\x1e\x0c\x06\xf3\x11\x23\x8f\x86\xbc\x51\xed\xb8\x88\x50\xe9\xad\xee\xa2\x76\xb7\x57\xf0\x66\xb5\xe3\xca\xe5\xd0\xbc\xd5\xdb\xd5\x2e\xb0\x69\x77\x50\xbb\xc4\xa3\x76\x0f\xf7\x56\xbb\xe1\x78\xa2\x59\xe0\x4c\x58\xee\xdc\xcd\x1b\xdb\x65\xd5\x8e\xf8\x20\x7b\xae\xd6\xfc\x32\x3d\x16\xaf\xf5\x29\x4f\xab\x32\x4e\x4f\xf4\xb9\xa9\xca\xd8\x9c\x1e\x3d\xa0\xbc\x1f\x35\xaf\x4b\x41\x33\x40\xd3\x53\xd0\x4b\x43\x1c\x06\xb1\x3a\x56\x01\xf8\x95\xb6\xf4\xca\x4b\xb6\x7e\xc1\xfd\x9a\x5b\xda\xa8\xf8\x12\x67\xb5\x7d\x91\x0c\x10\x7d\x0b\x17\x96\xb3\xd2\x5e\x54\xa2\x52\xb9\x23\xa3\xd5\xaa\xe2\x03\xde\x6a\xaf\x91\xba\xda\x7c\xd6\x4f\x89\xc8\xbf\xad\xa0\xb6\xb5\x85\xa1\x76\x26\xd0\x45\xa4\xaf\xfe\xdd\x9e\x1e\xaa\x86\xea\x21\xce\xef\xff\x32\x4f\x16\xdb\xef\x03\x1a\xe7\x46\x27\x36\x7a\x5e\x66\x79\x4a\xba\xaa\x69\x3d\xba\xa6\xc2\x8e\x09\x12\xc1\x1a\x76\x7f\x56\xc0\xaf\x5a\xf3\x42\xf7\xdb\x82\xf2\x10\x00\x87\xc3\xbd\x2b\xd7\x03\x86\x18\xf7\x45\xae\x7b\xf3\x50\xf9\x35\xb7\x5a\xef\xcf\x59\xa2\xc7\xf8\x67\xe0\x88\x55\xdf\xae\x5e\x76\xb1\x3a\x3a\xe4\x3d\x8c\x0c\x77\xd4\xa2\xbf\x6c\xf1\x42\xdd\x74\x27\x1f\x1d\x7b\x3d\x7a\xb8\x51\x6e\x0c\xa0\xda\x0d\x64\x00\x57\x29\xb2\xbd\x73\xa3\xbd\x73\x64\x4f\xc3\x7f\x6f\x73\x50\x35\x9e\x0c\xda\xa3\x28\x2a\x31\xf4\xef\xa0\xda\xcc\xf5\xa8\xeb\xca\x50\x1b\x78\x65\x85\x0f\x28\xe3\x62\x84\x75\x11\xe2\xae\xae\xb9\xb3\x99\xea\x20\x9b\x46\x09\xe8\xa1\x08\x04\xb5\x69\x43\x69\xc9\x63\x41\xea\x8c\x94\x76\x36\xec\xd7\x9a\x58\xde\x3a\xb3\x0c\x47\xbe\xc4\x09\x35\xa9\x25\x0b\xfd\xc8\x9a\x34\x73\x62\x1f\x19\xae\x96\x16\xea\x9c\xd7\x1b\x9b\x09\xe7\x16\x66\xe7\xcd\x09\x65\x75\x5d\x45\x61\x13\x8a\x56\x93\x9a\x44\xd0\xaa\x80\xf2\x4b\x3d\x9f\x73\xe3\x25\x14\x5b\xfe\x65\x6a\x2d\x2a\x22\xc3\xee\xbe\xd3\xb3\x3f\x0c\x61\x0e\x75\xb8\x32\x96\x4f\xc9\x3e\x0d\xdf\x78\xf0\x79\x12\x8d\x40\xf1\xf9\x80\x79\x22\xfd\xc7\xae\xaa\x8a\x3d\x69\x34\x64\xf9\x4d\x80\x46\xd3\xb4\xa0\xa4\x39\xe4\x2f\x0a\x4a\x7d\x00\xd4\x7a\x91\x92\xbc\xa4\x4d\x7c\x28\x2e\x79\x36\xc0\x1a\xdf\x07\xaa\xb2\x40\x80\x6a\x44\x06\xb0\xac\x88\x4f\x55\x93\xff\xdc\x97\x14\x51\x36\x10\xb6\x0a\x00\x33\x2c\xce\x0a\x4a\xf9\x07\x5d\x4e\x3e\x18\x40\x0a\x1e\x50\x55\xb8\xda\x47\xc5\x6a\x49\x9e\x15\x44\xff\x1b\x50\x29\xc9\xf3\x9e\x34\xea\x4e\x20\x04\xd3\xbe\x43\x5a\x7d\x01\x3f\xa0\x0c\x24\xa4\x7f\x37\xc0\x0d\xb2\x43\x71\x4d\x8e\x1a\x15\xfe\x37\x28\x96\x17\x14\x15\x05\xf0\x49\x81\xa9\x2d\x0e\xf1\x9b\x17\x08\x57\x4c\x7f\x4f\xd9\xdc\xe4\xb8\x5e\x85\x4d\xcd\x34\x94\x30\x48\xe5\xdc\xba\x32\x10\x09\x51\x15\x54\x07\x86\xde\x0e\xe8\x60\xad\x1f\xad\xee\xb2\xbb\xc7\xea\x0f\x63\xb3\xbb\x17\x06\x7b\x41\xfa\xa4\xa6\x2c\x36\xd9\x81\x23\xd3\xf6\xce\xbd\x6e\xda\xf4\x2b\x1e\xf1\xb0\xb8\x57\x3b\x5c\xfa\x8b\xdd\xf0\xa2\x5b\xf4\x4f\xf9\xb9\xae\x9a\x8e\x94\x9d\x06\xad\x62\x52\x02\x98\xfd\x6d\xc3\x9e\x72\x71\xbd\x40\xdb\x19\x42\x00\xdb\x93\xd8\xff\xd3\x1b\x83\x40\xe6\x25\xdb\x6d\x90\x2f\x73\x5b\x3b\x0f\xea\x94\x55\x3f\x7f\xab\xfa\xfb\xc9\x6b\x17\x25\x9f\x93\x88\x00\x5f\xc2\x38\xba\x60\x4d\xf9\xb8\x9b\x84\x1e\x78\x00\x71\x51\xce\x47\x50\xb3\xc9\xe1\x90\xbf\x60\xf7\x40\xa4\xb3\xf1\xed\x37\xf1\xb9\x8d\x9f\x73\xfa\xb5\xc7\x84\x3e\x5e\x46\x9f\xf3\x94\x72\xbf\x43\x92\x13\x92\x89\x8b\xe3\x24\x52\x7f\x9c\x33\xf0\x47\x7b\x06\x7f\xbc\xb4\x41\x4c\x0e\x54\xb9\xd2\x01\x0a\xc5\x31\xe6\x2e\x37\xf6\x4d\x40\xf7\x7a\x3e\xf0\x62\x91\x38\x67\x36\x09\xf5\x0d\x21\xd1\x9e\x2d\x12\xed\xd9\x26\xa1\xbe\x21\x24\x5e\x5a\x8b\xc4\x4b\x6b\x93\x50\xdf\xb0\xb1\x86\xcb\x6a\x38\x36\x2f\xcf\xbe\x45\xbb\xcd\x7a\xa3\x7c\x42\x43\xf2\x3e\x6d\x67\xae\x03\x33\xb1\x6e\x2c\x56\x2c\x41\x9b\x11\xb8\xb8\xa9\xbe\x22\x35\x64\x00\x6d\x12\x75\xa7\x31\x2a\x29\x2d\x0a\x8b\xcc\x95\x8d\x07\x02\x1d\x13\xc1\xb5\x94\x79\x8f\x19\xa4\xc5\xc7\xfb\xd0\x46\x99\xd7\x8a\x46\xea\x31\xaf\x92\xf0\x35\x84\x3a\x2c\xb9\xdd\xce\xac\xca\xe5\x6d\x8d\xeb\xf4\xc5\xc2\x72\xe8\x0b\x0e\x37\xaa\x2f\xbd\x2d\x01\xfa\xe2\xa0\x12\xa2\x2f\x37\x49\xe4\x76\x25\xba\xad\xba\x37\x68\xd6\x5b\x2a\xbc\xa3\xba\xf1\x0b\x3c\x46\xe5\xb3\xd9\x76\x6b\xd5\x7e\xce\x6e\xd1\x37\x0b\xcb\xa1\x6f\x38\xdc\xa8\xbe\xf5\x13\x19\xd0\x37\x07\x95\xeb\xf4\xed\x1a\x91\xdc\x43\xe1\xae\xaa\xef\x2e\x1a\x77\x43\x8d\x77\x54\xb9\x19\xbb\xc7\x63\x54\x24\xaf\x8d\x5d\xa7\x5d\x16\x96\x43\xbb\x70\xb8\x51\xed\xea\x7d\x26\xa0\x5d\x0e\x2a\xd7\x69\x97\xa3\xf5\xf7\x50\x24\x17\xe9\xbb\xe8\x8c\x9f\xf8\x9b\xd5\x03\x9f\x68\xb9\xdb\x6c\xbb\x1d\x96\xa7\xf5\x36\x03\x2b\xaa\xb1\x66\xab\xeb\xaa\x19\x1f\x55\xa2\x1e\xcb\x4a\x5d\x57\x8f\xd6\x13\x82\xa4\xa5\x9a\x6e\x92\xaa\xf3\xea\x26\x17\x07\xc8\xc3\x3c\xd8\x01\x1e\x21\x71\xe5\xc0\xc5\x10\x1d\x63\xd7\x09\x3a\x3a\x7c\x19\xa6\x36\x82\xdd\xb4\xdc\x83\x58\x47\xbe\xda\xef\x77\x49\xed\xda\x01\x6f\x60\x83\x31\xfd\x46\x3e\xae\xb6\x0e\x28\xfe\xfd\xe4\x72\x0f\x83\x02\x88\x8b\x01\x82\xf5\x3c\x3e\x46\xfe\x4f\x00\x00\x00\xff\xff\x47\x37\xb0\x07\xc9\x28\x02\x00") - -func cssBootstrapMinCssBytes() ([]byte, error) { - return bindataRead( - _cssBootstrapMinCss, - "css/bootstrap.min.css", - ) -} - -func cssBootstrapMinCss() (*asset, error) { - bytes, err := cssBootstrapMinCssBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "css/bootstrap.min.css", size: 141513, mode: os.FileMode(438), modTime: time.Unix(1565946440, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _faviconIco = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\x0b\x70\x55\xc7\x79\xde\x7b\xce\x45\x12\xb2\x90\xc4\xc3\xe6\x61\x3b\x90\xf8\x31\xc4\x19\x6c\x32\xe3\xc4\x34\xe3\xc6\x34\x6d\xed\xd4\x69\x62\x32\x49\x9a\xa6\x75\xea\x36\x33\xee\xd8\x9e\xb4\x75\xdc\x7a\xa6\xc5\x31\x02\xa6\xd3\x84\x47\x28\x6f\x3b\xc6\x3c\xcc\xeb\x9e\xbd\x08\x21\x04\x92\x28\x12\x0e\x08\x5b\x3c\xec\x02\x92\x78\x08\x21\x09\x41\x25\x24\x10\xe8\x71\xb5\xe7\xdc\xd7\xb9\xf7\xef\xfc\xff\x9e\x73\x74\x25\xdd\x97\x24\x82\x33\x1e\xce\xcc\x3f\x7b\xee\x9e\xdd\xff\xff\xf6\xdf\x7f\xff\xfd\xf7\xdf\xcb\x98\x8b\xa9\x2c\x3f\x1f\xcb\x19\xec\x15\x37\x63\x5f\x67\x8c\xcd\x98\x21\x7f\x6b\xf9\x8c\x6d\x72\x33\x36\x7b\xb6\xf5\xfb\x11\xc6\x9e\xbd\x97\xb1\x99\x8c\xb1\x7c\x6c\xc7\x64\x3d\x3d\x6e\x76\xdb\x1f\xe1\x75\xab\x42\x53\x7e\x22\x3c\x6c\x91\xf0\xb0\x02\x22\xae\x14\x08\x8f\xab\x40\xec\x64\x92\xf0\x5d\x53\xfe\x59\xec\x64\x5f\x15\x1e\xa6\x08\x4f\x7f\x7f\xdf\x7a\x96\xa1\x97\x3c\xb8\x3f\x78\xfa\x0d\x08\x9e\x5d\x08\xc1\xda\x5f\x82\x51\xf6\x65\x30\xca\x67\x41\xf0\xcc\xbf\x11\x19\x07\x1e\x07\xbd\x78\x2a\x18\x65\x8f\xb5\x0b\x4d\x7d\xad\x6f\x07\x73\x0b\xcd\x45\xfd\xbb\x17\xb3\x0c\xa3\x62\xce\xfe\xa8\xd1\x0a\xf8\x98\x6d\x25\x10\x38\xfe\x53\x88\xdc\x3a\x01\x66\x6b\x11\x11\xbe\x07\x8e\xfd\x2d\x84\x2e\x2c\x05\xff\xd1\x79\x3d\xc2\xc3\x7e\x20\x78\x06\x13\x5c\x89\xe9\xdf\x06\xd1\x50\x2f\x04\x4e\xfc\x0c\xcc\x6b\xa5\x60\x1c\xfd\x21\x74\x6c\x1e\x47\x84\xef\x58\x17\xf8\xe4\x65\x30\x6f\x54\x81\x71\xe0\x89\xea\xbe\x2d\x6c\xd2\x80\xfe\xfe\x76\x30\x6f\x1c\x81\x60\xed\x7c\x08\x9e\x5d\x0c\x2d\xeb\xc7\x41\xed\xd2\x29\x50\xbb\x74\x32\xbd\x63\x1d\x7e\xc3\x36\xa1\x73\xff\x19\x14\x1e\x36\x4f\x78\xc7\xc4\xf4\xef\x80\x70\xd3\xfb\x10\x6e\x5c\x0f\xdd\x65\x73\xe1\xdc\xf2\x89\xd0\xb1\x25\x0f\x6e\x7c\x90\x07\xe7\x7f\x33\x81\xea\xf0\x5b\xb8\x79\x13\x61\xd0\x8b\xa7\x2c\x09\x7c\xfc\x57\xac\x7b\x11\xf6\x7f\x6a\x5f\xd4\xb8\x06\xa1\xfa\x15\x10\x6e\x7a\x0f\x3a\xb4\xc7\xa0\x61\x55\x3e\x04\x8f\xfc\x39\x84\x3e\xfa\x4b\x68\x5c\x93\x4f\x75\xf8\x2d\x74\x71\x05\x44\x45\x13\xea\x54\xeb\x7c\x85\xa9\x48\xf8\x1e\x15\xcd\xf4\xcd\xee\x7f\x71\x65\x3e\x04\x3e\x7c\x86\x78\x5c\x5a\x1d\xd3\xbf\x7e\x05\xa0\x2c\x94\x89\xb2\x03\xd5\x3f\x66\x88\x05\x31\x21\x36\x1b\xff\xd9\xe5\x13\xe1\xda\xc6\x5c\x68\xdf\x94\x4b\x63\x71\xf0\x37\xbd\x0f\x38\x56\x1c\x33\x8e\x1d\x75\x80\xba\x40\x9d\x0c\xd6\x5f\xcd\x92\x29\x44\x83\xf5\x87\xba\x76\xfa\x73\x85\xe1\x5c\x18\x07\x9e\x38\x86\x18\x68\x8e\xac\xf9\xbb\xbe\x39\x87\xc8\x99\xbf\x13\x3f\xa3\x39\xc6\xb9\x8e\xed\x4f\xb6\xe0\x61\x3f\x40\xdb\x40\x1b\x41\x5b\x19\x62\x3f\xc7\x7f\x4a\xb6\x85\x0f\xda\x9a\xdd\x9f\xd6\x80\xe6\x62\xd2\x26\xd5\xd7\xd0\x46\xc9\x56\x0f\x3c\xde\x6f\xbf\xe5\xb3\xc8\xa6\xd1\xb6\xc9\xc6\x4f\xbf\x01\x68\xf3\x68\xfb\xce\x3a\xf2\x30\x26\x76\x32\x85\xd6\x08\xae\x95\xc1\xeb\x87\xd6\x14\xb3\x69\x11\xad\x39\xaf\x5b\x1d\xed\xfa\x05\x60\x8c\x65\x32\xc6\x54\x8b\x5c\x31\x64\x3d\x0b\x63\xe8\xb0\x45\x2d\x56\xdf\x99\x96\x8f\x99\x1b\xeb\x67\xf2\x47\x8b\xea\xf3\xf9\x08\xae\x22\xe5\x09\xae\x4e\x17\x5c\xfd\xc2\x28\x69\x8a\xe0\xca\x58\xb4\x3d\xdb\x17\xa6\x29\xff\x5f\x04\x57\x5b\x85\xe6\xba\x92\x90\xb8\x1a\x43\x4a\x4c\xbd\x62\xd7\xb7\x08\xae\xd6\x0b\xae\xfe\x8f\xe0\xea\x9b\x38\x1e\x1f\x1f\x4b\xfe\x34\xb5\x7c\xa5\x40\xec\xca\x02\xbd\x64\x3a\xe8\xfb\xbe\x38\x94\x4a\xa6\x83\xf0\x66\x82\xd0\x14\x10\x9a\x0b\x44\xe1\x38\x5c\x2b\x44\xf8\x4e\x75\x5c\x01\xe1\x75\x03\xf2\x11\x9a\x2b\x2a\xb8\x52\x2b\xb8\x3a\x4f\x68\x8a\x92\x0c\x03\xc9\xf7\xb0\x02\xa3\xfc\x2b\x10\xe9\xae\x85\xa8\x7e\x15\xa2\xfa\x95\x18\xba\x0a\xa1\xb3\x8b\x49\xbe\xbe\xe7\x5e\x08\xfe\xef\x3f\x81\xd9\x51\x09\x91\xbe\x4b\x44\xf8\x8e\x75\xf8\x4d\x70\x37\x04\x3e\xfe\x11\xf9\x14\xbd\x68\x3c\xe2\xe8\x14\x5c\x7d\x49\x78\x99\x2b\x11\x06\x47\xfe\x81\xd9\x10\x0d\xde\x82\xc1\x8f\x79\xe3\x30\xe8\x7b\xa7\x81\x51\xfa\x28\x98\xd7\xca\x00\xa2\xa6\xfc\x80\x65\xcc\x3b\x7e\xc3\x36\xfa\xde\x07\x08\x93\xd9\x5a\x0c\xfa\xfe\x87\x41\x68\xac\x43\x70\xf5\x59\x92\xe3\x1d\xea\x1a\x92\xc9\x8f\x06\x3a\xc1\xff\xe1\x5c\xda\x67\x91\x27\x3e\x91\xde\x0b\xe4\xaf\xfc\x47\x5f\x20\xc2\x77\xac\x23\xac\x1d\x95\xd4\xd6\xff\xe1\x9f\x10\x2f\xfa\x5d\xf2\x05\xc4\x70\x4c\x70\xf5\x7e\x94\x35\x1c\xf9\xa1\xc6\x77\x68\x3e\x43\x17\x57\x4a\xfe\xe8\xc3\xcb\xbe\x8c\xfc\xa0\xcf\x23\x09\xdf\xb1\x0e\xbf\x51\x9f\x8b\x2b\x65\x9f\xc6\x77\xe8\x37\xee\x4f\x62\xd7\x58\xb4\x8f\x05\x3e\x9e\x35\xc4\x1e\x13\xc9\x8f\x06\xbb\xc0\xa8\xfc\x23\xf0\x1f\xfa\x63\x88\x86\xba\x21\x72\xeb\x24\x18\xfb\x1f\x82\xde\x1d\x2e\x68\xdd\x30\x0e\x1a\x56\x4f\x24\xc2\x77\xac\xc3\x6f\xd8\x06\xdb\x62\x1f\xec\x8b\xef\x10\xd6\xc1\xff\xd1\xf7\x11\x67\x83\xe0\xea\x97\x06\xeb\x20\x91\x7c\xd2\xdd\xee\x3c\x08\x37\x6f\x04\x30\x0d\x08\x7c\x34\x8f\xe4\x34\xae\x99\x00\xa7\x7f\x3d\x0d\x4e\xfd\xea\x7e\x22\x7c\xc7\x3a\xfc\x86\x6d\xb0\x6d\xb8\x69\x23\xf5\xb5\xe7\xcc\x6c\x3f\x00\x62\x77\x6e\x54\x68\xae\x57\xad\xf5\x96\x52\x7e\xb0\x6e\x01\xe8\xfb\x66\xd0\x1a\x30\xaf\x95\x83\x28\xcc\x81\x2b\xef\xe6\x92\x3c\x24\x8a\x63\x96\x4d\x71\x7e\xe3\x37\x6c\x83\x6d\xb1\x0f\xf6\x0d\xd6\x15\x48\x5d\x86\x7c\x64\x47\xc2\xc3\xf6\x0a\xae\x66\xc6\xea\x20\xae\xfc\x48\x08\xfc\x55\xdf\x05\x7f\xd5\x77\x00\x22\x41\x08\x7e\xfa\x2a\x74\x6d\x53\xa1\x6e\xf9\x64\x92\x75\x69\xcd\x44\xb8\xb9\x35\x13\x6e\x6d\xcb\x80\xe6\x75\xe3\xa9\x0e\xbf\x61\x1b\x6c\x8b\x7d\xb0\xaf\xbf\xea\x7b\xc4\x8b\xec\xe2\xec\x22\x9c\x83\x66\xc1\xd5\x19\xa9\xe4\xd3\xdc\x1f\x98\x0d\xc1\x33\x6f\x42\x34\xec\x03\x7f\xe5\x1c\x68\xdb\x30\x96\xe4\x9c\xfb\xcd\x7d\xd0\xbd\x63\x0c\xe8\x85\x63\x41\x2f\xbc\x07\x7a\x3d\x6e\xa8\x5f\x39\x89\xbe\x61\x1b\x6c\x8b\x7d\xb0\xaf\xe4\xd9\x65\xd9\x6e\x19\x88\x5d\xd9\xba\xd0\x5c\x73\x53\xca\xd7\xff\x0f\xf4\xfd\x0f\x41\xa8\x61\x35\xf9\x1f\x7d\xdf\x74\x68\x5e\x97\x47\xf3\xdd\xf2\x4e\x1e\xc9\x0d\x9f\xfc\x3b\x30\x4f\xbd\x02\xc6\x9e\x09\xd0\xba\x21\x07\x4e\xfd\x6a\x1a\xb5\xc1\xb6\xe4\xb3\x1a\x56\x13\x0f\xe4\x25\xd7\xed\x39\x5c\x9b\x51\xa1\xb1\x17\xe3\xc8\x7f\x0b\x63\x13\x5c\xef\xd4\xb6\xaf\x91\x7c\x6b\xf8\xf2\x16\x5a\xdb\x62\xcf\x64\xb8\xb4\x7a\x3c\xc9\x68\xdb\x90\x0d\xfe\xb2\x87\x01\x2e\x2d\x07\x68\x5a\x05\x81\xca\x27\xe1\xfa\xe6\x4c\x39\x2f\xab\xc7\x53\xdb\x88\xaf\x9e\xfa\x22\x0f\xe4\xe5\xc4\x47\xa5\x8f\xa2\x0d\xfc\x22\x8e\xfc\x5f\xe0\x37\x3b\x5e\x4f\x2e\xff\x1e\xf0\x97\x7e\x11\xa2\x0d\x4b\x00\x9a\x56\x42\xe0\xe0\x13\x70\x7d\x53\x56\x6a\xf9\x81\x4e\x8a\xbf\x70\xac\x43\xe4\x6b\xec\x45\xd4\x0d\xea\x28\xbe\xfe\x67\x38\xfa\x6f\x5e\x97\x2f\xfd\xcb\xd1\xe7\x21\x74\xec\x87\xa0\xef\xce\x81\xab\xbf\x1d\x67\x7d\xcb\xb3\xd6\xcc\x50\xfd\xe3\xdc\xe2\x1c\xcb\xb3\xd0\x60\xf9\xae\xb9\x68\x1b\xe4\xdf\x53\xd8\x1f\xda\x39\xda\xbe\xee\x55\x41\xf7\xba\xc9\x16\xcf\xaf\xb8\x2f\xa5\xfd\x25\x95\x8f\x6b\x42\x63\xcd\xb8\xcf\x25\x5c\x7f\x5b\xe5\xfa\xc3\x39\xb8\xf0\xdf\xf7\x42\xfb\xc6\x7b\xa0\x63\x53\x36\x5c\x5c\x35\x29\xad\xf5\x97\x42\x7e\x26\xfa\x06\xda\x37\xc2\xbe\xb4\xfc\x0f\xd2\x99\x25\xd3\xd2\xf2\x3f\xc9\xe5\x2b\xf6\x1c\xbc\x86\x3e\x12\x7d\xe5\x50\xff\xeb\x8f\xe3\x7f\x25\x0d\xf5\xbf\xfe\x21\xfe\x37\x99\xfc\x18\x1d\x7c\x09\xf7\x08\xdc\x2b\xc0\xd4\x69\xef\x30\x2a\x46\xb9\xff\x58\x73\x9f\x5a\xbe\xc2\x7c\x1a\xed\x8d\x0b\x70\xaf\xc4\x3d\x53\xee\xbf\xef\x8e\x7a\xff\x4d\x47\x7e\x8c\x0e\xee\xc7\x58\x01\x63\x06\xd4\x1d\xf6\x41\x9b\x18\x51\xfc\x61\xf9\xb2\xb4\xe5\x7b\x55\x1b\xc3\xb3\x18\x33\x61\xec\x84\x31\x14\xf1\xdc\xfb\x40\x5a\xf1\x97\x4e\xf1\xd7\x34\x8a\xd9\x06\x3f\xa9\xe4\x3b\xb6\x48\xb1\xa2\xfa\x12\xc6\x8e\x18\x43\x62\x2c\x89\x31\x25\xc6\x96\x29\xe3\x4f\x6f\x26\xc5\xaa\xf1\x62\x58\x8c\x6d\x31\xc6\x4d\x26\xbf\x7f\x3d\x60\xcc\xac\xce\xa3\x18\x1a\x63\x69\x8c\xa9\xb9\x5b\xc6\xd8\x14\x7f\xe7\xc4\xc4\xdf\x39\xb2\x0e\x63\x73\x8c\x91\x93\xc5\xf0\xc4\x47\x49\x2a\x9f\x30\x68\x0a\xf3\x15\x65\x31\x6b\xaf\x7e\xd3\x3a\x53\xd4\x5b\x67\x8c\x44\xe7\x0f\x49\xc9\xcf\x30\xad\xd6\x59\x27\xa9\xfc\x58\x5d\xf4\x69\x14\x2f\x8d\x95\x67\xab\x51\x9f\xcf\xa6\x5b\x67\xbd\xb4\xe4\x7f\xde\x1f\x7b\x6d\x1c\x66\x2a\x1c\x66\x0c\xe9\x99\xc3\x8c\x4d\xb7\x28\xcf\xa2\x4c\x8b\xd4\x74\xa8\xc5\xa2\x1e\x8b\x02\x16\x99\x8c\xa9\xc0\x48\x90\x6a\xcb\x9d\xc9\x18\x9b\xcd\x18\xfb\xfb\xd8\x3c\xc5\xc3\x9f\xb5\x56\xee\x3e\x77\x9f\x3f\xcc\xc7\xda\x1f\x1f\x16\x5c\x7d\x5b\x70\x75\xa1\xe0\x6a\xc1\xef\x89\x6c\xde\xff\x2a\xb8\xfa\x37\x82\x2b\xb3\x05\x57\x72\x7a\x35\xc6\x0c\x2d\x79\x3e\x29\x0d\xfc\xdf\x16\x5c\x0d\x0a\xae\xc2\x1d\x22\x53\x70\xb5\x53\x70\xf5\x20\xed\xeb\x5c\xc9\xc7\x58\xc3\x48\x33\x3f\x97\x18\xbf\x42\xb1\x57\x5a\x84\x6d\x07\x60\x4a\xd2\x37\x6e\x5b\x97\xfd\x1b\xf5\x56\x2a\xb8\xfa\x24\xec\x67\x4c\xe7\xc3\x1b\x83\x83\x5f\x73\x05\x31\xc6\x0b\xd6\xbe\x45\xe7\xf2\x64\x14\x3c\xbb\x08\x8c\x8a\xa7\xfa\x71\x21\xc6\xc2\x1c\x30\x0e\x7e\x0d\x02\x27\xfe\x81\x78\x20\xe1\x3b\xd6\xc9\x78\x84\x39\xd8\xf5\xe2\x29\x60\x94\xcd\x04\xe1\xcd\x8a\x1d\x47\xa3\xe0\xea\x0b\x7e\xce\x5c\x7a\x8a\xfc\x64\x7c\xfc\x2c\x48\xf1\x75\xb8\x6f\x48\x9c\x37\xf8\x31\xdb\x4a\x64\x9c\x84\xb2\xbd\x19\xe0\x3f\xf2\x17\x60\xb6\xee\x85\x68\xe0\x26\x40\x34\x12\x13\x20\x46\xa8\x0e\xbf\x61\x1b\x6c\x8b\x7d\xf4\xe2\xc9\x10\x6a\x58\x0b\xe1\xcb\x5b\xc1\xa8\xfc\x46\xff\x9c\x70\xb5\x0d\xc7\xd0\xa3\x65\x33\x91\xe6\x3c\x0c\x17\x7f\xa4\xeb\x14\xc5\xb4\xc2\xc3\xe8\x3c\x43\xb1\x65\xb0\x3b\xe5\x98\xb1\x0d\xb6\xc5\x3e\xf2\x7c\x30\x13\x22\xdd\x35\x10\xf5\x5f\xa7\x73\xa9\x28\xbc\xc7\x1e\x43\x93\xe0\xca\x53\x14\x73\x16\xa6\x8e\x89\x86\x83\x9f\xce\x41\x55\xdf\x23\xec\x62\x77\x2e\x9d\xc7\xed\xb3\xa8\x1c\x5c\x10\xa2\xa2\x05\x22\xb7\x3e\x21\xc2\x77\xac\xeb\xff\x1e\xa2\x3e\xd8\x17\x79\x20\xaf\x68\xa8\x87\xda\x84\xea\x97\xcb\xbc\xb3\x1c\x43\xa5\xe0\xea\xe4\x74\x62\xba\xe1\xe0\x0f\x35\xac\x91\x36\xc0\xdd\x10\xac\x7b\xbb\x1f\x7b\x34\x0c\x66\x47\x05\xdd\x3d\xe9\xa5\x8f\x80\x5e\x34\x51\x52\xe9\x23\xf2\x3e\xaa\xa3\x82\xda\xd8\x63\x08\xd6\xfe\x52\xc6\xee\xde\x0c\xe2\x69\x8f\x1d\xcf\x4d\x92\xbf\x1a\x45\x7f\xeb\xf3\x32\x57\x5f\x0a\x3b\x4a\x17\x3f\xea\xd2\x28\x9f\x25\xf5\x76\xe4\x3b\xfd\x79\xad\x70\x1f\x84\xce\xff\x17\xe8\x7b\x26\x59\xfe\xc6\xca\xdb\xdb\x3e\x46\x63\xf4\x0d\xdb\xd8\xbc\xe9\x0c\x78\xe4\x79\xe2\x85\x3c\x69\x9e\x68\x7e\x7b\x21\x50\xfd\x63\x7b\x4d\x5f\x13\x5c\xfd\x7a\xca\x73\x45\x9a\xf8\x69\x7e\xad\xb5\x67\xde\xa8\xea\xd7\x59\xdd\x02\x79\x0f\xc1\xa5\x1f\xe9\xd9\x39\x06\x6e\x6e\xcd\x22\xc2\x77\xb9\x36\x5d\xd4\x06\xdb\xda\xf6\x64\xde\x38\x42\xbc\x90\x27\xf2\x76\x4c\xac\xbb\x86\x72\x44\xd6\x18\xde\xd3\xb9\xcb\x9d\xcc\x1f\xa5\x83\x9f\xf2\x5c\x15\x73\x48\x5f\x81\x4f\x5f\x75\xce\xa8\xe1\xcb\x5b\x1c\x9b\x45\xac\x57\xde\xcd\xa3\x5c\x66\xcd\xd2\x29\x44\xf8\x8e\x75\x72\x1c\x0a\xb5\xc5\x3e\x92\xa9\x49\xbc\x68\x0e\x2a\xe6\x0c\x38\x5b\x87\x2e\x2c\xb1\xce\x86\x6a\xbb\xe0\xea\x57\x93\x9f\x2d\x53\xe3\xa7\x5c\xcf\xae\x6c\xb2\x03\xb3\xb3\x5a\xea\xa9\xaf\x51\x9e\x5d\x35\x06\xdd\xdb\x33\x9c\x9c\x53\x3c\xc2\x6f\xd8\x86\xfc\x4e\xf9\x57\x9c\xfc\x9f\xd9\xf9\xb1\xb4\xbb\xc2\x6c\x30\xdb\xcb\xfb\xf5\xa5\x5f\x95\x79\x41\xb9\x67\x2c\x12\xdc\x9d\xf0\xce\x2a\x1d\xfc\xe4\xdf\xc8\x5f\x7c\x97\x72\xf1\x54\x57\xf3\xef\x64\x17\xbd\x1e\x37\xe5\x6c\x12\x61\xb7\x09\xdb\x60\x5b\xec\x83\x7d\xe5\x00\x0c\xe2\x89\xbc\x51\xc6\x00\x99\x75\x0b\x6d\x1b\x3a\x2e\xb8\x32\x61\xa4\xf8\xf1\x37\xe5\xe9\x35\x06\xa1\x86\x55\x96\x7e\x5a\xc0\x28\x9d\x49\x75\xad\xef\x8d\x1b\x82\xb5\x76\xd9\xc0\x7b\x00\x9b\xb0\xad\xed\xfb\xa3\xfa\x15\x69\x2b\x17\x57\x51\x1d\xca\x88\x95\x8d\xfe\x57\xde\x9f\x29\x3e\xc1\xd5\x6f\x26\xce\x8f\x24\xc7\x1f\xf1\x35\x80\x5e\xf2\x00\xe8\xbb\xf3\x21\x72\xf3\x98\x65\xf7\x1f\x80\xf0\x8e\x81\x9e\x1d\x63\xc8\xc6\x6d\x7c\x35\x4b\xa7\x92\xbd\xdf\xda\x96\x09\x5d\xdb\x33\xa1\x6d\x43\x8e\x73\xbf\x60\xe7\xf9\xb1\x0f\xfa\x48\xdc\x7b\x89\xff\xcd\x6a\xe2\x4d\x79\x65\x5f\xc3\x40\xbd\xfd\xee\x5b\xb6\x0d\x51\x7e\x3b\xde\x3a\x4e\x85\xdf\xec\x38\x44\xb6\x6f\x94\x3d\x46\xff\x67\xc0\x27\x70\xf2\x65\xe2\x7b\xed\xfd\x9c\x98\xbc\xe7\x54\xa9\x5f\x27\x16\x50\x40\xe7\x2a\x5c\xdf\x9c\x4d\xf7\x32\x76\x3b\xec\x83\x7d\x03\x9f\xfc\xa3\xc4\xe9\x6f\x27\xde\x28\x03\x65\x0d\xb0\xa1\x9a\xff\xb0\xf1\x6f\xd3\xb9\x2b\xee\x9d\x69\x2a\xfc\xa4\x6b\x9c\xdf\xc3\xcf\x01\x44\x02\x94\xcb\x35\x2a\x9f\xa6\xba\xa6\xb5\x13\x9c\x7c\x29\xae\x51\x9f\x47\xe6\x93\xf4\xc2\x6c\xd0\x77\x8f\x73\xe2\xcd\xcb\xeb\xf3\x9d\xfc\x2a\xf6\x21\x7e\x87\x9e\x96\x79\xe1\x48\x80\x78\x63\x1d\xca\x1a\x20\xfb\x2a\xb7\xf7\xb3\x6a\xc1\x95\xdc\x91\xe0\x0f\x5d\x58\x26\xfd\xe6\xf1\x97\xa4\xbe\xc4\x65\xca\x5d\xf5\xee\x54\x29\xe7\x6d\xeb\xb5\x0d\xf5\xca\x5d\x60\xec\x9d\x4a\x77\x30\x91\xda\x37\xc0\x5f\x3e\x93\xc6\xd3\xf9\xc1\x58\xb2\x2d\x3b\x4f\xee\xdb\xa9\x12\x0f\xe4\x45\xf3\x79\xfc\x25\x92\x81\xb2\x06\xd8\xee\xcd\x13\xf2\xce\x98\x2b\x4d\x82\xab\x0f\x26\xc9\x91\x3e\x97\x08\x3f\xed\x4f\x3b\x19\x04\x4f\xbd\x2e\x79\xf6\xd4\xd2\xbe\xd3\xbd\x7d\x0c\x9c\xb5\x6c\x1b\xb1\xe1\x7e\xa5\x7b\x55\x08\x1d\xfb\x11\x40\xf3\x5a\x22\xf3\xf4\xcf\x69\x2e\xd0\xff\xa3\xed\x23\x7e\xec\xd3\xbd\xdd\x4d\x31\x74\xa4\xa7\x4e\xca\x38\xf5\xba\x94\x81\xfb\x5b\xac\xef\x10\xcd\x74\xf7\x64\xdd\x79\xcf\x4a\x82\xff\x5b\x42\x63\x86\x71\xf0\xc9\x21\xb1\x24\xf9\x4e\xe4\x5d\x3b\xdf\xd2\xc9\x71\xd0\x8b\xf2\xa1\x6b\x5b\x86\xe3\x63\xb0\xec\xda\x9e\x41\xf7\x6f\x66\xcd\xeb\x00\xcd\x6b\x00\x9a\x56\x43\xb4\x7e\x31\x18\x7b\x27\x83\xcf\x23\xe7\x0a\xf1\x3b\x6d\x8b\xf2\xe9\xff\x3a\x24\xa3\x76\xbe\x94\x31\xc8\x87\x62\x6c\x4a\x31\x8b\xc6\xfa\x04\x57\x9f\x4e\x82\xff\x69\x6c\x43\xb1\x88\xff\xfa\xc8\xf0\x6f\xcb\x00\x7d\x57\x16\x98\x67\x7e\xde\x8f\xff\x42\x01\x18\xc5\x93\x08\xff\xf9\x91\xe0\x0f\x76\x03\xea\x14\x75\x4b\x3a\x4e\x8c\x7f\x16\xe5\x96\xf7\xcd\xa0\x39\x4b\x6e\x3f\x75\x34\xf7\x68\x03\xb6\xfd\xa0\xef\xb9\xb1\x85\xee\xd3\x21\x78\xe4\xcf\xe8\x0e\x10\xed\x27\x7c\xe2\x45\xd0\xbd\x19\xd0\xbd\x23\x83\xda\x0e\xdb\x7e\xc2\x7d\x74\x67\x81\xb6\x4d\x36\x9e\x18\xff\x83\xb8\x46\xf4\xa2\x09\x74\xdf\x31\x92\xf5\x7b\xf5\xb7\xb9\x96\xef\xc9\x81\x60\xd5\x73\x10\xaa\xfe\x3e\xe8\xc5\xf7\x82\xce\x15\xba\xd3\xc2\x31\x9e\xfa\xb5\xbd\x7e\x95\xb4\xd6\xef\x20\xfc\xdf\x8e\x8f\x9f\x72\xeb\xb9\xe4\xa3\x70\x5f\xb9\xca\x07\xf0\x48\xd7\x7f\x9e\x5b\x81\x7b\x53\x46\x7f\xec\x6c\x91\x4f\xeb\x8f\x2f\xb0\x6d\xe3\x30\xfc\x67\xba\xf8\xe5\xde\xa0\x6e\x47\x1e\xc1\x9a\xf9\x03\x78\xa4\xbb\x7f\x21\x35\xad\x1b\x0f\xbd\x9e\x31\xd6\x3d\xa6\x0a\x7d\x9a\x9b\xe6\x05\x75\x3f\x64\xff\x3a\xf9\xb2\xb5\x46\x13\xef\x5f\xe9\xe0\xd7\xed\xbb\x3e\xdc\xa3\x51\x2f\xbf\xfb\xd3\x81\x71\x48\xdc\xf8\x61\x6b\xdc\xf8\xc1\xde\xc7\x30\x6e\x40\x9c\xa8\xeb\x58\xec\xc3\x89\x1f\xd2\xc5\x1f\xb3\x06\xbe\x29\xb8\xd2\xa7\xef\xb9\x0f\x22\x5d\x9f\x0e\xe0\xe1\xc4\x6f\x17\xd3\x8b\xdf\x12\xd1\x70\xe2\xb7\xe1\xe1\xa7\x35\x30\x81\x62\x55\xcd\x45\xe7\xd0\xd8\xe7\xb3\x88\x9f\x87\x85\x5f\x53\x18\xfd\x3f\x95\xab\x8b\xe5\x19\xe3\x71\x3a\x43\x38\x6b\xe0\xf7\x76\x7e\xa9\x8e\x7b\x7e\x19\x2e\xfe\x18\x1b\xc2\xb3\x5a\x07\x9e\xdd\xf0\x0c\xe7\xf0\xb9\x23\xe7\xc7\x9b\xa3\xc4\x4f\x7e\xc8\x8d\x67\x66\x3a\xa7\xef\x7f\x88\xce\xd2\xf6\x93\xf6\xf9\x7d\x47\xcc\xf9\x7d\x47\xb2\xf3\x7b\x55\xdc\xf3\xfb\x48\xf1\xc7\xcc\xc1\xd7\x28\x77\x81\x3e\xae\xfa\xaf\x29\xa7\x01\x43\xf2\x27\xcf\x0f\xcc\x9f\x9c\xbb\x3d\xf9\x93\xd1\xe2\xef\xe3\x2e\xe6\xe3\x4c\x91\x67\x66\x35\x8a\x7e\x8e\xd6\xb2\xa5\xb3\xd4\xf9\xab\x17\xc1\x28\x7d\x04\xf4\x3d\x13\x89\x8c\x44\xf9\xab\xba\xb7\x87\xe6\xaf\x6e\x03\xfe\x98\x39\x98\x2c\xb8\x7a\xc8\xb6\xd9\x50\xfd\x32\x99\x1b\x0c\xf5\x38\xfe\xe2\xf6\xe5\x0f\x13\xe7\x4e\x47\x84\xbf\x50\xb5\xfd\xe9\x1c\x2b\x97\x4a\xb9\x55\xfa\xdf\x50\xe0\x3a\x44\xba\xcf\xc8\xdc\x37\xda\x8a\x9d\xbf\x4d\x82\xc1\xc1\x62\xe5\x6f\xb1\x0f\xe5\x7e\x4b\x1f\xa5\x5c\x70\xd2\x3e\x23\xc0\x4f\x63\xf0\xba\x58\x8f\x27\x1b\xe7\xe1\x05\x99\xd3\x56\x68\xbe\x8d\xca\x6f\xd0\xbe\x19\x6a\x58\xeb\xac\x3d\x27\x7f\xde\x56\x92\x7e\xfe\xbc\xe4\x41\x30\xdb\xf6\xa5\x1e\xf3\x08\xf1\xe3\xa3\x7b\x15\x66\xec\xa2\xff\x6d\xbc\x60\xdd\x2d\x48\xbc\xbb\xb2\xe8\xbf\x31\x7a\xf1\xd4\x24\xf7\x17\xf3\x89\x12\xdd\x5f\x18\x15\x4f\xd1\x1d\x48\xca\x7b\x92\xda\xb7\xac\xff\xda\xba\x86\x8d\x9f\xc6\xc0\x5d\x0c\xbc\xe4\x5b\xd1\x27\x95\x39\x77\x64\x8e\x8f\x19\xcd\xfd\xd1\xb0\xee\xa9\x46\x84\x1f\x1f\x43\x73\xd9\x6b\x7a\xbc\xbc\x6b\xa3\x3b\xb7\x4e\xeb\x0e\xee\x4e\xdd\xf7\x8d\x18\xbf\x33\x0e\x8f\xc2\x7a\x8b\x54\x8c\x35\x72\x04\x57\x67\x0b\xae\xfe\xc4\xba\x0b\x2d\xb8\x03\xf7\xae\x6f\x5b\x77\xbc\x23\xc6\x7f\xf7\xb9\xfb\x7c\x9e\x1e\xb9\x43\x24\x2e\x5b\x18\x63\xcf\x58\x65\x9e\x55\x66\x5a\xa5\x6b\x50\xc9\xec\xb2\xc0\x2a\x9f\x19\x54\x4e\x4f\x50\xe6\x25\x28\x33\x6f\x5f\xd9\x93\xa0\x0c\x24\x28\xcd\x41\x65\xd4\x2a\xc1\x2e\x17\x0e\x2a\x5b\xac\xb2\xc7\x2a\x4d\xab\x4c\xa1\xdf\xff\x0f\x00\x00\xff\xff\xc6\xb9\x24\x2f\xee\x3a\x00\x00") - -func faviconIcoBytes() ([]byte, error) { - return bindataRead( - _faviconIco, - "favicon.ico", - ) -} - -func faviconIco() (*asset, error) { - bytes, err := faviconIcoBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "favicon.ico", size: 15086, mode: os.FileMode(438), modTime: time.Unix(1565946440, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _jsJquery211Js = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\xce\xcf\x2b\xce\xcf\x49\xd5\xcb\xc9\x4f\xd7\x50\x4a\xad\x48\xcc\x2d\xc8\x49\x55\xd2\xb4\x06\x04\x00\x00\xff\xff\xc8\x9f\xbd\x5f\x17\x00\x00\x00") - -func jsJquery211JsBytes() ([]byte, error) { - return bindataRead( - _jsJquery211Js, - "js/jquery-2.1.1.js", - ) -} - -func jsJquery211Js() (*asset, error) { - bytes, err := jsJquery211JsBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "js/jquery-2.1.1.js", size: 23, mode: os.FileMode(438), modTime: time.Unix(1591451173, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "css/bootstrap.min.css": cssBootstrapMinCss, - "favicon.ico": faviconIco, - "js/jquery-2.1.1.js": jsJquery211Js, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "css": {nil, map[string]*bintree{ - "bootstrap.min.css": {cssBootstrapMinCss, map[string]*bintree{}}, - }}, - "favicon.ico": {faviconIco, map[string]*bintree{}}, - "js": {nil, map[string]*bintree{ - "jquery-2.1.1.js": {jsJquery211Js, map[string]*bintree{}}, - }}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} diff --git a/_examples/file-server/embedding-gzipped-files-into-app/main.go b/_examples/file-server/embedding-gzipped-files-into-app/main.go deleted file mode 100644 index a80814c2..00000000 --- a/_examples/file-server/embedding-gzipped-files-into-app/main.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -// How to run: -// -// $ go get -u github.com/go-bindata/go-bindata/v3/go-bindata -// $ go-bindata -prefix "../embedding-files-into-app/assets/" -fs ../embedding-files-into-app/assets/... -// $ go run . -// Time to complete the compression and caching of [2/3] files: 31.9998ms -// Total size reduced from 156.6 kB to: -// br (22.9 kB) [85.37%] -// snappy (41.7 kB) [73.37%] -// gzip (27.9 kB) [82.16%] -// deflate (27.9 kB) [82.19%] - -var dirOptions = iris.DirOptions{ - IndexName: "index.html", - // The `Compress` field is ignored - // when the file is cached (when Cache.Enable is true), - // because the cache file has a map of pre-compressed contents for each encoding - // that is served based on client's accept-encoding. - Compress: true, // true or false does not matter here. - Cache: iris.DirCacheOptions{ - Enable: true, - CompressIgnore: iris.MatchImagesAssets, - // Here, define the encodings that the cached files should be pre-compressed - // and served based on client's needs. - Encodings: []string{"gzip", "deflate", "br", "snappy"}, - CompressMinSize: 50, // files smaller than this size will NOT be compressed. - Verbose: 1, - }, -} - -func newApp() *iris.Application { - app := iris.New() - app.HandleDir("/static", AssetFile(), dirOptions) - return app -} - -func main() { - app := newApp() - - // http://localhost:8080/static/css/bootstrap.min.css - // http://localhost:8080/static/js/jquery-2.1.1.js - // http://localhost:8080/static/favicon.ico - app.Listen(":8080") -} diff --git a/_examples/file-server/embedding-gzipped-files-into-app/main_test.go b/_examples/file-server/embedding-gzipped-files-into-app/main_test.go deleted file mode 100644 index af4ac99f..00000000 --- a/_examples/file-server/embedding-gzipped-files-into-app/main_test.go +++ /dev/null @@ -1,125 +0,0 @@ -package main - -import ( - "bytes" - "io/ioutil" - "path/filepath" - "runtime" - "strings" - "testing" - - "github.com/kataras/iris/v12/httptest" - "github.com/klauspost/compress/gzip" -) - -type resource string - -// content types that are used in the ./assets, -// we could use the detectContentType that iris do but it's better -// to do it manually so we can test if that returns the correct result on embedding files. -func (r resource) contentType() string { - switch filepath.Ext(r.String()) { - case ".js": - return "text/javascript" - case ".css": - return "text/css" - case ".ico": - return "image/x-icon" - case ".html": - return "text/html" - default: - return "text/plain" - } -} - -func (r resource) String() string { - return string(r) -} - -func (r resource) strip(strip string) string { - s := r.String() - return strings.TrimPrefix(s, strip) -} - -func (r resource) loadFromBase(dir string) string { - filename := r.String() - - filename = r.strip("/static") - - fullpath := filepath.Join(dir, filename) - - b, err := ioutil.ReadFile(fullpath) - if err != nil { - panic(fullpath + " failed with error: " + err.Error()) - } - result := string(b) - - if runtime.GOOS != "windows" { - result = strings.Replace(result, "\n", "\r\n", -1) - } - return result -} - -var urls = []resource{ - "/static/css/bootstrap.min.css", - "/static/js/jquery-2.1.1.js", - "/static/favicon.ico", -} - -// if bindata's values matches with the assets/... contents -// and secondly if the HandleDir had successfully registered -// the routes and gave the correct response. -func TestEmbeddingGzipFilesIntoApp(t *testing.T) { - dirOptions.Cache.Verbose = 0 - app := newApp() - - e := httptest.New(t, app) - - if runtime.GOOS != "windows" { - // remove the embedded static favicon for !windows, - // it should be built for unix-specific in order to be work - urls = urls[0 : len(urls)-1] - } - - for i, u := range urls { - url := u.String() - rawContents := u.loadFromBase("../embedding-files-into-app/assets") - shouldBeCompressed := int64(len(rawContents)) >= dirOptions.Cache.CompressMinSize - - request := e.GET(url) - if shouldBeCompressed { - request.WithHeader("Accept-Encoding", "gzip") - } - response := request.Expect() - response.ContentType(u.contentType(), app.ConfigurationReadOnly().GetCharset()) - if shouldBeCompressed { - response.ContentEncoding("gzip") - } - - if expected, got := response.Raw().StatusCode, httptest.StatusOK; expected != got { - t.Fatalf("[%d] of '%s': expected %d status code but got %d", i, url, expected, got) - } - rawBody := response.Body().Raw() - - if shouldBeCompressed { - reader, err := gzip.NewReader(strings.NewReader(rawBody)) - defer reader.Close() - if err != nil { - t.Fatalf("[%d] of '%s': %v", i, url, err) - } - buf := new(bytes.Buffer) - reader.WriteTo(buf) - if expected, got := rawContents, buf.String(); expected != got { - // t.Fatalf("[%d] of '%s': expected body:\n%s but got:\n%s", i, url, expected, got) - // let's reduce the output here... - // they are big files, no need to check for length here. - t.Fatalf("[%d] %s, expected body to look like: '%s...%s' but got '%s...%s'", i, url, expected[:40], expected[len(rawContents)-40:], got[:40], got[len(got)-40:]) - } - } else { - if expected, got := rawContents, rawBody; expected != got { - t.Fatalf("[%d] %s, expected body to look like: '%s...%s' but got '%s...%s'", i, url, expected[:40], expected[len(rawContents)-40:], got[:40], got[len(got)-40:]) - } - } - - } -} diff --git a/_examples/file-server/favicon/main.go b/_examples/file-server/favicon/main.go deleted file mode 100644 index f10f6088..00000000 --- a/_examples/file-server/favicon/main.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - // This will serve the ./static/favicons/favicon.ico to: localhost:8080/favicon.ico - app.Favicon("./static/favicons/favicon.ico") - - // app.Favicon("./static/favicons/favicon.\\.ico", "/favicon_16_16.ico") - // This will serve the ./static/favicons/favicon.ico to: localhost:8080/favicon_16_16.ico - - app.Get("/", func(ctx iris.Context) { - ctx.HTML(`
press here to see the favicon.ico. - At some browsers like chrome, it should be visible at the top-left side of the browser's window, - because some browsers make requests to the /favicon.ico automatically, - so iris serves your favicon in that path too (you can change it).`) - }) // if favicon doesn't show to you, try to clear your browser's cache. - - app.Listen(":8080") -} diff --git a/_examples/file-server/favicon/static/favicons/favicon.ico b/_examples/file-server/favicon/static/favicons/favicon.ico deleted file mode 100644 index c370da518ec542579b7cc0d5d30f4778b4a96318..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 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 unit; n /= unit { - div *= unit - exp++ - } - return fmt.Sprintf("%.1f %cB", - float64(b)/float64(div), "kMGTPE"[exp]) - }) - app.RegisterView(view) - - // Serve assets (e.g. javascript, css). - // app.HandleDir("/public", iris.Dir("./public")) - - app.Get("/", index) - - app.Get("/upload", uploadView) - app.Post("/upload", upload) - - filesRouter := app.Party("/files") - { - filesRouter.HandleDir("/", iris.Dir(uploadDir), iris.DirOptions{ - Compress: true, - ShowList: true, - - // Optionally, force-send files to the client inside of showing to the browser. - Attachments: iris.Attachments{ - Enable: true, - // Optionally, control data sent per second: - Limit: 50.0 * iris.KB, - Burst: 100 * iris.KB, - // Change the destination name through: - // NameFunc: func(systemName string) string {...} - }, - - DirList: iris.DirListRich(iris.DirListRichOptions{ - // Optionally, use a custom template for listing: - // Tmpl: dirListRichTemplate, - TmplName: "dirlist.html", - }), - }) - - auth := basicauth.New(basicauth.Config{ - Users: map[string]string{ - "myusername": "mypassword", - }, - }) - - filesRouter.Delete("/{file:path}", auth, deleteFile) - } - - app.Listen(":8080") -} - -func index(ctx iris.Context) { - ctx.Redirect("/upload") -} - -func uploadView(ctx iris.Context) { - now := time.Now().Unix() - h := md5.New() - io.WriteString(h, strconv.FormatInt(now, 10)) - token := fmt.Sprintf("%x", h.Sum(nil)) - - ctx.View("upload.html", token) -} - -func upload(ctx iris.Context) { - ctx.SetMaxRequestBodySize(maxSize) - - _, err := ctx.UploadFormFiles(uploadDir, beforeSave) - if err != nil { - ctx.StopWithError(iris.StatusPayloadTooRage, err) - return - } - - ctx.Redirect("/files") -} - -func beforeSave(ctx iris.Context, file *multipart.FileHeader) { - ip := ctx.RemoteAddr() - ip = strings.ReplaceAll(ip, ".", "_") - ip = strings.ReplaceAll(ip, ":", "_") - - file.Filename = ip + "-" + file.Filename -} - -func deleteFile(ctx iris.Context) { - // It does not contain the system path, - // as we are not exposing it to the user. - fileName := ctx.Params().Get("file") - - filePath := path.Join(uploadDir, fileName) - - if err := os.RemoveAll(filePath); err != nil { - ctx.StopWithError(iris.StatusInternalServerError, err) - return - } - - ctx.Redirect("/files") -} diff --git a/_examples/file-server/file-server/views/dirlist.html b/_examples/file-server/file-server/views/dirlist.html deleted file mode 100644 index 2b676f0c..00000000 --- a/_examples/file-server/file-server/views/dirlist.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - {{.Title}} - - - - - - - - - - - - - - - {{ range $idx, $file := .Files }} - - - {{ if $file.Download }} - - {{ else }} - - {{ end }} - {{ if $file.Info.IsDir }} - - {{ else }} - - {{ end }} - - - - {{ end }} - -
#NameSizeActions
{{ $idx }}{{ $file.Name }}{{ $file.Name }}Dir{{ formatBytes $file.Info.Size }}
- - - - \ No newline at end of file diff --git a/_examples/file-server/file-server/views/upload.html b/_examples/file-server/file-server/views/upload.html deleted file mode 100644 index a278be2e..00000000 --- a/_examples/file-server/file-server/views/upload.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - Upload Files - - - -
- - - - -
- - - - - \ No newline at end of file diff --git a/_examples/file-server/http2push-embedded-gzipped/bindata.go b/_examples/file-server/http2push-embedded-gzipped/bindata.go deleted file mode 100644 index 78976fd8..00000000 --- a/_examples/file-server/http2push-embedded-gzipped/bindata.go +++ /dev/null @@ -1,580 +0,0 @@ -// Code generated by go-bindata. (@generated) DO NOT EDIT. - -//Package main generated by go-bindata.// sources: -// ../http2push/assets/app2/app2app3/css/main.css -// ../http2push/assets/app2/app2app3/dirs/dir1/text.txt -// ../http2push/assets/app2/app2app3/dirs/dir2/text.txt -// ../http2push/assets/app2/app2app3/dirs/text.txt -// ../http2push/assets/app2/app2app3/index.html -// ../http2push/assets/app2/index.html -// ../http2push/assets/app2/mydir/text.txt -// ../http2push/assets/css/main.css -// ../http2push/assets/favicon.ico -// ../http2push/assets/index.html -// ../http2push/assets/js/main.js -package main - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(data, name string) ([]byte, error) { - gz, err := gzip.NewReader(strings.NewReader(data)) - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -// Name return file name -func (fi bindataFileInfo) Name() string { - return fi.name -} - -// Size return file size -func (fi bindataFileInfo) Size() int64 { - return fi.size -} - -// Mode return file mode -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} - -// ModTime return file modify time -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} - -// IsDir return file whether a directory -func (fi bindataFileInfo) IsDir() bool { - return fi.mode&os.ModeDir != 0 -} - -// Sys return file is sys mode -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -type assetFile struct { - *bytes.Reader - name string - childInfos []os.FileInfo - childInfoOffset int -} - -type assetOperator struct{} - -// Open implement http.FileSystem interface -func (f *assetOperator) Open(name string) (http.File, error) { - var err error - if len(name) > 0 && name[0] == '/' { - name = name[1:] - } - content, err := Asset(name) - if err == nil { - return &assetFile{name: name, Reader: bytes.NewReader(content)}, nil - } - children, err := AssetDir(name) - if err == nil { - childInfos := make([]os.FileInfo, 0, len(children)) - for _, child := range children { - childPath := filepath.Join(name, child) - info, errInfo := AssetInfo(filepath.Join(name, child)) - if errInfo == nil { - childInfos = append(childInfos, info) - } else { - childInfos = append(childInfos, newDirFileInfo(childPath)) - } - } - return &assetFile{name: name, childInfos: childInfos}, nil - } else { - // If the error is not found, return an error that will - // result in a 404 error. Otherwise the server returns - // a 500 error for files not found. - if strings.Contains(err.Error(), "not found") { - return nil, os.ErrNotExist - } - return nil, err - } -} - -// Close no need do anything -func (f *assetFile) Close() error { - return nil -} - -// Readdir read dir's children file info -func (f *assetFile) Readdir(count int) ([]os.FileInfo, error) { - if len(f.childInfos) == 0 { - return nil, os.ErrNotExist - } - if count <= 0 { - return f.childInfos, nil - } - if f.childInfoOffset+count > len(f.childInfos) { - count = len(f.childInfos) - f.childInfoOffset - } - offset := f.childInfoOffset - f.childInfoOffset += count - return f.childInfos[offset : offset+count], nil -} - -// Stat read file info from asset item -func (f *assetFile) Stat() (os.FileInfo, error) { - if len(f.childInfos) != 0 { - return newDirFileInfo(f.name), nil - } - return AssetInfo(f.name) -} - -// newDirFileInfo return default dir file info -func newDirFileInfo(name string) os.FileInfo { - return &bindataFileInfo{ - name: name, - size: 0, - mode: os.FileMode(2147484068), // equal os.FileMode(0644)|os.ModeDir - modTime: time.Time{}} -} - -// AssetFile return a http.FileSystem instance that data backend by asset -func AssetFile() http.FileSystem { - return &assetOperator{} -} - -var _app2App2app3CssMainCss = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\xca\x4f\xa9\x54\xa8\xe6\xe5\x52\x50\x50\x50\x48\x4a\x4c\xce\x4e\x2f\xca\x2f\xcd\x4b\xd1\x4d\xce\xcf\xc9\x2f\xb2\x52\x48\xca\x29\x4d\xb5\xe6\xe5\xaa\x05\x04\x00\x00\xff\xff\x52\xd7\xbb\x8b\x26\x00\x00\x00" - -func app2App2app3CssMainCssBytes() ([]byte, error) { - return bindataRead( - _app2App2app3CssMainCss, - "app2/app2app3/css/main.css", - ) -} - -func app2App2app3CssMainCss() (*asset, error) { - bytes, err := app2App2app3CssMainCssBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app2/app2app3/css/main.css", size: 38, mode: os.FileMode(438), modTime: time.Unix(1595043712, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _app2App2app3DirsDir1TextTxt = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\x2c\x28\x30\xd2\x07\x11\x89\x05\x05\xc6\xfa\x29\x99\x45\xc5\x20\xc2\x50\xbf\x24\xb5\xa2\x44\xaf\xa4\xa2\x04\x10\x00\x00\xff\xff\x87\xaf\x9d\x00\x20\x00\x00\x00" - -func app2App2app3DirsDir1TextTxtBytes() ([]byte, error) { - return bindataRead( - _app2App2app3DirsDir1TextTxt, - "app2/app2app3/dirs/dir1/text.txt", - ) -} - -func app2App2app3DirsDir1TextTxt() (*asset, error) { - bytes, err := app2App2app3DirsDir1TextTxtBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app2/app2app3/dirs/dir1/text.txt", size: 32, mode: os.FileMode(438), modTime: time.Unix(1594843207, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _app2App2app3DirsDir2TextTxt = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\x2c\x28\x30\xd2\x07\x11\x89\x05\x05\xc6\xfa\x29\x99\x45\xc5\x20\xc2\x48\xbf\x24\xb5\xa2\x44\xaf\xa4\xa2\x04\x10\x00\x00\xff\xff\x84\x14\xaa\xeb\x20\x00\x00\x00" - -func app2App2app3DirsDir2TextTxtBytes() ([]byte, error) { - return bindataRead( - _app2App2app3DirsDir2TextTxt, - "app2/app2app3/dirs/dir2/text.txt", - ) -} - -func app2App2app3DirsDir2TextTxt() (*asset, error) { - bytes, err := app2App2app3DirsDir2TextTxtBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app2/app2app3/dirs/dir2/text.txt", size: 32, mode: os.FileMode(438), modTime: time.Unix(1594843207, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _app2App2app3DirsTextTxt = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\x2c\x28\x30\xd2\x07\x11\x89\x05\x05\xc6\xfa\x29\x99\x45\xc5\xfa\x25\xa9\x15\x25\x7a\x25\x15\x25\x80\x00\x00\x00\xff\xff\x64\xfe\x96\xd6\x1b\x00\x00\x00" - -func app2App2app3DirsTextTxtBytes() ([]byte, error) { - return bindataRead( - _app2App2app3DirsTextTxt, - "app2/app2app3/dirs/text.txt", - ) -} - -func app2App2app3DirsTextTxt() (*asset, error) { - bytes, err := app2App2app3DirsTextTxtBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app2/app2app3/dirs/text.txt", size: 27, mode: os.FileMode(438), modTime: time.Unix(1594843207, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _app2App2app3IndexHtml = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x90\x3f\x4f\xc3\x40\x0c\xc5\xf7\x48\xf9\x0e\xc6\x33\xed\x91\x76\x61\xb8\x8b\x54\xf1\x47\x6c\x30\x94\x81\xf1\x7a\x31\x9c\x85\x73\x39\xe5\x4c\x4b\xbf\x3d\x4a\x68\x90\x58\x6c\x3d\xfb\xbd\x9f\x64\xdb\xab\xfb\xe7\xbb\xfd\xdb\xcb\x03\x44\xed\xa5\xad\x2b\x3b\x75\x10\x9f\x3e\x1c\x52\xc2\xb6\xae\xa6\x19\xf9\xae\xad\x2b\x00\x00\xdb\x93\x7a\x08\xd1\x8f\x85\xd4\xe1\xeb\xfe\x71\x75\x8b\xff\x76\xc9\xf7\xe4\xf0\xc8\x74\xca\xc3\xa8\x08\x61\x48\x4a\x49\x1d\x9e\xb8\xd3\xe8\x3a\x3a\x72\xa0\xd5\x2c\xae\x81\x13\x2b\x7b\x59\x95\xe0\x85\x5c\xb3\xbe\xf9\x63\x09\xa7\x4f\x18\x49\x1c\x16\x3d\x0b\x95\x48\xa4\x08\x71\xa4\x77\x87\x26\x7f\x1d\x84\x83\xf1\x39\x6f\xe6\xe2\x73\xde\x9a\x50\x8a\xe9\x3d\xa7\x75\x28\x05\xc1\x2c\x20\x65\x15\x6a\x77\x39\x6f\x76\x39\x6f\xad\xf9\xd5\x75\x65\xcd\xe5\xac\xba\xb2\x87\xa1\x3b\x2f\xfe\xd8\xb4\x4f\x24\x32\xc0\x12\x01\x4e\x1d\x7d\x5b\x13\x9b\x39\x75\xf1\xce\x80\xe9\x67\x3f\x01\x00\x00\xff\xff\xef\x25\x54\xc8\x43\x01\x00\x00" - -func app2App2app3IndexHtmlBytes() ([]byte, error) { - return bindataRead( - _app2App2app3IndexHtml, - "app2/app2app3/index.html", - ) -} - -func app2App2app3IndexHtml() (*asset, error) { - bytes, err := app2App2app3IndexHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app2/app2app3/index.html", size: 323, mode: os.FileMode(438), modTime: time.Unix(1595043725, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _app2IndexHtml = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb2\xc9\x30\xb4\xf3\x48\xcd\xc9\xc9\x57\x70\x2c\x28\x30\x52\xc8\xcc\x4b\x49\xad\xb0\xd1\xcf\x30\xb4\x03\x04\x00\x00\xff\xff\x75\x17\xab\xfa\x19\x00\x00\x00" - -func app2IndexHtmlBytes() ([]byte, error) { - return bindataRead( - _app2IndexHtml, - "app2/index.html", - ) -} - -func app2IndexHtml() (*asset, error) { - bytes, err := app2IndexHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app2/index.html", size: 25, mode: os.FileMode(438), modTime: time.Unix(1565946440, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _app2MydirTextTxt = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xca\x2a\x2d\x2e\x51\x48\x54\x28\x49\xad\x28\xd1\x03\x04\x00\x00\xff\xff\x2f\xf9\x22\x98\x0c\x00\x00\x00" - -func app2MydirTextTxtBytes() ([]byte, error) { - return bindataRead( - _app2MydirTextTxt, - "app2/mydir/text.txt", - ) -} - -func app2MydirTextTxt() (*asset, error) { - bytes, err := app2MydirTextTxtBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app2/mydir/text.txt", size: 12, mode: os.FileMode(438), modTime: time.Unix(1594787248, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _cssMainCss = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\xca\x4f\xa9\x54\xa8\xe6\xe5\x52\x50\x50\x50\x48\x4a\x4c\xce\x4e\x2f\xca\x2f\xcd\x4b\xd1\x4d\xce\xcf\xc9\x2f\xb2\x52\x48\xca\x49\x4c\xce\xb6\xe6\xe5\xaa\xe5\xe5\x02\x04\x00\x00\xff\xff\x03\x25\x9c\x89\x29\x00\x00\x00" - -func cssMainCssBytes() ([]byte, error) { - return bindataRead( - _cssMainCss, - "css/main.css", - ) -} - -func cssMainCss() (*asset, error) { - bytes, err := cssMainCssBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "css/main.css", size: 41, mode: os.FileMode(438), modTime: time.Unix(1565946440, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _faviconIco = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\x0b\x70\x55\xc7\x79\xde\x7b\xce\x45\x12\xb2\x90\xc4\xc3\xe6\x61\x3b\x90\xf8\x31\xc4\x19\x6c\x32\xe3\xc4\x34\xe3\xc6\x34\x6d\xed\xd4\x69\x62\x32\x49\x9a\xa6\x75\xea\x36\x33\xee\xd8\x9e\xb4\x75\xdc\x7a\xa6\xc5\x31\x02\xa6\xd3\x84\x47\x28\x6f\x3b\xc6\x3c\xcc\xeb\x9e\xbd\x08\x21\x04\x92\x28\x12\x0e\x08\x5b\x3c\xec\x02\x92\x78\x08\x21\x09\x41\x25\x24\x10\xe8\x71\xb5\xe7\xdc\xd7\xb9\xf7\xef\xfc\xff\x9e\x73\x74\x25\xdd\x97\x24\x82\x33\x1e\xce\xcc\x3f\x7b\xee\x9e\xdd\xff\xff\xf6\xdf\x7f\xff\xfd\xf7\xdf\xcb\x98\x8b\xa9\x2c\x3f\x1f\xcb\x19\xec\x15\x37\x63\x5f\x67\x8c\xcd\x98\x21\x7f\x6b\xf9\x8c\x6d\x72\x33\x36\x7b\xb6\xf5\xfb\x11\xc6\x9e\xbd\x97\xb1\x99\x8c\xb1\x7c\x6c\xc7\x64\x3d\x3d\x6e\x76\xdb\x1f\xe1\x75\xab\x42\x53\x7e\x22\x3c\x6c\x91\xf0\xb0\x02\x22\xae\x14\x08\x8f\xab\x40\xec\x64\x92\xf0\x5d\x53\xfe\x59\xec\x64\x5f\x15\x1e\xa6\x08\x4f\x7f\x7f\xdf\x7a\x96\xa1\x97\x3c\xb8\x3f\x78\xfa\x0d\x08\x9e\x5d\x08\xc1\xda\x5f\x82\x51\xf6\x65\x30\xca\x67\x41\xf0\xcc\xbf\x11\x19\x07\x1e\x07\xbd\x78\x2a\x18\x65\x8f\xb5\x0b\x4d\x7d\xad\x6f\x07\x73\x0b\xcd\x45\xfd\xbb\x17\xb3\x0c\xa3\x62\xce\xfe\xa8\xd1\x0a\xf8\x98\x6d\x25\x10\x38\xfe\x53\x88\xdc\x3a\x01\x66\x6b\x11\x11\xbe\x07\x8e\xfd\x2d\x84\x2e\x2c\x05\xff\xd1\x79\x3d\xc2\xc3\x7e\x20\x78\x06\x13\x5c\x89\xe9\xdf\x06\xd1\x50\x2f\x04\x4e\xfc\x0c\xcc\x6b\xa5\x60\x1c\xfd\x21\x74\x6c\x1e\x47\x84\xef\x58\x17\xf8\xe4\x65\x30\x6f\x54\x81\x71\xe0\x89\xea\xbe\x2d\x6c\xd2\x80\xfe\xfe\x76\x30\x6f\x1c\x81\x60\xed\x7c\x08\x9e\x5d\x0c\x2d\xeb\xc7\x41\xed\xd2\x29\x50\xbb\x74\x32\xbd\x63\x1d\x7e\xc3\x36\xa1\x73\xff\x19\x14\x1e\x36\x4f\x78\xc7\xc4\xf4\xef\x80\x70\xd3\xfb\x10\x6e\x5c\x0f\xdd\x65\x73\xe1\xdc\xf2\x89\xd0\xb1\x25\x0f\x6e\x7c\x90\x07\xe7\x7f\x33\x81\xea\xf0\x5b\xb8\x79\x13\x61\xd0\x8b\xa7\x2c\x09\x7c\xfc\x57\xac\x7b\x11\xf6\x7f\x6a\x5f\xd4\xb8\x06\xa1\xfa\x15\x10\x6e\x7a\x0f\x3a\xb4\xc7\xa0\x61\x55\x3e\x04\x8f\xfc\x39\x84\x3e\xfa\x4b\x68\x5c\x93\x4f\x75\xf8\x2d\x74\x71\x05\x44\x45\x13\xea\x54\xeb\x7c\x85\xa9\x48\xf8\x1e\x15\xcd\xf4\xcd\xee\x7f\x71\x65\x3e\x04\x3e\x7c\x86\x78\x5c\x5a\x1d\xd3\xbf\x7e\x05\xa0\x2c\x94\x89\xb2\x03\xd5\x3f\x66\x88\x05\x31\x21\x36\x1b\xff\xd9\xe5\x13\xe1\xda\xc6\x5c\x68\xdf\x94\x4b\x63\x71\xf0\x37\xbd\x0f\x38\x56\x1c\x33\x8e\x1d\x75\x80\xba\x40\x9d\x0c\xd6\x5f\xcd\x92\x29\x44\x83\xf5\x87\xba\x76\xfa\x73\x85\xe1\x5c\x18\x07\x9e\x38\x86\x18\x68\x8e\xac\xf9\xbb\xbe\x39\x87\xc8\x99\xbf\x13\x3f\xa3\x39\xc6\xb9\x8e\xed\x4f\xb6\xe0\x61\x3f\x40\xdb\x40\x1b\x41\x5b\x19\x62\x3f\xc7\x7f\x4a\xb6\x85\x0f\xda\x9a\xdd\x9f\xd6\x80\xe6\x62\xd2\x26\xd5\xd7\xd0\x46\xc9\x56\x0f\x3c\xde\x6f\xbf\xe5\xb3\xc8\xa6\xd1\xb6\xc9\xc6\x4f\xbf\x01\x68\xf3\x68\xfb\xce\x3a\xf2\x30\x26\x76\x32\x85\xd6\x08\xae\x95\xc1\xeb\x87\xd6\x14\xb3\x69\x11\xad\x39\xaf\x5b\x1d\xed\xfa\x05\x60\x8c\x65\x32\xc6\x54\x8b\x5c\x31\x64\x3d\x0b\x63\xe8\xb0\x45\x2d\x56\xdf\x99\x96\x8f\x99\x1b\xeb\x67\xf2\x47\x8b\xea\xf3\xf9\x08\xae\x22\xe5\x09\xae\x4e\x17\x5c\xfd\xc2\x28\x69\x8a\xe0\xca\x58\xb4\x3d\xdb\x17\xa6\x29\xff\x5f\x04\x57\x5b\x85\xe6\xba\x92\x90\xb8\x1a\x43\x4a\x4c\xbd\x62\xd7\xb7\x08\xae\xd6\x0b\xae\xfe\x8f\xe0\xea\x9b\x38\x1e\x1f\x1f\x4b\xfe\x34\xb5\x7c\xa5\x40\xec\xca\x02\xbd\x64\x3a\xe8\xfb\xbe\x38\x94\x4a\xa6\x83\xf0\x66\x82\xd0\x14\x10\x9a\x0b\x44\xe1\x38\x5c\x2b\x44\xf8\x4e\x75\x5c\x01\xe1\x75\x03\xf2\x11\x9a\x2b\x2a\xb8\x52\x2b\xb8\x3a\x4f\x68\x8a\x92\x0c\x03\xc9\xf7\xb0\x02\xa3\xfc\x2b\x10\xe9\xae\x85\xa8\x7e\x15\xa2\xfa\x95\x18\xba\x0a\xa1\xb3\x8b\x49\xbe\xbe\xe7\x5e\x08\xfe\xef\x3f\x81\xd9\x51\x09\x91\xbe\x4b\x44\xf8\x8e\x75\xf8\x4d\x70\x37\x04\x3e\xfe\x11\xf9\x14\xbd\x68\x3c\xe2\xe8\x14\x5c\x7d\x49\x78\x99\x2b\x11\x06\x47\xfe\x81\xd9\x10\x0d\xde\x82\xc1\x8f\x79\xe3\x30\xe8\x7b\xa7\x81\x51\xfa\x28\x98\xd7\xca\x00\xa2\xa6\xfc\x80\x65\xcc\x3b\x7e\xc3\x36\xfa\xde\x07\x08\x93\xd9\x5a\x0c\xfa\xfe\x87\x41\x68\xac\x43\x70\xf5\x59\x92\xe3\x1d\xea\x1a\x92\xc9\x8f\x06\x3a\xc1\xff\xe1\x5c\xda\x67\x91\x27\x3e\x91\xde\x0b\xe4\xaf\xfc\x47\x5f\x20\xc2\x77\xac\x23\xac\x1d\x95\xd4\xd6\xff\xe1\x9f\x10\x2f\xfa\x5d\xf2\x05\xc4\x70\x4c\x70\xf5\x7e\x94\x35\x1c\xf9\xa1\xc6\x77\x68\x3e\x43\x17\x57\x4a\xfe\xe8\xc3\xcb\xbe\x8c\xfc\xa0\xcf\x23\x09\xdf\xb1\x0e\xbf\x51\x9f\x8b\x2b\x65\x9f\xc6\x77\xe8\x37\xee\x4f\x62\xd7\x58\xb4\x8f\x05\x3e\x9e\x35\xc4\x1e\x13\xc9\x8f\x06\xbb\xc0\xa8\xfc\x23\xf0\x1f\xfa\x63\x88\x86\xba\x21\x72\xeb\x24\x18\xfb\x1f\x82\xde\x1d\x2e\x68\xdd\x30\x0e\x1a\x56\x4f\x24\xc2\x77\xac\xc3\x6f\xd8\x06\xdb\x62\x1f\xec\x8b\xef\x10\xd6\xc1\xff\xd1\xf7\x11\x67\x83\xe0\xea\x97\x06\xeb\x20\x91\x7c\xd2\xdd\xee\x3c\x08\x37\x6f\x04\x30\x0d\x08\x7c\x34\x8f\xe4\x34\xae\x99\x00\xa7\x7f\x3d\x0d\x4e\xfd\xea\x7e\x22\x7c\xc7\x3a\xfc\x86\x6d\xb0\x6d\xb8\x69\x23\xf5\xb5\xe7\xcc\x6c\x3f\x00\x62\x77\x6e\x54\x68\xae\x57\xad\xf5\x96\x52\x7e\xb0\x6e\x01\xe8\xfb\x66\xd0\x1a\x30\xaf\x95\x83\x28\xcc\x81\x2b\xef\xe6\x92\x3c\x24\x8a\x63\x96\x4d\x71\x7e\xe3\x37\x6c\x83\x6d\xb1\x0f\xf6\x0d\xd6\x15\x48\x5d\x86\x7c\x64\x47\xc2\xc3\xf6\x0a\xae\x66\xc6\xea\x20\xae\xfc\x48\x08\xfc\x55\xdf\x05\x7f\xd5\x77\x00\x22\x41\x08\x7e\xfa\x2a\x74\x6d\x53\xa1\x6e\xf9\x64\x92\x75\x69\xcd\x44\xb8\xb9\x35\x13\x6e\x6d\xcb\x80\xe6\x75\xe3\xa9\x0e\xbf\x61\x1b\x6c\x8b\x7d\xb0\xaf\xbf\xea\x7b\xc4\x8b\xec\xe2\xec\x22\x9c\x83\x66\xc1\xd5\x19\xa9\xe4\xd3\xdc\x1f\x98\x0d\xc1\x33\x6f\x42\x34\xec\x03\x7f\xe5\x1c\x68\xdb\x30\x96\xe4\x9c\xfb\xcd\x7d\xd0\xbd\x63\x0c\xe8\x85\x63\x41\x2f\xbc\x07\x7a\x3d\x6e\xa8\x5f\x39\x89\xbe\x61\x1b\x6c\x8b\x7d\xb0\xaf\xe4\xd9\x65\xd9\x6e\x19\x88\x5d\xd9\xba\xd0\x5c\x73\x53\xca\xd7\xff\x0f\xf4\xfd\x0f\x41\xa8\x61\x35\xf9\x1f\x7d\xdf\x74\x68\x5e\x97\x47\xf3\xdd\xf2\x4e\x1e\xc9\x0d\x9f\xfc\x3b\x30\x4f\xbd\x02\xc6\x9e\x09\xd0\xba\x21\x07\x4e\xfd\x6a\x1a\xb5\xc1\xb6\xe4\xb3\x1a\x56\x13\x0f\xe4\x25\xd7\xed\x39\x5c\x9b\x51\xa1\xb1\x17\xe3\xc8\x7f\x0b\x63\x13\x5c\xef\xd4\xb6\xaf\x91\x7c\x6b\xf8\xf2\x16\x5a\xdb\x62\xcf\x64\xb8\xb4\x7a\x3c\xc9\x68\xdb\x90\x0d\xfe\xb2\x87\x01\x2e\x2d\x07\x68\x5a\x05\x81\xca\x27\xe1\xfa\xe6\x4c\x39\x2f\xab\xc7\x53\xdb\x88\xaf\x9e\xfa\x22\x0f\xe4\xe5\xc4\x47\xa5\x8f\xa2\x0d\xfc\x22\x8e\xfc\x5f\xe0\x37\x3b\x5e\x4f\x2e\xff\x1e\xf0\x97\x7e\x11\xa2\x0d\x4b\x00\x9a\x56\x42\xe0\xe0\x13\x70\x7d\x53\x56\x6a\xf9\x81\x4e\x8a\xbf\x70\xac\x43\xe4\x6b\xec\x45\xd4\x0d\xea\x28\xbe\xfe\x67\x38\xfa\x6f\x5e\x97\x2f\xfd\xcb\xd1\xe7\x21\x74\xec\x87\xa0\xef\xce\x81\xab\xbf\x1d\x67\x7d\xcb\xb3\xd6\xcc\x50\xfd\xe3\xdc\xe2\x1c\xcb\xb3\xd0\x60\xf9\xae\xb9\x68\x1b\xe4\xdf\x53\xd8\x1f\xda\x39\xda\xbe\xee\x55\x41\xf7\xba\xc9\x16\xcf\xaf\xb8\x2f\xa5\xfd\x25\x95\x8f\x6b\x42\x63\xcd\xb8\xcf\x25\x5c\x7f\x5b\xe5\xfa\xc3\x39\xb8\xf0\xdf\xf7\x42\xfb\xc6\x7b\xa0\x63\x53\x36\x5c\x5c\x35\x29\xad\xf5\x97\x42\x7e\x26\xfa\x06\xda\x37\xc2\xbe\xb4\xfc\x0f\xd2\x99\x25\xd3\xd2\xf2\x3f\xc9\xe5\x2b\xf6\x1c\xbc\x86\x3e\x12\x7d\xe5\x50\xff\xeb\x8f\xe3\x7f\x25\x0d\xf5\xbf\xfe\x21\xfe\x37\x99\xfc\x18\x1d\x7c\x09\xf7\x08\xdc\x2b\xc0\xd4\x69\xef\x30\x2a\x46\xb9\xff\x58\x73\x9f\x5a\xbe\xc2\x7c\x1a\xed\x8d\x0b\x70\xaf\xc4\x3d\x53\xee\xbf\xef\x8e\x7a\xff\x4d\x47\x7e\x8c\x0e\xee\xc7\x58\x01\x63\x06\xd4\x1d\xf6\x41\x9b\x18\x51\xfc\x61\xf9\xb2\xb4\xe5\x7b\x55\x1b\xc3\xb3\x18\x33\x61\xec\x84\x31\x14\xf1\xdc\xfb\x40\x5a\xf1\x97\x4e\xf1\xd7\x34\x8a\xd9\x06\x3f\xa9\xe4\x3b\xb6\x48\xb1\xa2\xfa\x12\xc6\x8e\x18\x43\x62\x2c\x89\x31\x25\xc6\x96\x29\xe3\x4f\x6f\x26\xc5\xaa\xf1\x62\x58\x8c\x6d\x31\xc6\x4d\x26\xbf\x7f\x3d\x60\xcc\xac\xce\xa3\x18\x1a\x63\x69\x8c\xa9\xb9\x5b\xc6\xd8\x14\x7f\xe7\xc4\xc4\xdf\x39\xb2\x0e\x63\x73\x8c\x91\x93\xc5\xf0\xc4\x47\x49\x2a\x9f\x30\x68\x0a\xf3\x15\x65\x31\x6b\xaf\x7e\xd3\x3a\x53\xd4\x5b\x67\x8c\x44\xe7\x0f\x49\xc9\xcf\x30\xad\xd6\x59\x27\xa9\xfc\x58\x5d\xf4\x69\x14\x2f\x8d\x95\x67\xab\x51\x9f\xcf\xa6\x5b\x67\xbd\xb4\xe4\x7f\xde\x1f\x7b\x6d\x1c\x66\x2a\x1c\x66\x0c\xe9\x99\xc3\x8c\x4d\xb7\x28\xcf\xa2\x4c\x8b\xd4\x74\xa8\xc5\xa2\x1e\x8b\x02\x16\x99\x8c\xa9\xc0\x48\x90\x6a\xcb\x9d\xc9\x18\x9b\xcd\x18\xfb\xfb\xd8\x3c\xc5\xc3\x9f\xb5\x56\xee\x3e\x77\x9f\x3f\xcc\xc7\xda\x1f\x1f\x16\x5c\x7d\x5b\x70\x75\xa1\xe0\x6a\xc1\xef\x89\x6c\xde\xff\x2a\xb8\xfa\x37\x82\x2b\xb3\x05\x57\x72\x7a\x35\xc6\x0c\x2d\x79\x3e\x29\x0d\xfc\xdf\x16\x5c\x0d\x0a\xae\xc2\x1d\x22\x53\x70\xb5\x53\x70\xf5\x20\xed\xeb\x5c\xc9\xc7\x58\xc3\x48\x33\x3f\x97\x18\xbf\x42\xb1\x57\x5a\x84\x6d\x07\x60\x4a\xd2\x37\x6e\x5b\x97\xfd\x1b\xf5\x56\x2a\xb8\xfa\x24\xec\x67\x4c\xe7\xc3\x1b\x83\x83\x5f\x73\x05\x31\xc6\x0b\xd6\xbe\x45\xe7\xf2\x64\x14\x3c\xbb\x08\x8c\x8a\xa7\xfa\x71\x21\xc6\xc2\x1c\x30\x0e\x7e\x0d\x02\x27\xfe\x81\x78\x20\xe1\x3b\xd6\xc9\x78\x84\x39\xd8\xf5\xe2\x29\x60\x94\xcd\x04\xe1\xcd\x8a\x1d\x47\xa3\xe0\xea\x0b\x7e\xce\x5c\x7a\x8a\xfc\x64\x7c\xfc\x2c\x48\xf1\x75\xb8\x6f\x48\x9c\x37\xf8\x31\xdb\x4a\x64\x9c\x84\xb2\xbd\x19\xe0\x3f\xf2\x17\x60\xb6\xee\x85\x68\xe0\x26\x40\x34\x12\x13\x20\x46\xa8\x0e\xbf\x61\x1b\x6c\x8b\x7d\xf4\xe2\xc9\x10\x6a\x58\x0b\xe1\xcb\x5b\xc1\xa8\xfc\x46\xff\x9c\x70\xb5\x0d\xc7\xd0\xa3\x65\x33\x91\xe6\x3c\x0c\x17\x7f\xa4\xeb\x14\xc5\xb4\xc2\xc3\xe8\x3c\x43\xb1\x65\xb0\x3b\xe5\x98\xb1\x0d\xb6\xc5\x3e\xf2\x7c\x30\x13\x22\xdd\x35\x10\xf5\x5f\xa7\x73\xa9\x28\xbc\xc7\x1e\x43\x93\xe0\xca\x53\x14\x73\x16\xa6\x8e\x89\x86\x83\x9f\xce\x41\x55\xdf\x23\xec\x62\x77\x2e\x9d\xc7\xed\xb3\xa8\x1c\x5c\x10\xa2\xa2\x05\x22\xb7\x3e\x21\xc2\x77\xac\xeb\xff\x1e\xa2\x3e\xd8\x17\x79\x20\xaf\x68\xa8\x87\xda\x84\xea\x97\xcb\xbc\xb3\x1c\x43\xa5\xe0\xea\xe4\x74\x62\xba\xe1\xe0\x0f\x35\xac\x91\x36\xc0\xdd\x10\xac\x7b\xbb\x1f\x7b\x34\x0c\x66\x47\x05\xdd\x3d\xe9\xa5\x8f\x80\x5e\x34\x51\x52\xe9\x23\xf2\x3e\xaa\xa3\x82\xda\xd8\x63\x08\xd6\xfe\x52\xc6\xee\xde\x0c\xe2\x69\x8f\x1d\xcf\x4d\x92\xbf\x1a\x45\x7f\xeb\xf3\x32\x57\x5f\x0a\x3b\x4a\x17\x3f\xea\xd2\x28\x9f\x25\xf5\x76\xe4\x3b\xfd\x79\xad\x70\x1f\x84\xce\xff\x17\xe8\x7b\x26\x59\xfe\xc6\xca\xdb\xdb\x3e\x46\x63\xf4\x0d\xdb\xd8\xbc\xe9\x0c\x78\xe4\x79\xe2\x85\x3c\x69\x9e\x68\x7e\x7b\x21\x50\xfd\x63\x7b\x4d\x5f\x13\x5c\xfd\x7a\xca\x73\x45\x9a\xf8\x69\x7e\xad\xb5\x67\xde\xa8\xea\xd7\x59\xdd\x02\x79\x0f\xc1\xa5\x1f\xe9\xd9\x39\x06\x6e\x6e\xcd\x22\xc2\x77\xb9\x36\x5d\xd4\x06\xdb\xda\xf6\x64\xde\x38\x42\xbc\x90\x27\xf2\x76\x4c\xac\xbb\x86\x72\x44\xd6\x18\xde\xd3\xb9\xcb\x9d\xcc\x1f\xa5\x83\x9f\xf2\x5c\x15\x73\x48\x5f\x81\x4f\x5f\x75\xce\xa8\xe1\xcb\x5b\x1c\x9b\x45\xac\x57\xde\xcd\xa3\x5c\x66\xcd\xd2\x29\x44\xf8\x8e\x75\x72\x1c\x0a\xb5\xc5\x3e\x92\xa9\x49\xbc\x68\x0e\x2a\xe6\x0c\x38\x5b\x87\x2e\x2c\xb1\xce\x86\x6a\xbb\xe0\xea\x57\x93\x9f\x2d\x53\xe3\xa7\x5c\xcf\xae\x6c\xb2\x03\xb3\xb3\x5a\xea\xa9\xaf\x51\x9e\x5d\x35\x06\xdd\xdb\x33\x9c\x9c\x53\x3c\xc2\x6f\xd8\x86\xfc\x4e\xf9\x57\x9c\xfc\x9f\xd9\xf9\xb1\xb4\xbb\xc2\x6c\x30\xdb\xcb\xfb\xf5\xa5\x5f\x95\x79\x41\xb9\x67\x2c\x12\xdc\x9d\xf0\xce\x2a\x1d\xfc\xe4\xdf\xc8\x5f\x7c\x97\x72\xf1\x54\x57\xf3\xef\x64\x17\xbd\x1e\x37\xe5\x6c\x12\x61\xb7\x09\xdb\x60\x5b\xec\x83\x7d\xe5\x00\x0c\xe2\x89\xbc\x51\xc6\x00\x99\x75\x0b\x6d\x1b\x3a\x2e\xb8\x32\x61\xa4\xf8\xf1\x37\xe5\xe9\x35\x06\xa1\x86\x55\x96\x7e\x5a\xc0\x28\x9d\x49\x75\xad\xef\x8d\x1b\x82\xb5\x76\xd9\xc0\x7b\x00\x9b\xb0\xad\xed\xfb\xa3\xfa\x15\x69\x2b\x17\x57\x51\x1d\xca\x88\x95\x8d\xfe\x57\xde\x9f\x29\x3e\xc1\xd5\x6f\x26\xce\x8f\x24\xc7\x1f\xf1\x35\x80\x5e\xf2\x00\xe8\xbb\xf3\x21\x72\xf3\x98\x65\xf7\x1f\x80\xf0\x8e\x81\x9e\x1d\x63\xc8\xc6\x6d\x7c\x35\x4b\xa7\x92\xbd\xdf\xda\x96\x09\x5d\xdb\x33\xa1\x6d\x43\x8e\x73\xbf\x60\xe7\xf9\xb1\x0f\xfa\x48\xdc\x7b\x89\xff\xcd\x6a\xe2\x4d\x79\x65\x5f\xc3\x40\xbd\xfd\xee\x5b\xb6\x0d\x51\x7e\x3b\xde\x3a\x4e\x85\xdf\xec\x38\x44\xb6\x6f\x94\x3d\x46\xff\x67\xc0\x27\x70\xf2\x65\xe2\x7b\xed\xfd\x9c\x98\xbc\xe7\x54\xa9\x5f\x27\x16\x50\x40\xe7\x2a\x5c\xdf\x9c\x4d\xf7\x32\x76\x3b\xec\x83\x7d\x03\x9f\xfc\xa3\xc4\xe9\x6f\x27\xde\x28\x03\x65\x0d\xb0\xa1\x9a\xff\xb0\xf1\x6f\xd3\xb9\x2b\xee\x9d\x69\x2a\xfc\xa4\x6b\x9c\xdf\xc3\xcf\x01\x44\x02\x94\xcb\x35\x2a\x9f\xa6\xba\xa6\xb5\x13\x9c\x7c\x29\xae\x51\x9f\x47\xe6\x93\xf4\xc2\x6c\xd0\x77\x8f\x73\xe2\xcd\xcb\xeb\xf3\x9d\xfc\x2a\xf6\x21\x7e\x87\x9e\x96\x79\xe1\x48\x80\x78\x63\x1d\xca\x1a\x20\xfb\x2a\xb7\xf7\xb3\x6a\xc1\x95\xdc\x91\xe0\x0f\x5d\x58\x26\xfd\xe6\xf1\x97\xa4\xbe\xc4\x65\xca\x5d\xf5\xee\x54\x29\xe7\x6d\xeb\xb5\x0d\xf5\xca\x5d\x60\xec\x9d\x4a\x77\x30\x91\xda\x37\xc0\x5f\x3e\x93\xc6\xd3\xf9\xc1\x58\xb2\x2d\x3b\x4f\xee\xdb\xa9\x12\x0f\xe4\x45\xf3\x79\xfc\x25\x92\x81\xb2\x06\xd8\xee\xcd\x13\xf2\xce\x98\x2b\x4d\x82\xab\x0f\x26\xc9\x91\x3e\x97\x08\x3f\xed\x4f\x3b\x19\x04\x4f\xbd\x2e\x79\xf6\xd4\xd2\xbe\xd3\xbd\x7d\x0c\x9c\xb5\x6c\x1b\xb1\xe1\x7e\xa5\x7b\x55\x08\x1d\xfb\x11\x40\xf3\x5a\x22\xf3\xf4\xcf\x69\x2e\xd0\xff\xa3\xed\x23\x7e\xec\xd3\xbd\xdd\x4d\x31\x74\xa4\xa7\x4e\xca\x38\xf5\xba\x94\x81\xfb\x5b\xac\xef\x10\xcd\x74\xf7\x64\xdd\x79\xcf\x4a\x82\xff\x5b\x42\x63\x86\x71\xf0\xc9\x21\xb1\x24\xf9\x4e\xe4\x5d\x3b\xdf\xd2\xc9\x71\xd0\x8b\xf2\xa1\x6b\x5b\x86\xe3\x63\xb0\xec\xda\x9e\x41\xf7\x6f\x66\xcd\xeb\x00\xcd\x6b\x00\x9a\x56\x43\xb4\x7e\x31\x18\x7b\x27\x83\xcf\x23\xe7\x0a\xf1\x3b\x6d\x8b\xf2\xe9\xff\x3a\x24\xa3\x76\xbe\x94\x31\xc8\x87\x62\x6c\x4a\x31\x8b\xc6\xfa\x04\x57\x9f\x4e\x82\xff\x69\x6c\x43\xb1\x88\xff\xfa\xc8\xf0\x6f\xcb\x00\x7d\x57\x16\x98\x67\x7e\xde\x8f\xff\x42\x01\x18\xc5\x93\x08\xff\xf9\x91\xe0\x0f\x76\x03\xea\x14\x75\x4b\x3a\x4e\x8c\x7f\x16\xe5\x96\xf7\xcd\xa0\x39\x4b\x6e\x3f\x75\x34\xf7\x68\x03\xb6\xfd\xa0\xef\xb9\xb1\x85\xee\xd3\x21\x78\xe4\xcf\xe8\x0e\x10\xed\x27\x7c\xe2\x45\xd0\xbd\x19\xd0\xbd\x23\x83\xda\x0e\xdb\x7e\xc2\x7d\x74\x67\x81\xb6\x4d\x36\x9e\x18\xff\x83\xb8\x46\xf4\xa2\x09\x74\xdf\x31\x92\xf5\x7b\xf5\xb7\xb9\x96\xef\xc9\x81\x60\xd5\x73\x10\xaa\xfe\x3e\xe8\xc5\xf7\x82\xce\x15\xba\xd3\xc2\x31\x9e\xfa\xb5\xbd\x7e\x95\xb4\xd6\xef\x20\xfc\xdf\x8e\x8f\x9f\x72\xeb\xb9\xe4\xa3\x70\x5f\xb9\xca\x07\xf0\x48\xd7\x7f\x9e\x5b\x81\x7b\x53\x46\x7f\xec\x6c\x91\x4f\xeb\x8f\x2f\xb0\x6d\xe3\x30\xfc\x67\xba\xf8\xe5\xde\xa0\x6e\x47\x1e\xc1\x9a\xf9\x03\x78\xa4\xbb\x7f\x21\x35\xad\x1b\x0f\xbd\x9e\x31\xd6\x3d\xa6\x0a\x7d\x9a\x9b\xe6\x05\x75\x3f\x64\xff\x3a\xf9\xb2\xb5\x46\x13\xef\x5f\xe9\xe0\xd7\xed\xbb\x3e\xdc\xa3\x51\x2f\xbf\xfb\xd3\x81\x71\x48\xdc\xf8\x61\x6b\xdc\xf8\xc1\xde\xc7\x30\x6e\x40\x9c\xa8\xeb\x58\xec\xc3\x89\x1f\xd2\xc5\x1f\xb3\x06\xbe\x29\xb8\xd2\xa7\xef\xb9\x0f\x22\x5d\x9f\x0e\xe0\xe1\xc4\x6f\x17\xd3\x8b\xdf\x12\xd1\x70\xe2\xb7\xe1\xe1\xa7\x35\x30\x81\x62\x55\xcd\x45\xe7\xd0\xd8\xe7\xb3\x88\x9f\x87\x85\x5f\x53\x18\xfd\x3f\x95\xab\x8b\xe5\x19\xe3\x71\x3a\x43\x38\x6b\xe0\xf7\x76\x7e\xa9\x8e\x7b\x7e\x19\x2e\xfe\x18\x1b\xc2\xb3\x5a\x07\x9e\xdd\xf0\x0c\xe7\xf0\xb9\x23\xe7\xc7\x9b\xa3\xc4\x4f\x7e\xc8\x8d\x67\x66\x3a\xa7\xef\x7f\x88\xce\xd2\xf6\x93\xf6\xf9\x7d\x47\xcc\xf9\x7d\x47\xb2\xf3\x7b\x55\xdc\xf3\xfb\x48\xf1\xc7\xcc\xc1\xd7\x28\x77\x81\x3e\xae\xfa\xaf\x29\xa7\x01\x43\xf2\x27\xcf\x0f\xcc\x9f\x9c\xbb\x3d\xf9\x93\xd1\xe2\xef\xe3\x2e\xe6\xe3\x4c\x91\x67\x66\x35\x8a\x7e\x8e\xd6\xb2\xa5\xb3\xd4\xf9\xab\x17\xc1\x28\x7d\x04\xf4\x3d\x13\x89\x8c\x44\xf9\xab\xba\xb7\x87\xe6\xaf\x6e\x03\xfe\x98\x39\x98\x2c\xb8\x7a\xc8\xb6\xd9\x50\xfd\x32\x99\x1b\x0c\xf5\x38\xfe\xe2\xf6\xe5\x0f\x13\xe7\x4e\x47\x84\xbf\x50\xb5\xfd\xe9\x1c\x2b\x97\x4a\xb9\x55\xfa\xdf\x50\xe0\x3a\x44\xba\xcf\xc8\xdc\x37\xda\x8a\x9d\xbf\x4d\x82\xc1\xc1\x62\xe5\x6f\xb1\x0f\xe5\x7e\x4b\x1f\xa5\x5c\x70\xd2\x3e\x23\xc0\x4f\x63\xf0\xba\x58\x8f\x27\x1b\xe7\xe1\x05\x99\xd3\x56\x68\xbe\x8d\xca\x6f\xd0\xbe\x19\x6a\x58\xeb\xac\x3d\x27\x7f\xde\x56\x92\x7e\xfe\xbc\xe4\x41\x30\xdb\xf6\xa5\x1e\xf3\x08\xf1\xe3\xa3\x7b\x15\x66\xec\xa2\xff\x6d\xbc\x60\xdd\x2d\x48\xbc\xbb\xb2\xe8\xbf\x31\x7a\xf1\xd4\x24\xf7\x17\xf3\x89\x12\xdd\x5f\x18\x15\x4f\xd1\x1d\x48\xca\x7b\x92\xda\xb7\xac\xff\xda\xba\x86\x8d\x9f\xc6\xc0\x5d\x0c\xbc\xe4\x5b\xd1\x27\x95\x39\x77\x64\x8e\x8f\x19\xcd\xfd\xd1\xb0\xee\xa9\x46\x84\x1f\x1f\x43\x73\xd9\x6b\x7a\xbc\xbc\x6b\xa3\x3b\xb7\x4e\xeb\x0e\xee\x4e\xdd\xf7\x8d\x18\xbf\x33\x0e\x8f\xc2\x7a\x8b\x54\x8c\x35\x72\x04\x57\x67\x0b\xae\xfe\xc4\xba\x0b\x2d\xb8\x03\xf7\xae\x6f\x5b\x77\xbc\x23\xc6\x7f\xf7\xb9\xfb\x7c\x9e\x1e\xb9\x43\x24\x2e\x5b\x18\x63\xcf\x58\x65\x9e\x55\x66\x5a\xa5\x6b\x50\xc9\xec\xb2\xc0\x2a\x9f\x19\x54\x4e\x4f\x50\xe6\x25\x28\x33\x6f\x5f\xd9\x93\xa0\x0c\x24\x28\xcd\x41\x65\xd4\x2a\xc1\x2e\x17\x0e\x2a\x5b\xac\xb2\xc7\x2a\x4d\xab\x4c\xa1\xdf\xff\x0f\x00\x00\xff\xff\xc6\xb9\x24\x2f\xee\x3a\x00\x00" - -func faviconIcoBytes() ([]byte, error) { - return bindataRead( - _faviconIco, - "favicon.ico", - ) -} - -func faviconIco() (*asset, error) { - bytes, err := faviconIcoBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "favicon.ico", size: 15086, mode: os.FileMode(438), modTime: time.Unix(1565946440, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _indexHtml = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\x91\x3d\x4f\xc3\x30\x10\x86\xf7\x48\xf9\x0f\xd7\x9b\x40\x22\x35\x6c\x0c\x71\x96\x42\x57\x90\x28\x03\xa3\xeb\x5c\x9b\x6b\x1d\x27\xb2\x2f\x69\xfb\xef\x51\x3e\xca\xe7\x64\xdf\xeb\xbb\xc7\x8f\xec\x7c\xf1\xf4\xb2\xda\x7c\xbc\x3e\x43\x25\xb5\x2b\xd2\x24\x1f\x56\x70\xc6\xef\x35\x92\xc7\x22\x4d\x86\x8c\x4c\x59\xa4\x09\x00\x40\x5e\x93\x18\xb0\x95\x09\x91\x44\xe3\xfb\x66\x9d\x3d\xe2\xaf\x33\x6f\x6a\xd2\xd8\x33\x9d\xda\x26\x08\x82\x6d\xbc\x90\x17\x8d\x27\x2e\xa5\xd2\x25\xf5\x6c\x29\x1b\x8b\x3b\x60\xcf\xc2\xc6\x65\xd1\x1a\x47\xfa\x61\x79\xff\xc5\x72\xec\x8f\x10\xc8\x69\x64\xdb\x78\x84\x2a\xd0\x4e\xa3\x6a\xbb\xad\x63\xab\x76\xa6\x1f\xe2\x25\xdb\x06\x41\x2e\x2d\x69\xe4\xda\xec\x49\x9d\xb3\xa9\x5d\xfd\xe7\x44\xb9\x38\x8a\x15\x91\xfc\xa5\xd9\x18\x55\x6d\xd8\x2f\x6d\x8c\x3f\x46\x85\xc5\x51\xb1\x66\x47\xf0\x46\xa1\xa7\x90\xab\x29\x4a\x93\x5c\xcd\x6f\x92\x26\xf9\xb6\x29\x2f\xd7\x11\xf6\x6d\x27\xb3\xd0\xb6\x13\x19\x54\x1a\x6f\x1d\xdb\xa3\xc6\xc6\xaf\x86\xcd\xcd\x2d\x42\x6f\x5c\x47\x1a\xc7\x1a\x6a\x5a\x4c\xb7\xce\x90\x68\x03\xb7\x57\x8a\xd0\x59\xd4\xc1\xf4\x66\x4a\x11\x62\xb0\xdf\xe6\x87\x59\xfc\x10\xb1\xc8\xd5\xd4\x32\xea\xcd\x52\xa3\xe9\xf0\xb3\x9f\x01\x00\x00\xff\xff\x00\xcf\x96\xa8\xe9\x01\x00\x00" - -func indexHtmlBytes() ([]byte, error) { - return bindataRead( - _indexHtml, - "index.html", - ) -} - -func indexHtml() (*asset, error) { - bytes, err := indexHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "index.html", size: 489, mode: os.FileMode(438), modTime: time.Unix(1594886229, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _jsMainJs = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\xce\xcf\x2b\xce\xcf\x49\xd5\xcb\xc9\x4f\xd7\x50\x4a\xad\x48\xcc\x2d\xc8\x49\x55\xd2\xb4\xe6\xe5\xe2\xe5\x4a\x2b\xcd\x4b\x2e\xc9\xcc\xcf\x53\xc8\xcf\x73\xce\xc9\x4c\xce\xd6\xd0\x54\xa8\xe6\xe5\x52\x50\x50\x50\x28\xcf\xcc\x4b\xc9\x2f\xd7\x4b\xcc\x49\x2d\x2a\xd1\x50\x4a\x2a\x2d\x29\xc9\xcf\x53\x48\x06\xa9\x49\x4d\x01\x6b\xae\x05\x04\x00\x00\xff\xff\xa4\xb7\x99\x52\x57\x00\x00\x00" - -func jsMainJsBytes() ([]byte, error) { - return bindataRead( - _jsMainJs, - "js/main.js", - ) -} - -func jsMainJs() (*asset, error) { - bytes, err := jsMainJsBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "js/main.js", size: 87, mode: os.FileMode(438), modTime: time.Unix(1594787764, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "app2/app2app3/css/main.css": app2App2app3CssMainCss, - "app2/app2app3/dirs/dir1/text.txt": app2App2app3DirsDir1TextTxt, - "app2/app2app3/dirs/dir2/text.txt": app2App2app3DirsDir2TextTxt, - "app2/app2app3/dirs/text.txt": app2App2app3DirsTextTxt, - "app2/app2app3/index.html": app2App2app3IndexHtml, - "app2/index.html": app2IndexHtml, - "app2/mydir/text.txt": app2MydirTextTxt, - "css/main.css": cssMainCss, - "favicon.ico": faviconIco, - "index.html": indexHtml, - "js/main.js": jsMainJs, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "app2": {nil, map[string]*bintree{ - "app2app3": {nil, map[string]*bintree{ - "css": {nil, map[string]*bintree{ - "main.css": {app2App2app3CssMainCss, map[string]*bintree{}}, - }}, - "dirs": {nil, map[string]*bintree{ - "dir1": {nil, map[string]*bintree{ - "text.txt": {app2App2app3DirsDir1TextTxt, map[string]*bintree{}}, - }}, - "dir2": {nil, map[string]*bintree{ - "text.txt": {app2App2app3DirsDir2TextTxt, map[string]*bintree{}}, - }}, - "text.txt": {app2App2app3DirsTextTxt, map[string]*bintree{}}, - }}, - "index.html": {app2App2app3IndexHtml, map[string]*bintree{}}, - }}, - "index.html": {app2IndexHtml, map[string]*bintree{}}, - "mydir": {nil, map[string]*bintree{ - "text.txt": {app2MydirTextTxt, map[string]*bintree{}}, - }}, - }}, - "css": {nil, map[string]*bintree{ - "main.css": {cssMainCss, map[string]*bintree{}}, - }}, - "favicon.ico": {faviconIco, map[string]*bintree{}}, - "index.html": {indexHtml, map[string]*bintree{}}, - "js": {nil, map[string]*bintree{ - "main.js": {jsMainJs, map[string]*bintree{}}, - }}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} diff --git a/_examples/file-server/http2push-embedded-gzipped/main.go b/_examples/file-server/http2push-embedded-gzipped/main.go deleted file mode 100644 index 8714d137..00000000 --- a/_examples/file-server/http2push-embedded-gzipped/main.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "regexp" - - "github.com/kataras/iris/v12" -) - -// How to run: -// $ go get -u github.com/go-bindata/go-bindata/v3/go-bindata -// $ go-bindata -nomemcopy -fs -prefix "../http2push/assets" ../http2push/assets/... -// $ go run . - -var opts = iris.DirOptions{ - IndexName: "index.html", - PushTargetsRegexp: map[string]*regexp.Regexp{ - "/": iris.MatchCommonAssets, - "/app2/app2app3": iris.MatchCommonAssets, - }, - ShowList: true, - Cache: iris.DirCacheOptions{ - Enable: true, - CompressIgnore: iris.MatchImagesAssets, - // Here, define the encodings that the cached files should be pre-compressed - // and served based on client's needs. - Encodings: []string{"gzip", "deflate", "br", "snappy"}, - CompressMinSize: 50, // files smaller than this size will NOT be compressed. - Verbose: 1, - }, -} - -func main() { - app := iris.New() - app.HandleDir("/public", AssetFile(), opts) - - // https://127.0.0.1/public - // https://127.0.0.1/public/app2 - // https://127.0.0.1/public/app2/app2app3 - // https://127.0.0.1/public/app2/app2app3/dirs - app.Run(iris.TLS(":443", "../http2push/mycert.crt", "../http2push/mykey.key")) -} diff --git a/_examples/file-server/http2push-embedded/bindata.go b/_examples/file-server/http2push-embedded/bindata.go deleted file mode 100644 index 78976fd8..00000000 --- a/_examples/file-server/http2push-embedded/bindata.go +++ /dev/null @@ -1,580 +0,0 @@ -// Code generated by go-bindata. (@generated) DO NOT EDIT. - -//Package main generated by go-bindata.// sources: -// ../http2push/assets/app2/app2app3/css/main.css -// ../http2push/assets/app2/app2app3/dirs/dir1/text.txt -// ../http2push/assets/app2/app2app3/dirs/dir2/text.txt -// ../http2push/assets/app2/app2app3/dirs/text.txt -// ../http2push/assets/app2/app2app3/index.html -// ../http2push/assets/app2/index.html -// ../http2push/assets/app2/mydir/text.txt -// ../http2push/assets/css/main.css -// ../http2push/assets/favicon.ico -// ../http2push/assets/index.html -// ../http2push/assets/js/main.js -package main - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(data, name string) ([]byte, error) { - gz, err := gzip.NewReader(strings.NewReader(data)) - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -// Name return file name -func (fi bindataFileInfo) Name() string { - return fi.name -} - -// Size return file size -func (fi bindataFileInfo) Size() int64 { - return fi.size -} - -// Mode return file mode -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} - -// ModTime return file modify time -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} - -// IsDir return file whether a directory -func (fi bindataFileInfo) IsDir() bool { - return fi.mode&os.ModeDir != 0 -} - -// Sys return file is sys mode -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -type assetFile struct { - *bytes.Reader - name string - childInfos []os.FileInfo - childInfoOffset int -} - -type assetOperator struct{} - -// Open implement http.FileSystem interface -func (f *assetOperator) Open(name string) (http.File, error) { - var err error - if len(name) > 0 && name[0] == '/' { - name = name[1:] - } - content, err := Asset(name) - if err == nil { - return &assetFile{name: name, Reader: bytes.NewReader(content)}, nil - } - children, err := AssetDir(name) - if err == nil { - childInfos := make([]os.FileInfo, 0, len(children)) - for _, child := range children { - childPath := filepath.Join(name, child) - info, errInfo := AssetInfo(filepath.Join(name, child)) - if errInfo == nil { - childInfos = append(childInfos, info) - } else { - childInfos = append(childInfos, newDirFileInfo(childPath)) - } - } - return &assetFile{name: name, childInfos: childInfos}, nil - } else { - // If the error is not found, return an error that will - // result in a 404 error. Otherwise the server returns - // a 500 error for files not found. - if strings.Contains(err.Error(), "not found") { - return nil, os.ErrNotExist - } - return nil, err - } -} - -// Close no need do anything -func (f *assetFile) Close() error { - return nil -} - -// Readdir read dir's children file info -func (f *assetFile) Readdir(count int) ([]os.FileInfo, error) { - if len(f.childInfos) == 0 { - return nil, os.ErrNotExist - } - if count <= 0 { - return f.childInfos, nil - } - if f.childInfoOffset+count > len(f.childInfos) { - count = len(f.childInfos) - f.childInfoOffset - } - offset := f.childInfoOffset - f.childInfoOffset += count - return f.childInfos[offset : offset+count], nil -} - -// Stat read file info from asset item -func (f *assetFile) Stat() (os.FileInfo, error) { - if len(f.childInfos) != 0 { - return newDirFileInfo(f.name), nil - } - return AssetInfo(f.name) -} - -// newDirFileInfo return default dir file info -func newDirFileInfo(name string) os.FileInfo { - return &bindataFileInfo{ - name: name, - size: 0, - mode: os.FileMode(2147484068), // equal os.FileMode(0644)|os.ModeDir - modTime: time.Time{}} -} - -// AssetFile return a http.FileSystem instance that data backend by asset -func AssetFile() http.FileSystem { - return &assetOperator{} -} - -var _app2App2app3CssMainCss = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\xca\x4f\xa9\x54\xa8\xe6\xe5\x52\x50\x50\x50\x48\x4a\x4c\xce\x4e\x2f\xca\x2f\xcd\x4b\xd1\x4d\xce\xcf\xc9\x2f\xb2\x52\x48\xca\x29\x4d\xb5\xe6\xe5\xaa\x05\x04\x00\x00\xff\xff\x52\xd7\xbb\x8b\x26\x00\x00\x00" - -func app2App2app3CssMainCssBytes() ([]byte, error) { - return bindataRead( - _app2App2app3CssMainCss, - "app2/app2app3/css/main.css", - ) -} - -func app2App2app3CssMainCss() (*asset, error) { - bytes, err := app2App2app3CssMainCssBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app2/app2app3/css/main.css", size: 38, mode: os.FileMode(438), modTime: time.Unix(1595043712, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _app2App2app3DirsDir1TextTxt = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\x2c\x28\x30\xd2\x07\x11\x89\x05\x05\xc6\xfa\x29\x99\x45\xc5\x20\xc2\x50\xbf\x24\xb5\xa2\x44\xaf\xa4\xa2\x04\x10\x00\x00\xff\xff\x87\xaf\x9d\x00\x20\x00\x00\x00" - -func app2App2app3DirsDir1TextTxtBytes() ([]byte, error) { - return bindataRead( - _app2App2app3DirsDir1TextTxt, - "app2/app2app3/dirs/dir1/text.txt", - ) -} - -func app2App2app3DirsDir1TextTxt() (*asset, error) { - bytes, err := app2App2app3DirsDir1TextTxtBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app2/app2app3/dirs/dir1/text.txt", size: 32, mode: os.FileMode(438), modTime: time.Unix(1594843207, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _app2App2app3DirsDir2TextTxt = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\x2c\x28\x30\xd2\x07\x11\x89\x05\x05\xc6\xfa\x29\x99\x45\xc5\x20\xc2\x48\xbf\x24\xb5\xa2\x44\xaf\xa4\xa2\x04\x10\x00\x00\xff\xff\x84\x14\xaa\xeb\x20\x00\x00\x00" - -func app2App2app3DirsDir2TextTxtBytes() ([]byte, error) { - return bindataRead( - _app2App2app3DirsDir2TextTxt, - "app2/app2app3/dirs/dir2/text.txt", - ) -} - -func app2App2app3DirsDir2TextTxt() (*asset, error) { - bytes, err := app2App2app3DirsDir2TextTxtBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app2/app2app3/dirs/dir2/text.txt", size: 32, mode: os.FileMode(438), modTime: time.Unix(1594843207, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _app2App2app3DirsTextTxt = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\x2c\x28\x30\xd2\x07\x11\x89\x05\x05\xc6\xfa\x29\x99\x45\xc5\xfa\x25\xa9\x15\x25\x7a\x25\x15\x25\x80\x00\x00\x00\xff\xff\x64\xfe\x96\xd6\x1b\x00\x00\x00" - -func app2App2app3DirsTextTxtBytes() ([]byte, error) { - return bindataRead( - _app2App2app3DirsTextTxt, - "app2/app2app3/dirs/text.txt", - ) -} - -func app2App2app3DirsTextTxt() (*asset, error) { - bytes, err := app2App2app3DirsTextTxtBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app2/app2app3/dirs/text.txt", size: 27, mode: os.FileMode(438), modTime: time.Unix(1594843207, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _app2App2app3IndexHtml = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x90\x3f\x4f\xc3\x40\x0c\xc5\xf7\x48\xf9\x0e\xc6\x33\xed\x91\x76\x61\xb8\x8b\x54\xf1\x47\x6c\x30\x94\x81\xf1\x7a\x31\x9c\x85\x73\x39\xe5\x4c\x4b\xbf\x3d\x4a\x68\x90\x58\x6c\x3d\xfb\xbd\x9f\x64\xdb\xab\xfb\xe7\xbb\xfd\xdb\xcb\x03\x44\xed\xa5\xad\x2b\x3b\x75\x10\x9f\x3e\x1c\x52\xc2\xb6\xae\xa6\x19\xf9\xae\xad\x2b\x00\x00\xdb\x93\x7a\x08\xd1\x8f\x85\xd4\xe1\xeb\xfe\x71\x75\x8b\xff\x76\xc9\xf7\xe4\xf0\xc8\x74\xca\xc3\xa8\x08\x61\x48\x4a\x49\x1d\x9e\xb8\xd3\xe8\x3a\x3a\x72\xa0\xd5\x2c\xae\x81\x13\x2b\x7b\x59\x95\xe0\x85\x5c\xb3\xbe\xf9\x63\x09\xa7\x4f\x18\x49\x1c\x16\x3d\x0b\x95\x48\xa4\x08\x71\xa4\x77\x87\x26\x7f\x1d\x84\x83\xf1\x39\x6f\xe6\xe2\x73\xde\x9a\x50\x8a\xe9\x3d\xa7\x75\x28\x05\xc1\x2c\x20\x65\x15\x6a\x77\x39\x6f\x76\x39\x6f\xad\xf9\xd5\x75\x65\xcd\xe5\xac\xba\xb2\x87\xa1\x3b\x2f\xfe\xd8\xb4\x4f\x24\x32\xc0\x12\x01\x4e\x1d\x7d\x5b\x13\x9b\x39\x75\xf1\xce\x80\xe9\x67\x3f\x01\x00\x00\xff\xff\xef\x25\x54\xc8\x43\x01\x00\x00" - -func app2App2app3IndexHtmlBytes() ([]byte, error) { - return bindataRead( - _app2App2app3IndexHtml, - "app2/app2app3/index.html", - ) -} - -func app2App2app3IndexHtml() (*asset, error) { - bytes, err := app2App2app3IndexHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app2/app2app3/index.html", size: 323, mode: os.FileMode(438), modTime: time.Unix(1595043725, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _app2IndexHtml = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb2\xc9\x30\xb4\xf3\x48\xcd\xc9\xc9\x57\x70\x2c\x28\x30\x52\xc8\xcc\x4b\x49\xad\xb0\xd1\xcf\x30\xb4\x03\x04\x00\x00\xff\xff\x75\x17\xab\xfa\x19\x00\x00\x00" - -func app2IndexHtmlBytes() ([]byte, error) { - return bindataRead( - _app2IndexHtml, - "app2/index.html", - ) -} - -func app2IndexHtml() (*asset, error) { - bytes, err := app2IndexHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app2/index.html", size: 25, mode: os.FileMode(438), modTime: time.Unix(1565946440, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _app2MydirTextTxt = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xca\x2a\x2d\x2e\x51\x48\x54\x28\x49\xad\x28\xd1\x03\x04\x00\x00\xff\xff\x2f\xf9\x22\x98\x0c\x00\x00\x00" - -func app2MydirTextTxtBytes() ([]byte, error) { - return bindataRead( - _app2MydirTextTxt, - "app2/mydir/text.txt", - ) -} - -func app2MydirTextTxt() (*asset, error) { - bytes, err := app2MydirTextTxtBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app2/mydir/text.txt", size: 12, mode: os.FileMode(438), modTime: time.Unix(1594787248, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _cssMainCss = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\xca\x4f\xa9\x54\xa8\xe6\xe5\x52\x50\x50\x50\x48\x4a\x4c\xce\x4e\x2f\xca\x2f\xcd\x4b\xd1\x4d\xce\xcf\xc9\x2f\xb2\x52\x48\xca\x49\x4c\xce\xb6\xe6\xe5\xaa\xe5\xe5\x02\x04\x00\x00\xff\xff\x03\x25\x9c\x89\x29\x00\x00\x00" - -func cssMainCssBytes() ([]byte, error) { - return bindataRead( - _cssMainCss, - "css/main.css", - ) -} - -func cssMainCss() (*asset, error) { - bytes, err := cssMainCssBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "css/main.css", size: 41, mode: os.FileMode(438), modTime: time.Unix(1565946440, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _faviconIco = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\x0b\x70\x55\xc7\x79\xde\x7b\xce\x45\x12\xb2\x90\xc4\xc3\xe6\x61\x3b\x90\xf8\x31\xc4\x19\x6c\x32\xe3\xc4\x34\xe3\xc6\x34\x6d\xed\xd4\x69\x62\x32\x49\x9a\xa6\x75\xea\x36\x33\xee\xd8\x9e\xb4\x75\xdc\x7a\xa6\xc5\x31\x02\xa6\xd3\x84\x47\x28\x6f\x3b\xc6\x3c\xcc\xeb\x9e\xbd\x08\x21\x04\x92\x28\x12\x0e\x08\x5b\x3c\xec\x02\x92\x78\x08\x21\x09\x41\x25\x24\x10\xe8\x71\xb5\xe7\xdc\xd7\xb9\xf7\xef\xfc\xff\x9e\x73\x74\x25\xdd\x97\x24\x82\x33\x1e\xce\xcc\x3f\x7b\xee\x9e\xdd\xff\xff\xf6\xdf\x7f\xff\xfd\xf7\xdf\xcb\x98\x8b\xa9\x2c\x3f\x1f\xcb\x19\xec\x15\x37\x63\x5f\x67\x8c\xcd\x98\x21\x7f\x6b\xf9\x8c\x6d\x72\x33\x36\x7b\xb6\xf5\xfb\x11\xc6\x9e\xbd\x97\xb1\x99\x8c\xb1\x7c\x6c\xc7\x64\x3d\x3d\x6e\x76\xdb\x1f\xe1\x75\xab\x42\x53\x7e\x22\x3c\x6c\x91\xf0\xb0\x02\x22\xae\x14\x08\x8f\xab\x40\xec\x64\x92\xf0\x5d\x53\xfe\x59\xec\x64\x5f\x15\x1e\xa6\x08\x4f\x7f\x7f\xdf\x7a\x96\xa1\x97\x3c\xb8\x3f\x78\xfa\x0d\x08\x9e\x5d\x08\xc1\xda\x5f\x82\x51\xf6\x65\x30\xca\x67\x41\xf0\xcc\xbf\x11\x19\x07\x1e\x07\xbd\x78\x2a\x18\x65\x8f\xb5\x0b\x4d\x7d\xad\x6f\x07\x73\x0b\xcd\x45\xfd\xbb\x17\xb3\x0c\xa3\x62\xce\xfe\xa8\xd1\x0a\xf8\x98\x6d\x25\x10\x38\xfe\x53\x88\xdc\x3a\x01\x66\x6b\x11\x11\xbe\x07\x8e\xfd\x2d\x84\x2e\x2c\x05\xff\xd1\x79\x3d\xc2\xc3\x7e\x20\x78\x06\x13\x5c\x89\xe9\xdf\x06\xd1\x50\x2f\x04\x4e\xfc\x0c\xcc\x6b\xa5\x60\x1c\xfd\x21\x74\x6c\x1e\x47\x84\xef\x58\x17\xf8\xe4\x65\x30\x6f\x54\x81\x71\xe0\x89\xea\xbe\x2d\x6c\xd2\x80\xfe\xfe\x76\x30\x6f\x1c\x81\x60\xed\x7c\x08\x9e\x5d\x0c\x2d\xeb\xc7\x41\xed\xd2\x29\x50\xbb\x74\x32\xbd\x63\x1d\x7e\xc3\x36\xa1\x73\xff\x19\x14\x1e\x36\x4f\x78\xc7\xc4\xf4\xef\x80\x70\xd3\xfb\x10\x6e\x5c\x0f\xdd\x65\x73\xe1\xdc\xf2\x89\xd0\xb1\x25\x0f\x6e\x7c\x90\x07\xe7\x7f\x33\x81\xea\xf0\x5b\xb8\x79\x13\x61\xd0\x8b\xa7\x2c\x09\x7c\xfc\x57\xac\x7b\x11\xf6\x7f\x6a\x5f\xd4\xb8\x06\xa1\xfa\x15\x10\x6e\x7a\x0f\x3a\xb4\xc7\xa0\x61\x55\x3e\x04\x8f\xfc\x39\x84\x3e\xfa\x4b\x68\x5c\x93\x4f\x75\xf8\x2d\x74\x71\x05\x44\x45\x13\xea\x54\xeb\x7c\x85\xa9\x48\xf8\x1e\x15\xcd\xf4\xcd\xee\x7f\x71\x65\x3e\x04\x3e\x7c\x86\x78\x5c\x5a\x1d\xd3\xbf\x7e\x05\xa0\x2c\x94\x89\xb2\x03\xd5\x3f\x66\x88\x05\x31\x21\x36\x1b\xff\xd9\xe5\x13\xe1\xda\xc6\x5c\x68\xdf\x94\x4b\x63\x71\xf0\x37\xbd\x0f\x38\x56\x1c\x33\x8e\x1d\x75\x80\xba\x40\x9d\x0c\xd6\x5f\xcd\x92\x29\x44\x83\xf5\x87\xba\x76\xfa\x73\x85\xe1\x5c\x18\x07\x9e\x38\x86\x18\x68\x8e\xac\xf9\xbb\xbe\x39\x87\xc8\x99\xbf\x13\x3f\xa3\x39\xc6\xb9\x8e\xed\x4f\xb6\xe0\x61\x3f\x40\xdb\x40\x1b\x41\x5b\x19\x62\x3f\xc7\x7f\x4a\xb6\x85\x0f\xda\x9a\xdd\x9f\xd6\x80\xe6\x62\xd2\x26\xd5\xd7\xd0\x46\xc9\x56\x0f\x3c\xde\x6f\xbf\xe5\xb3\xc8\xa6\xd1\xb6\xc9\xc6\x4f\xbf\x01\x68\xf3\x68\xfb\xce\x3a\xf2\x30\x26\x76\x32\x85\xd6\x08\xae\x95\xc1\xeb\x87\xd6\x14\xb3\x69\x11\xad\x39\xaf\x5b\x1d\xed\xfa\x05\x60\x8c\x65\x32\xc6\x54\x8b\x5c\x31\x64\x3d\x0b\x63\xe8\xb0\x45\x2d\x56\xdf\x99\x96\x8f\x99\x1b\xeb\x67\xf2\x47\x8b\xea\xf3\xf9\x08\xae\x22\xe5\x09\xae\x4e\x17\x5c\xfd\xc2\x28\x69\x8a\xe0\xca\x58\xb4\x3d\xdb\x17\xa6\x29\xff\x5f\x04\x57\x5b\x85\xe6\xba\x92\x90\xb8\x1a\x43\x4a\x4c\xbd\x62\xd7\xb7\x08\xae\xd6\x0b\xae\xfe\x8f\xe0\xea\x9b\x38\x1e\x1f\x1f\x4b\xfe\x34\xb5\x7c\xa5\x40\xec\xca\x02\xbd\x64\x3a\xe8\xfb\xbe\x38\x94\x4a\xa6\x83\xf0\x66\x82\xd0\x14\x10\x9a\x0b\x44\xe1\x38\x5c\x2b\x44\xf8\x4e\x75\x5c\x01\xe1\x75\x03\xf2\x11\x9a\x2b\x2a\xb8\x52\x2b\xb8\x3a\x4f\x68\x8a\x92\x0c\x03\xc9\xf7\xb0\x02\xa3\xfc\x2b\x10\xe9\xae\x85\xa8\x7e\x15\xa2\xfa\x95\x18\xba\x0a\xa1\xb3\x8b\x49\xbe\xbe\xe7\x5e\x08\xfe\xef\x3f\x81\xd9\x51\x09\x91\xbe\x4b\x44\xf8\x8e\x75\xf8\x4d\x70\x37\x04\x3e\xfe\x11\xf9\x14\xbd\x68\x3c\xe2\xe8\x14\x5c\x7d\x49\x78\x99\x2b\x11\x06\x47\xfe\x81\xd9\x10\x0d\xde\x82\xc1\x8f\x79\xe3\x30\xe8\x7b\xa7\x81\x51\xfa\x28\x98\xd7\xca\x00\xa2\xa6\xfc\x80\x65\xcc\x3b\x7e\xc3\x36\xfa\xde\x07\x08\x93\xd9\x5a\x0c\xfa\xfe\x87\x41\x68\xac\x43\x70\xf5\x59\x92\xe3\x1d\xea\x1a\x92\xc9\x8f\x06\x3a\xc1\xff\xe1\x5c\xda\x67\x91\x27\x3e\x91\xde\x0b\xe4\xaf\xfc\x47\x5f\x20\xc2\x77\xac\x23\xac\x1d\x95\xd4\xd6\xff\xe1\x9f\x10\x2f\xfa\x5d\xf2\x05\xc4\x70\x4c\x70\xf5\x7e\x94\x35\x1c\xf9\xa1\xc6\x77\x68\x3e\x43\x17\x57\x4a\xfe\xe8\xc3\xcb\xbe\x8c\xfc\xa0\xcf\x23\x09\xdf\xb1\x0e\xbf\x51\x9f\x8b\x2b\x65\x9f\xc6\x77\xe8\x37\xee\x4f\x62\xd7\x58\xb4\x8f\x05\x3e\x9e\x35\xc4\x1e\x13\xc9\x8f\x06\xbb\xc0\xa8\xfc\x23\xf0\x1f\xfa\x63\x88\x86\xba\x21\x72\xeb\x24\x18\xfb\x1f\x82\xde\x1d\x2e\x68\xdd\x30\x0e\x1a\x56\x4f\x24\xc2\x77\xac\xc3\x6f\xd8\x06\xdb\x62\x1f\xec\x8b\xef\x10\xd6\xc1\xff\xd1\xf7\x11\x67\x83\xe0\xea\x97\x06\xeb\x20\x91\x7c\xd2\xdd\xee\x3c\x08\x37\x6f\x04\x30\x0d\x08\x7c\x34\x8f\xe4\x34\xae\x99\x00\xa7\x7f\x3d\x0d\x4e\xfd\xea\x7e\x22\x7c\xc7\x3a\xfc\x86\x6d\xb0\x6d\xb8\x69\x23\xf5\xb5\xe7\xcc\x6c\x3f\x00\x62\x77\x6e\x54\x68\xae\x57\xad\xf5\x96\x52\x7e\xb0\x6e\x01\xe8\xfb\x66\xd0\x1a\x30\xaf\x95\x83\x28\xcc\x81\x2b\xef\xe6\x92\x3c\x24\x8a\x63\x96\x4d\x71\x7e\xe3\x37\x6c\x83\x6d\xb1\x0f\xf6\x0d\xd6\x15\x48\x5d\x86\x7c\x64\x47\xc2\xc3\xf6\x0a\xae\x66\xc6\xea\x20\xae\xfc\x48\x08\xfc\x55\xdf\x05\x7f\xd5\x77\x00\x22\x41\x08\x7e\xfa\x2a\x74\x6d\x53\xa1\x6e\xf9\x64\x92\x75\x69\xcd\x44\xb8\xb9\x35\x13\x6e\x6d\xcb\x80\xe6\x75\xe3\xa9\x0e\xbf\x61\x1b\x6c\x8b\x7d\xb0\xaf\xbf\xea\x7b\xc4\x8b\xec\xe2\xec\x22\x9c\x83\x66\xc1\xd5\x19\xa9\xe4\xd3\xdc\x1f\x98\x0d\xc1\x33\x6f\x42\x34\xec\x03\x7f\xe5\x1c\x68\xdb\x30\x96\xe4\x9c\xfb\xcd\x7d\xd0\xbd\x63\x0c\xe8\x85\x63\x41\x2f\xbc\x07\x7a\x3d\x6e\xa8\x5f\x39\x89\xbe\x61\x1b\x6c\x8b\x7d\xb0\xaf\xe4\xd9\x65\xd9\x6e\x19\x88\x5d\xd9\xba\xd0\x5c\x73\x53\xca\xd7\xff\x0f\xf4\xfd\x0f\x41\xa8\x61\x35\xf9\x1f\x7d\xdf\x74\x68\x5e\x97\x47\xf3\xdd\xf2\x4e\x1e\xc9\x0d\x9f\xfc\x3b\x30\x4f\xbd\x02\xc6\x9e\x09\xd0\xba\x21\x07\x4e\xfd\x6a\x1a\xb5\xc1\xb6\xe4\xb3\x1a\x56\x13\x0f\xe4\x25\xd7\xed\x39\x5c\x9b\x51\xa1\xb1\x17\xe3\xc8\x7f\x0b\x63\x13\x5c\xef\xd4\xb6\xaf\x91\x7c\x6b\xf8\xf2\x16\x5a\xdb\x62\xcf\x64\xb8\xb4\x7a\x3c\xc9\x68\xdb\x90\x0d\xfe\xb2\x87\x01\x2e\x2d\x07\x68\x5a\x05\x81\xca\x27\xe1\xfa\xe6\x4c\x39\x2f\xab\xc7\x53\xdb\x88\xaf\x9e\xfa\x22\x0f\xe4\xe5\xc4\x47\xa5\x8f\xa2\x0d\xfc\x22\x8e\xfc\x5f\xe0\x37\x3b\x5e\x4f\x2e\xff\x1e\xf0\x97\x7e\x11\xa2\x0d\x4b\x00\x9a\x56\x42\xe0\xe0\x13\x70\x7d\x53\x56\x6a\xf9\x81\x4e\x8a\xbf\x70\xac\x43\xe4\x6b\xec\x45\xd4\x0d\xea\x28\xbe\xfe\x67\x38\xfa\x6f\x5e\x97\x2f\xfd\xcb\xd1\xe7\x21\x74\xec\x87\xa0\xef\xce\x81\xab\xbf\x1d\x67\x7d\xcb\xb3\xd6\xcc\x50\xfd\xe3\xdc\xe2\x1c\xcb\xb3\xd0\x60\xf9\xae\xb9\x68\x1b\xe4\xdf\x53\xd8\x1f\xda\x39\xda\xbe\xee\x55\x41\xf7\xba\xc9\x16\xcf\xaf\xb8\x2f\xa5\xfd\x25\x95\x8f\x6b\x42\x63\xcd\xb8\xcf\x25\x5c\x7f\x5b\xe5\xfa\xc3\x39\xb8\xf0\xdf\xf7\x42\xfb\xc6\x7b\xa0\x63\x53\x36\x5c\x5c\x35\x29\xad\xf5\x97\x42\x7e\x26\xfa\x06\xda\x37\xc2\xbe\xb4\xfc\x0f\xd2\x99\x25\xd3\xd2\xf2\x3f\xc9\xe5\x2b\xf6\x1c\xbc\x86\x3e\x12\x7d\xe5\x50\xff\xeb\x8f\xe3\x7f\x25\x0d\xf5\xbf\xfe\x21\xfe\x37\x99\xfc\x18\x1d\x7c\x09\xf7\x08\xdc\x2b\xc0\xd4\x69\xef\x30\x2a\x46\xb9\xff\x58\x73\x9f\x5a\xbe\xc2\x7c\x1a\xed\x8d\x0b\x70\xaf\xc4\x3d\x53\xee\xbf\xef\x8e\x7a\xff\x4d\x47\x7e\x8c\x0e\xee\xc7\x58\x01\x63\x06\xd4\x1d\xf6\x41\x9b\x18\x51\xfc\x61\xf9\xb2\xb4\xe5\x7b\x55\x1b\xc3\xb3\x18\x33\x61\xec\x84\x31\x14\xf1\xdc\xfb\x40\x5a\xf1\x97\x4e\xf1\xd7\x34\x8a\xd9\x06\x3f\xa9\xe4\x3b\xb6\x48\xb1\xa2\xfa\x12\xc6\x8e\x18\x43\x62\x2c\x89\x31\x25\xc6\x96\x29\xe3\x4f\x6f\x26\xc5\xaa\xf1\x62\x58\x8c\x6d\x31\xc6\x4d\x26\xbf\x7f\x3d\x60\xcc\xac\xce\xa3\x18\x1a\x63\x69\x8c\xa9\xb9\x5b\xc6\xd8\x14\x7f\xe7\xc4\xc4\xdf\x39\xb2\x0e\x63\x73\x8c\x91\x93\xc5\xf0\xc4\x47\x49\x2a\x9f\x30\x68\x0a\xf3\x15\x65\x31\x6b\xaf\x7e\xd3\x3a\x53\xd4\x5b\x67\x8c\x44\xe7\x0f\x49\xc9\xcf\x30\xad\xd6\x59\x27\xa9\xfc\x58\x5d\xf4\x69\x14\x2f\x8d\x95\x67\xab\x51\x9f\xcf\xa6\x5b\x67\xbd\xb4\xe4\x7f\xde\x1f\x7b\x6d\x1c\x66\x2a\x1c\x66\x0c\xe9\x99\xc3\x8c\x4d\xb7\x28\xcf\xa2\x4c\x8b\xd4\x74\xa8\xc5\xa2\x1e\x8b\x02\x16\x99\x8c\xa9\xc0\x48\x90\x6a\xcb\x9d\xc9\x18\x9b\xcd\x18\xfb\xfb\xd8\x3c\xc5\xc3\x9f\xb5\x56\xee\x3e\x77\x9f\x3f\xcc\xc7\xda\x1f\x1f\x16\x5c\x7d\x5b\x70\x75\xa1\xe0\x6a\xc1\xef\x89\x6c\xde\xff\x2a\xb8\xfa\x37\x82\x2b\xb3\x05\x57\x72\x7a\x35\xc6\x0c\x2d\x79\x3e\x29\x0d\xfc\xdf\x16\x5c\x0d\x0a\xae\xc2\x1d\x22\x53\x70\xb5\x53\x70\xf5\x20\xed\xeb\x5c\xc9\xc7\x58\xc3\x48\x33\x3f\x97\x18\xbf\x42\xb1\x57\x5a\x84\x6d\x07\x60\x4a\xd2\x37\x6e\x5b\x97\xfd\x1b\xf5\x56\x2a\xb8\xfa\x24\xec\x67\x4c\xe7\xc3\x1b\x83\x83\x5f\x73\x05\x31\xc6\x0b\xd6\xbe\x45\xe7\xf2\x64\x14\x3c\xbb\x08\x8c\x8a\xa7\xfa\x71\x21\xc6\xc2\x1c\x30\x0e\x7e\x0d\x02\x27\xfe\x81\x78\x20\xe1\x3b\xd6\xc9\x78\x84\x39\xd8\xf5\xe2\x29\x60\x94\xcd\x04\xe1\xcd\x8a\x1d\x47\xa3\xe0\xea\x0b\x7e\xce\x5c\x7a\x8a\xfc\x64\x7c\xfc\x2c\x48\xf1\x75\xb8\x6f\x48\x9c\x37\xf8\x31\xdb\x4a\x64\x9c\x84\xb2\xbd\x19\xe0\x3f\xf2\x17\x60\xb6\xee\x85\x68\xe0\x26\x40\x34\x12\x13\x20\x46\xa8\x0e\xbf\x61\x1b\x6c\x8b\x7d\xf4\xe2\xc9\x10\x6a\x58\x0b\xe1\xcb\x5b\xc1\xa8\xfc\x46\xff\x9c\x70\xb5\x0d\xc7\xd0\xa3\x65\x33\x91\xe6\x3c\x0c\x17\x7f\xa4\xeb\x14\xc5\xb4\xc2\xc3\xe8\x3c\x43\xb1\x65\xb0\x3b\xe5\x98\xb1\x0d\xb6\xc5\x3e\xf2\x7c\x30\x13\x22\xdd\x35\x10\xf5\x5f\xa7\x73\xa9\x28\xbc\xc7\x1e\x43\x93\xe0\xca\x53\x14\x73\x16\xa6\x8e\x89\x86\x83\x9f\xce\x41\x55\xdf\x23\xec\x62\x77\x2e\x9d\xc7\xed\xb3\xa8\x1c\x5c\x10\xa2\xa2\x05\x22\xb7\x3e\x21\xc2\x77\xac\xeb\xff\x1e\xa2\x3e\xd8\x17\x79\x20\xaf\x68\xa8\x87\xda\x84\xea\x97\xcb\xbc\xb3\x1c\x43\xa5\xe0\xea\xe4\x74\x62\xba\xe1\xe0\x0f\x35\xac\x91\x36\xc0\xdd\x10\xac\x7b\xbb\x1f\x7b\x34\x0c\x66\x47\x05\xdd\x3d\xe9\xa5\x8f\x80\x5e\x34\x51\x52\xe9\x23\xf2\x3e\xaa\xa3\x82\xda\xd8\x63\x08\xd6\xfe\x52\xc6\xee\xde\x0c\xe2\x69\x8f\x1d\xcf\x4d\x92\xbf\x1a\x45\x7f\xeb\xf3\x32\x57\x5f\x0a\x3b\x4a\x17\x3f\xea\xd2\x28\x9f\x25\xf5\x76\xe4\x3b\xfd\x79\xad\x70\x1f\x84\xce\xff\x17\xe8\x7b\x26\x59\xfe\xc6\xca\xdb\xdb\x3e\x46\x63\xf4\x0d\xdb\xd8\xbc\xe9\x0c\x78\xe4\x79\xe2\x85\x3c\x69\x9e\x68\x7e\x7b\x21\x50\xfd\x63\x7b\x4d\x5f\x13\x5c\xfd\x7a\xca\x73\x45\x9a\xf8\x69\x7e\xad\xb5\x67\xde\xa8\xea\xd7\x59\xdd\x02\x79\x0f\xc1\xa5\x1f\xe9\xd9\x39\x06\x6e\x6e\xcd\x22\xc2\x77\xb9\x36\x5d\xd4\x06\xdb\xda\xf6\x64\xde\x38\x42\xbc\x90\x27\xf2\x76\x4c\xac\xbb\x86\x72\x44\xd6\x18\xde\xd3\xb9\xcb\x9d\xcc\x1f\xa5\x83\x9f\xf2\x5c\x15\x73\x48\x5f\x81\x4f\x5f\x75\xce\xa8\xe1\xcb\x5b\x1c\x9b\x45\xac\x57\xde\xcd\xa3\x5c\x66\xcd\xd2\x29\x44\xf8\x8e\x75\x72\x1c\x0a\xb5\xc5\x3e\x92\xa9\x49\xbc\x68\x0e\x2a\xe6\x0c\x38\x5b\x87\x2e\x2c\xb1\xce\x86\x6a\xbb\xe0\xea\x57\x93\x9f\x2d\x53\xe3\xa7\x5c\xcf\xae\x6c\xb2\x03\xb3\xb3\x5a\xea\xa9\xaf\x51\x9e\x5d\x35\x06\xdd\xdb\x33\x9c\x9c\x53\x3c\xc2\x6f\xd8\x86\xfc\x4e\xf9\x57\x9c\xfc\x9f\xd9\xf9\xb1\xb4\xbb\xc2\x6c\x30\xdb\xcb\xfb\xf5\xa5\x5f\x95\x79\x41\xb9\x67\x2c\x12\xdc\x9d\xf0\xce\x2a\x1d\xfc\xe4\xdf\xc8\x5f\x7c\x97\x72\xf1\x54\x57\xf3\xef\x64\x17\xbd\x1e\x37\xe5\x6c\x12\x61\xb7\x09\xdb\x60\x5b\xec\x83\x7d\xe5\x00\x0c\xe2\x89\xbc\x51\xc6\x00\x99\x75\x0b\x6d\x1b\x3a\x2e\xb8\x32\x61\xa4\xf8\xf1\x37\xe5\xe9\x35\x06\xa1\x86\x55\x96\x7e\x5a\xc0\x28\x9d\x49\x75\xad\xef\x8d\x1b\x82\xb5\x76\xd9\xc0\x7b\x00\x9b\xb0\xad\xed\xfb\xa3\xfa\x15\x69\x2b\x17\x57\x51\x1d\xca\x88\x95\x8d\xfe\x57\xde\x9f\x29\x3e\xc1\xd5\x6f\x26\xce\x8f\x24\xc7\x1f\xf1\x35\x80\x5e\xf2\x00\xe8\xbb\xf3\x21\x72\xf3\x98\x65\xf7\x1f\x80\xf0\x8e\x81\x9e\x1d\x63\xc8\xc6\x6d\x7c\x35\x4b\xa7\x92\xbd\xdf\xda\x96\x09\x5d\xdb\x33\xa1\x6d\x43\x8e\x73\xbf\x60\xe7\xf9\xb1\x0f\xfa\x48\xdc\x7b\x89\xff\xcd\x6a\xe2\x4d\x79\x65\x5f\xc3\x40\xbd\xfd\xee\x5b\xb6\x0d\x51\x7e\x3b\xde\x3a\x4e\x85\xdf\xec\x38\x44\xb6\x6f\x94\x3d\x46\xff\x67\xc0\x27\x70\xf2\x65\xe2\x7b\xed\xfd\x9c\x98\xbc\xe7\x54\xa9\x5f\x27\x16\x50\x40\xe7\x2a\x5c\xdf\x9c\x4d\xf7\x32\x76\x3b\xec\x83\x7d\x03\x9f\xfc\xa3\xc4\xe9\x6f\x27\xde\x28\x03\x65\x0d\xb0\xa1\x9a\xff\xb0\xf1\x6f\xd3\xb9\x2b\xee\x9d\x69\x2a\xfc\xa4\x6b\x9c\xdf\xc3\xcf\x01\x44\x02\x94\xcb\x35\x2a\x9f\xa6\xba\xa6\xb5\x13\x9c\x7c\x29\xae\x51\x9f\x47\xe6\x93\xf4\xc2\x6c\xd0\x77\x8f\x73\xe2\xcd\xcb\xeb\xf3\x9d\xfc\x2a\xf6\x21\x7e\x87\x9e\x96\x79\xe1\x48\x80\x78\x63\x1d\xca\x1a\x20\xfb\x2a\xb7\xf7\xb3\x6a\xc1\x95\xdc\x91\xe0\x0f\x5d\x58\x26\xfd\xe6\xf1\x97\xa4\xbe\xc4\x65\xca\x5d\xf5\xee\x54\x29\xe7\x6d\xeb\xb5\x0d\xf5\xca\x5d\x60\xec\x9d\x4a\x77\x30\x91\xda\x37\xc0\x5f\x3e\x93\xc6\xd3\xf9\xc1\x58\xb2\x2d\x3b\x4f\xee\xdb\xa9\x12\x0f\xe4\x45\xf3\x79\xfc\x25\x92\x81\xb2\x06\xd8\xee\xcd\x13\xf2\xce\x98\x2b\x4d\x82\xab\x0f\x26\xc9\x91\x3e\x97\x08\x3f\xed\x4f\x3b\x19\x04\x4f\xbd\x2e\x79\xf6\xd4\xd2\xbe\xd3\xbd\x7d\x0c\x9c\xb5\x6c\x1b\xb1\xe1\x7e\xa5\x7b\x55\x08\x1d\xfb\x11\x40\xf3\x5a\x22\xf3\xf4\xcf\x69\x2e\xd0\xff\xa3\xed\x23\x7e\xec\xd3\xbd\xdd\x4d\x31\x74\xa4\xa7\x4e\xca\x38\xf5\xba\x94\x81\xfb\x5b\xac\xef\x10\xcd\x74\xf7\x64\xdd\x79\xcf\x4a\x82\xff\x5b\x42\x63\x86\x71\xf0\xc9\x21\xb1\x24\xf9\x4e\xe4\x5d\x3b\xdf\xd2\xc9\x71\xd0\x8b\xf2\xa1\x6b\x5b\x86\xe3\x63\xb0\xec\xda\x9e\x41\xf7\x6f\x66\xcd\xeb\x00\xcd\x6b\x00\x9a\x56\x43\xb4\x7e\x31\x18\x7b\x27\x83\xcf\x23\xe7\x0a\xf1\x3b\x6d\x8b\xf2\xe9\xff\x3a\x24\xa3\x76\xbe\x94\x31\xc8\x87\x62\x6c\x4a\x31\x8b\xc6\xfa\x04\x57\x9f\x4e\x82\xff\x69\x6c\x43\xb1\x88\xff\xfa\xc8\xf0\x6f\xcb\x00\x7d\x57\x16\x98\x67\x7e\xde\x8f\xff\x42\x01\x18\xc5\x93\x08\xff\xf9\x91\xe0\x0f\x76\x03\xea\x14\x75\x4b\x3a\x4e\x8c\x7f\x16\xe5\x96\xf7\xcd\xa0\x39\x4b\x6e\x3f\x75\x34\xf7\x68\x03\xb6\xfd\xa0\xef\xb9\xb1\x85\xee\xd3\x21\x78\xe4\xcf\xe8\x0e\x10\xed\x27\x7c\xe2\x45\xd0\xbd\x19\xd0\xbd\x23\x83\xda\x0e\xdb\x7e\xc2\x7d\x74\x67\x81\xb6\x4d\x36\x9e\x18\xff\x83\xb8\x46\xf4\xa2\x09\x74\xdf\x31\x92\xf5\x7b\xf5\xb7\xb9\x96\xef\xc9\x81\x60\xd5\x73\x10\xaa\xfe\x3e\xe8\xc5\xf7\x82\xce\x15\xba\xd3\xc2\x31\x9e\xfa\xb5\xbd\x7e\x95\xb4\xd6\xef\x20\xfc\xdf\x8e\x8f\x9f\x72\xeb\xb9\xe4\xa3\x70\x5f\xb9\xca\x07\xf0\x48\xd7\x7f\x9e\x5b\x81\x7b\x53\x46\x7f\xec\x6c\x91\x4f\xeb\x8f\x2f\xb0\x6d\xe3\x30\xfc\x67\xba\xf8\xe5\xde\xa0\x6e\x47\x1e\xc1\x9a\xf9\x03\x78\xa4\xbb\x7f\x21\x35\xad\x1b\x0f\xbd\x9e\x31\xd6\x3d\xa6\x0a\x7d\x9a\x9b\xe6\x05\x75\x3f\x64\xff\x3a\xf9\xb2\xb5\x46\x13\xef\x5f\xe9\xe0\xd7\xed\xbb\x3e\xdc\xa3\x51\x2f\xbf\xfb\xd3\x81\x71\x48\xdc\xf8\x61\x6b\xdc\xf8\xc1\xde\xc7\x30\x6e\x40\x9c\xa8\xeb\x58\xec\xc3\x89\x1f\xd2\xc5\x1f\xb3\x06\xbe\x29\xb8\xd2\xa7\xef\xb9\x0f\x22\x5d\x9f\x0e\xe0\xe1\xc4\x6f\x17\xd3\x8b\xdf\x12\xd1\x70\xe2\xb7\xe1\xe1\xa7\x35\x30\x81\x62\x55\xcd\x45\xe7\xd0\xd8\xe7\xb3\x88\x9f\x87\x85\x5f\x53\x18\xfd\x3f\x95\xab\x8b\xe5\x19\xe3\x71\x3a\x43\x38\x6b\xe0\xf7\x76\x7e\xa9\x8e\x7b\x7e\x19\x2e\xfe\x18\x1b\xc2\xb3\x5a\x07\x9e\xdd\xf0\x0c\xe7\xf0\xb9\x23\xe7\xc7\x9b\xa3\xc4\x4f\x7e\xc8\x8d\x67\x66\x3a\xa7\xef\x7f\x88\xce\xd2\xf6\x93\xf6\xf9\x7d\x47\xcc\xf9\x7d\x47\xb2\xf3\x7b\x55\xdc\xf3\xfb\x48\xf1\xc7\xcc\xc1\xd7\x28\x77\x81\x3e\xae\xfa\xaf\x29\xa7\x01\x43\xf2\x27\xcf\x0f\xcc\x9f\x9c\xbb\x3d\xf9\x93\xd1\xe2\xef\xe3\x2e\xe6\xe3\x4c\x91\x67\x66\x35\x8a\x7e\x8e\xd6\xb2\xa5\xb3\xd4\xf9\xab\x17\xc1\x28\x7d\x04\xf4\x3d\x13\x89\x8c\x44\xf9\xab\xba\xb7\x87\xe6\xaf\x6e\x03\xfe\x98\x39\x98\x2c\xb8\x7a\xc8\xb6\xd9\x50\xfd\x32\x99\x1b\x0c\xf5\x38\xfe\xe2\xf6\xe5\x0f\x13\xe7\x4e\x47\x84\xbf\x50\xb5\xfd\xe9\x1c\x2b\x97\x4a\xb9\x55\xfa\xdf\x50\xe0\x3a\x44\xba\xcf\xc8\xdc\x37\xda\x8a\x9d\xbf\x4d\x82\xc1\xc1\x62\xe5\x6f\xb1\x0f\xe5\x7e\x4b\x1f\xa5\x5c\x70\xd2\x3e\x23\xc0\x4f\x63\xf0\xba\x58\x8f\x27\x1b\xe7\xe1\x05\x99\xd3\x56\x68\xbe\x8d\xca\x6f\xd0\xbe\x19\x6a\x58\xeb\xac\x3d\x27\x7f\xde\x56\x92\x7e\xfe\xbc\xe4\x41\x30\xdb\xf6\xa5\x1e\xf3\x08\xf1\xe3\xa3\x7b\x15\x66\xec\xa2\xff\x6d\xbc\x60\xdd\x2d\x48\xbc\xbb\xb2\xe8\xbf\x31\x7a\xf1\xd4\x24\xf7\x17\xf3\x89\x12\xdd\x5f\x18\x15\x4f\xd1\x1d\x48\xca\x7b\x92\xda\xb7\xac\xff\xda\xba\x86\x8d\x9f\xc6\xc0\x5d\x0c\xbc\xe4\x5b\xd1\x27\x95\x39\x77\x64\x8e\x8f\x19\xcd\xfd\xd1\xb0\xee\xa9\x46\x84\x1f\x1f\x43\x73\xd9\x6b\x7a\xbc\xbc\x6b\xa3\x3b\xb7\x4e\xeb\x0e\xee\x4e\xdd\xf7\x8d\x18\xbf\x33\x0e\x8f\xc2\x7a\x8b\x54\x8c\x35\x72\x04\x57\x67\x0b\xae\xfe\xc4\xba\x0b\x2d\xb8\x03\xf7\xae\x6f\x5b\x77\xbc\x23\xc6\x7f\xf7\xb9\xfb\x7c\x9e\x1e\xb9\x43\x24\x2e\x5b\x18\x63\xcf\x58\x65\x9e\x55\x66\x5a\xa5\x6b\x50\xc9\xec\xb2\xc0\x2a\x9f\x19\x54\x4e\x4f\x50\xe6\x25\x28\x33\x6f\x5f\xd9\x93\xa0\x0c\x24\x28\xcd\x41\x65\xd4\x2a\xc1\x2e\x17\x0e\x2a\x5b\xac\xb2\xc7\x2a\x4d\xab\x4c\xa1\xdf\xff\x0f\x00\x00\xff\xff\xc6\xb9\x24\x2f\xee\x3a\x00\x00" - -func faviconIcoBytes() ([]byte, error) { - return bindataRead( - _faviconIco, - "favicon.ico", - ) -} - -func faviconIco() (*asset, error) { - bytes, err := faviconIcoBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "favicon.ico", size: 15086, mode: os.FileMode(438), modTime: time.Unix(1565946440, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _indexHtml = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\x91\x3d\x4f\xc3\x30\x10\x86\xf7\x48\xf9\x0f\xd7\x9b\x40\x22\x35\x6c\x0c\x71\x96\x42\x57\x90\x28\x03\xa3\xeb\x5c\x9b\x6b\x1d\x27\xb2\x2f\x69\xfb\xef\x51\x3e\xca\xe7\x64\xdf\xeb\xbb\xc7\x8f\xec\x7c\xf1\xf4\xb2\xda\x7c\xbc\x3e\x43\x25\xb5\x2b\xd2\x24\x1f\x56\x70\xc6\xef\x35\x92\xc7\x22\x4d\x86\x8c\x4c\x59\xa4\x09\x00\x40\x5e\x93\x18\xb0\x95\x09\x91\x44\xe3\xfb\x66\x9d\x3d\xe2\xaf\x33\x6f\x6a\xd2\xd8\x33\x9d\xda\x26\x08\x82\x6d\xbc\x90\x17\x8d\x27\x2e\xa5\xd2\x25\xf5\x6c\x29\x1b\x8b\x3b\x60\xcf\xc2\xc6\x65\xd1\x1a\x47\xfa\x61\x79\xff\xc5\x72\xec\x8f\x10\xc8\x69\x64\xdb\x78\x84\x2a\xd0\x4e\xa3\x6a\xbb\xad\x63\xab\x76\xa6\x1f\xe2\x25\xdb\x06\x41\x2e\x2d\x69\xe4\xda\xec\x49\x9d\xb3\xa9\x5d\xfd\xe7\x44\xb9\x38\x8a\x15\x91\xfc\xa5\xd9\x18\x55\x6d\xd8\x2f\x6d\x8c\x3f\x46\x85\xc5\x51\xb1\x66\x47\xf0\x46\xa1\xa7\x90\xab\x29\x4a\x93\x5c\xcd\x6f\x92\x26\xf9\xb6\x29\x2f\xd7\x11\xf6\x6d\x27\xb3\xd0\xb6\x13\x19\x54\x1a\x6f\x1d\xdb\xa3\xc6\xc6\xaf\x86\xcd\xcd\x2d\x42\x6f\x5c\x47\x1a\xc7\x1a\x6a\x5a\x4c\xb7\xce\x90\x68\x03\xb7\x57\x8a\xd0\x59\xd4\xc1\xf4\x66\x4a\x11\x62\xb0\xdf\xe6\x87\x59\xfc\x10\xb1\xc8\xd5\xd4\x32\xea\xcd\x52\xa3\xe9\xf0\xb3\x9f\x01\x00\x00\xff\xff\x00\xcf\x96\xa8\xe9\x01\x00\x00" - -func indexHtmlBytes() ([]byte, error) { - return bindataRead( - _indexHtml, - "index.html", - ) -} - -func indexHtml() (*asset, error) { - bytes, err := indexHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "index.html", size: 489, mode: os.FileMode(438), modTime: time.Unix(1594886229, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _jsMainJs = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\xce\xcf\x2b\xce\xcf\x49\xd5\xcb\xc9\x4f\xd7\x50\x4a\xad\x48\xcc\x2d\xc8\x49\x55\xd2\xb4\xe6\xe5\xe2\xe5\x4a\x2b\xcd\x4b\x2e\xc9\xcc\xcf\x53\xc8\xcf\x73\xce\xc9\x4c\xce\xd6\xd0\x54\xa8\xe6\xe5\x52\x50\x50\x50\x28\xcf\xcc\x4b\xc9\x2f\xd7\x4b\xcc\x49\x2d\x2a\xd1\x50\x4a\x2a\x2d\x29\xc9\xcf\x53\x48\x06\xa9\x49\x4d\x01\x6b\xae\x05\x04\x00\x00\xff\xff\xa4\xb7\x99\x52\x57\x00\x00\x00" - -func jsMainJsBytes() ([]byte, error) { - return bindataRead( - _jsMainJs, - "js/main.js", - ) -} - -func jsMainJs() (*asset, error) { - bytes, err := jsMainJsBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "js/main.js", size: 87, mode: os.FileMode(438), modTime: time.Unix(1594787764, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "app2/app2app3/css/main.css": app2App2app3CssMainCss, - "app2/app2app3/dirs/dir1/text.txt": app2App2app3DirsDir1TextTxt, - "app2/app2app3/dirs/dir2/text.txt": app2App2app3DirsDir2TextTxt, - "app2/app2app3/dirs/text.txt": app2App2app3DirsTextTxt, - "app2/app2app3/index.html": app2App2app3IndexHtml, - "app2/index.html": app2IndexHtml, - "app2/mydir/text.txt": app2MydirTextTxt, - "css/main.css": cssMainCss, - "favicon.ico": faviconIco, - "index.html": indexHtml, - "js/main.js": jsMainJs, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "app2": {nil, map[string]*bintree{ - "app2app3": {nil, map[string]*bintree{ - "css": {nil, map[string]*bintree{ - "main.css": {app2App2app3CssMainCss, map[string]*bintree{}}, - }}, - "dirs": {nil, map[string]*bintree{ - "dir1": {nil, map[string]*bintree{ - "text.txt": {app2App2app3DirsDir1TextTxt, map[string]*bintree{}}, - }}, - "dir2": {nil, map[string]*bintree{ - "text.txt": {app2App2app3DirsDir2TextTxt, map[string]*bintree{}}, - }}, - "text.txt": {app2App2app3DirsTextTxt, map[string]*bintree{}}, - }}, - "index.html": {app2App2app3IndexHtml, map[string]*bintree{}}, - }}, - "index.html": {app2IndexHtml, map[string]*bintree{}}, - "mydir": {nil, map[string]*bintree{ - "text.txt": {app2MydirTextTxt, map[string]*bintree{}}, - }}, - }}, - "css": {nil, map[string]*bintree{ - "main.css": {cssMainCss, map[string]*bintree{}}, - }}, - "favicon.ico": {faviconIco, map[string]*bintree{}}, - "index.html": {indexHtml, map[string]*bintree{}}, - "js": {nil, map[string]*bintree{ - "main.js": {jsMainJs, map[string]*bintree{}}, - }}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} diff --git a/_examples/file-server/http2push-embedded/main.go b/_examples/file-server/http2push-embedded/main.go deleted file mode 100644 index a29283f2..00000000 --- a/_examples/file-server/http2push-embedded/main.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import ( - "regexp" - - "github.com/kataras/iris/v12" -) - -// How to run: -// $ go get -u github.com/go-bindata/go-bindata/v3/go-bindata -// $ go-bindata -nomemcopy -fs -prefix "../http2push/assets" ../http2push/assets/... -// # OR if the ./assets directory was inside this example foder: -// # go-bindata -nomemcopy -refix "assets" ./assets/... -// -// $ go run . -// Physical files are not used, you can delete the "assets" folder and run the example. - -var opts = iris.DirOptions{ - IndexName: "index.html", - PushTargetsRegexp: map[string]*regexp.Regexp{ - "/": iris.MatchCommonAssets, - "/app2/app2app3": iris.MatchCommonAssets, - }, - Compress: false, - ShowList: true, -} - -func main() { - app := iris.New() - app.HandleDir("/public", AssetFile(), opts) - - // https://127.0.0.1/public - // https://127.0.0.1/public/app2 - // https://127.0.0.1/public/app2/app2app3 - // https://127.0.0.1/public/app2/app2app3/dirs - app.Run(iris.TLS(":443", "../http2push/mycert.crt", "../http2push/mykey.key")) -} diff --git a/_examples/file-server/http2push/assets/app2/app2app3/css/main.css b/_examples/file-server/http2push/assets/app2/app2app3/css/main.css deleted file mode 100644 index d60afbdf..00000000 --- a/_examples/file-server/http2push/assets/app2/app2app3/css/main.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - background-color: blue; -} \ No newline at end of file diff --git a/_examples/file-server/http2push/assets/app2/app2app3/dirs/dir1/text.txt b/_examples/file-server/http2push/assets/app2/app2app3/dirs/dir1/text.txt deleted file mode 100644 index fc7b9c64..00000000 --- a/_examples/file-server/http2push/assets/app2/app2app3/dirs/dir1/text.txt +++ /dev/null @@ -1 +0,0 @@ -app2/app2app3/dirs/dir1/text.txt \ No newline at end of file diff --git a/_examples/file-server/http2push/assets/app2/app2app3/dirs/dir2/text.txt b/_examples/file-server/http2push/assets/app2/app2app3/dirs/dir2/text.txt deleted file mode 100644 index 9fb3e047..00000000 --- a/_examples/file-server/http2push/assets/app2/app2app3/dirs/dir2/text.txt +++ /dev/null @@ -1 +0,0 @@ -app2/app2app3/dirs/dir2/text.txt \ No newline at end of file diff --git a/_examples/file-server/http2push/assets/app2/app2app3/dirs/text.txt b/_examples/file-server/http2push/assets/app2/app2app3/dirs/text.txt deleted file mode 100644 index eaad5124..00000000 --- a/_examples/file-server/http2push/assets/app2/app2app3/dirs/text.txt +++ /dev/null @@ -1 +0,0 @@ -app2/app2app3/dirs/text.txt \ No newline at end of file diff --git a/_examples/file-server/http2push/assets/app2/app2app3/index.html b/_examples/file-server/http2push/assets/app2/app2app3/index.html deleted file mode 100644 index ba5282d2..00000000 --- a/_examples/file-server/http2push/assets/app2/app2app3/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - App2App3 - - - -

Hello App2App3 index

- - - \ No newline at end of file diff --git a/_examples/file-server/http2push/assets/app2/index.html b/_examples/file-server/http2push/assets/app2/index.html deleted file mode 100644 index 8193d822..00000000 --- a/_examples/file-server/http2push/assets/app2/index.html +++ /dev/null @@ -1 +0,0 @@ -

Hello App2 index

\ No newline at end of file diff --git a/_examples/file-server/http2push/assets/app2/mydir/text.txt b/_examples/file-server/http2push/assets/app2/mydir/text.txt deleted file mode 100644 index f1cc1278..00000000 --- a/_examples/file-server/http2push/assets/app2/mydir/text.txt +++ /dev/null @@ -1 +0,0 @@ -just a text. \ No newline at end of file diff --git a/_examples/file-server/http2push/assets/css/main.css b/_examples/file-server/http2push/assets/css/main.css deleted file mode 100644 index 7db3df1d..00000000 --- a/_examples/file-server/http2push/assets/css/main.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - background-color: black; -} diff --git a/_examples/file-server/http2push/assets/favicon.ico b/_examples/file-server/http2push/assets/favicon.ico deleted file mode 100644 index c370da518ec542579b7cc0d5d30f4778b4a96318..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 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 - - - - - - - - File Server - - - - - - - - - \ No newline at end of file diff --git a/_examples/file-server/http2push/assets/js/main.js b/_examples/file-server/http2push/assets/js/main.js deleted file mode 100644 index f97190ca..00000000 --- a/_examples/file-server/http2push/assets/js/main.js +++ /dev/null @@ -1,5 +0,0 @@ -console.log("example"); - -function onClick() { - window.alert("button clicked"); -} \ No newline at end of file diff --git a/_examples/file-server/http2push/main.go b/_examples/file-server/http2push/main.go deleted file mode 100644 index 277c68f0..00000000 --- a/_examples/file-server/http2push/main.go +++ /dev/null @@ -1,52 +0,0 @@ -package main - -import ( - "regexp" - - "github.com/kataras/iris/v12" -) - -var opts = iris.DirOptions{ - IndexName: "index.html", - // Optionally register files (map's values) to be served - // when a specific path (map's key WITHOUT prefix) is requested - // is fired before client asks (HTTP/2 Push). - // E.g. "/" (which serves the `IndexName` if not empty). - // - // Note: Requires running server under TLS, - // that's why we use `iris.TLS` below. - // PushTargets: map[string][]string{ - // "/": { // Relative path without prefix. - // "favicon.ico", - // "js/main.js", - // "css/main.css", - // // ^ Relative to the index, if need absolute ones start with a slash ('/'). - // }, - // }, - // OR use regexp: - PushTargetsRegexp: map[string]*regexp.Regexp{ - // Match all js, css and ico files - // from all files (recursively). - // "/": regexp.MustCompile("((.*).js|(.*).css|(.*).ico)$"), - // OR: - "/": iris.MatchCommonAssets, - "/app2/app2app3": iris.MatchCommonAssets, - }, - Compress: true, - ShowList: true, -} - -func main() { - app := iris.New() - app.HandleDir("/public", iris.Dir("./assets"), opts) - - // Open your browser's Network tools, - // navigate to https://127.0.0.1/public. - // you should see `Initiator` tab: "Push / public". - // - // https://127.0.0.1/public - // https://127.0.0.1/public/app2 - // https://127.0.0.1/public/app2/app2app3 - // https://127.0.0.1/public/app2/app2app3/dirs - app.Run(iris.TLS(":443", "mycert.crt", "mykey.key")) -} diff --git a/_examples/file-server/http2push/mycert.crt b/_examples/file-server/http2push/mycert.crt deleted file mode 100644 index 9db93b09..00000000 --- a/_examples/file-server/http2push/mycert.crt +++ /dev/null @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIUfwMd9auWixp19UnXOmyxJ9Jkv7IwDQYJKoZIhvcNAQEL -BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM -GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA2MjUwOTUxNDdaFw0yMTA2 -MjUwOTUxNDdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw -HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQDlVGyGAQ9uyfNbwZyrtYOSjLpxf5NpNToh2OzU7gy2 -OexBji5lmWBQ3oYDG+FjAkbHORPzOMNpeMwje+IjGZBw8x6E+8WoGdSzbrEZ6pUV -wKJGKEuDlx6g6HEmtv3ZwgGe20gvPjjW+oCO888dwK/mbIHrHTq4nO3o0gAdAJwu -amn9BlHU5O4RW7BQ4tLF+j/fBCACWRG1NHXA0AT8eg544GyCdyteAH11oCDsHS8/ -DAPsM6t+tZrMCIt9+9dzPdVoOmQNaMMrcz8eJohddRTK6zHe9ixZTt/soayOF7OS -QQeekbr3HPYhD450zRVplLMHx7wnph/+O+Po6bqDnUzdnkqAAwwymQapHMuHXZKN -rhdfKau3rVo1GeXLIRgeWLUoxFSm4TYshrgt+0AidLRH+dCY7MS9Ngga/sAK3vID -gSF75mFgOhY+q7nvY9Ecao6TnoNNRY29hUat4y0VwSyysUy887vHr6lMK5CrAT/l -Ch8fuu20HUCoiLwMJvA6+wpivZkuiIvWY7bVGYsEYrrW+bCNN9wCGYTZEyX++os9 -v/38wdOqGUT00ewXkjIUFCWbrnxxSr98kF3w3wPf9K4Y40MNxeR90nyX4zjXGF1/ -91msUh+iivsz9mcN9DK83fgTyOsoVLX5cm/L2UBwMacsfjBbN4djOc5IuYMar/VN -GQIDAQABo1MwUTAdBgNVHQ4EFgQUtkf+yAvqgZC8f22iJny9hFEDolMwHwYDVR0j -BBgwFoAUtkf+yAvqgZC8f22iJny9hFEDolMwDwYDVR0TAQH/BAUwAwEB/zANBgkq -hkiG9w0BAQsFAAOCAgEAE2QasBVru618rxupyJgEHw6r4iv7sz1Afz3Q5qJ4oSA9 -xVsrVCjr3iHRFSw8Rf670E8Ffk/JjzS65mHw6zeZj/ANBKQWLjRlqzYXeetq5HzG -SIgaG7p1RFvvzz3+leFGzjinZ6sKbfB4OB72o2YN+fO8DsDxgGKll0W4KAazizSe -HY9Pgu437tWnwF16rFO3IL47n5HzYlRoGIPOpzFoNX5+fyn9GlnKEtONF2QBKTjY -rdjvqFRByDiC74d8z/Yx8IiDRn1mTcG90JLR9+c6M7fruha9Y/rJfw+4AhVh5ZDz -Bl9rGPjwEs5zwutYvVAJzs7AVcighYP1lHKoJ7DxBDQeyBsYlUNk2l6bmZgLgGUZ -+2OyWlqc/jD2GdDsIaZ4i7QqhTI/6aYZIf5zUkblKV1aMSaDulKxRv//OwW28Jax -9EEoV7VaFb3sOkB/tZGhusXeQVtdrhahT3KkZLNwmNXoXWKJ5LjeUlFWJyV6JbDe -y/PIWWCwWqyuFCSZS+Cg3RDgAzfSxkI8uVZ+IKKJS3UluDX45lxXtbRrvTQ+oDrA -6ga5c1Vz9C4kn1K5yW4d7QIvg6vPiy7gvl+//sz9oxUM3yswInDBY0HKLgT0Uq9b -YzLDh2RSaHsgHMPy2BKqR+q2N+lpg7inAWuJM1Huq6eHFqhiyQkzsfscBd1Dpm8= ------END CERTIFICATE----- diff --git a/_examples/file-server/http2push/mykey.key b/_examples/file-server/http2push/mykey.key deleted file mode 100644 index 39f7b3af..00000000 --- a/_examples/file-server/http2push/mykey.key +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -W2TzuSMYNDu876twbTVQJED3mwOAQ3J7 ------END PRIVATE KEY----- diff --git a/_examples/file-server/send-files/files/first.zip b/_examples/file-server/send-files/files/first.zip deleted file mode 100644 index c98f5ac8f564fa8b28df5f3efa10e5cb7e121ecb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2901 zcmZ`*cTm$=*Zw7x1TYvNAV>>UibN1mq!UU&q$`A84bn@1C>;VUMLH-VB8#E8geD+O zRC-;?0@5Tjg$+wb>Eau9zVEMh-gEAA&YUv$&fGh5?qgy=N6!qL3sb(l@!fPWs~TE( zj*GOM&jTFJ7w_QZ>*kB{^KnZwF~Y!@FQ50r^!2pOXkLZ}2`D4YdQ9Ra0RR;1uBBz7 zucd|b3-HCcdp)3)Gr}`e^*S{8x*Tlkh3`Y;6B1m@jJULQ_==Nss!e8?E0l6=j~NUv zXCf|P+Uge;dYmWPx~wcAmYVQWz~4W}EHH!p*E585=Oe!_X@mm-!WIzOI(V@Ob2!-E`GIP$eLwv3c1TWsAMi>~r6;gMn1U>r zt_vJG=>$vPVcxmD)2Mk#G~#RX`Y!KkOh-h4BscY|N{z-*kJ%>I$ZfH&l&y$o_*VyyX=@%ImErldnW{qw zsL?=vs;H>gSCf%}Sy@@-$~vL(9v*92zbp&sqJd}G+0NaAR#^LOEjaL0Lt;Em-n-Pl z=o_~{sFwgUGxMgzVO7}1{Kr?%)L#xm)-E@dm%eI29pEjE)d@;fZbO8_Jvu;uto-ZMQrzex5X2*#g`T)5}S5@FiRrY>{L^H#7gI{N~-IbE*~7!cEQym1i_R1Q*wfL%lDjPz)$Jn%>DfqU>BU7v zDDuzb>g}6?VyZMpV!6Sw%~!yA z;QF#R6yok~0LvHOFN^25EOP?OH0!p}H8=kdkLTa$?HvTapEviNPM+c_90C*DGAk+# zWfPc@Ggi4dvF%Ea?h9%R#i-b}1~9;2uxX32Hpg^cR)O}JS7eNb#~*ic;m=KzSh|?jLUPax-ra)Q8&zuqiwR5xuOmcms0x8-w$4wl!)8dehh{=QDwcD+o-{n z<-FBvAso_~(P8Le zI7fB-;Vv~*0t_ZO{lnVcp@o(o5co!(+@pT>`O?;(IL%n~U5ymXlb}7m2bJ#@D|MvJ z7IM4Us;?k|R~hb=j*?yJ}5 zCrG(GjMmF1`|D_X3J1KYsp(#I0E7MUQL^I1%u>A_j(&|*(S5vd>K|_UT|lov#?x*| z_a%$j2kF2b`61z0VFRcF;l+$x#5|u@`(ihcl$_kEO`BmTsSuDc$~N}5)j^%^x~t^y zV20qcZ+3Q3UytNM_o4@G$itU8xGxwetLX0o@nXb4nZq~@Y=7CyRO57yo0&U{kQBw; zHX$f{W@bkAK|nKq{=-K9x|$lc`uZ(8fI<$r)o*^RjzO`-}fXDaE;U@T}e!Iejst-mib3nDw zYn7`9lCrwDk@4A56<`hQJdv-|k4Sj?{ism;$xUKoqv8`DdE8X%lFThoGM7xdvhS8@ zSJ@?23~3I4OR@wKu5Rv26&1G)bw~YaE7aQU>PbXwwzj%U`CTloZs;82+Ff%Uh>1*0}VfzHsJnKmM<~T} z!Rg!H`MqzO1+6H&!4{ooJl?&J`uNE)cZb@wH?72h_QkcYO_cj4Q>FPeEbiam+3c4>RGzWnhWl#bBmA?Bq5IP_>~nD+(Iows)P@Awj7s8`Uxp15aQ_U7?DB|;3HRQ zJ=(^5QQjXJL?6Er{PC`#VK0v5(n5j36;V;7hzOm&zWy!MG~OoN%8Y@QGrAW+{o6=x z`%xO10rYi@v@6k$F(w8eusZO+_^s%9D@~C9+W%s^%>P#a0o*_jlklGq-wDwF`;jG~ Ve`6B^hI8% - - - {{ .Page.Title }} - - - -

Hello from index.html

- - - - - - \ No newline at end of file diff --git a/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/bindata.go b/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/bindata.go deleted file mode 100644 index 0fc5312b..00000000 --- a/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/bindata.go +++ /dev/null @@ -1,380 +0,0 @@ -// Code generated by go-bindata. (@generated) DO NOT EDIT. - -//Package main generated by go-bindata.// sources: -// public/app.js -// public/css/main.css -// public/index.html -package main - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(data []byte, name string) ([]byte, error) { - gz, err := gzip.NewReader(bytes.NewBuffer(data)) - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -// Name return file name -func (fi bindataFileInfo) Name() string { - return fi.name -} - -// Size return file size -func (fi bindataFileInfo) Size() int64 { - return fi.size -} - -// Mode return file mode -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} - -// ModTime return file modify time -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} - -// IsDir return file whether a directory -func (fi bindataFileInfo) IsDir() bool { - return fi.mode&os.ModeDir != 0 -} - -// Sys return file is sys mode -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -type assetFile struct { - *bytes.Reader - name string - childInfos []os.FileInfo - childInfoOffset int -} - -type assetOperator struct{} - -// Open implement http.FileSystem interface -func (f *assetOperator) Open(name string) (http.File, error) { - var err error - if len(name) > 0 && name[0] == '/' { - name = name[1:] - } - content, err := Asset(name) - if err == nil { - return &assetFile{name: name, Reader: bytes.NewReader(content)}, nil - } - children, err := AssetDir(name) - if err == nil { - childInfos := make([]os.FileInfo, 0, len(children)) - for _, child := range children { - childPath := filepath.Join(name, child) - info, errInfo := AssetInfo(filepath.Join(name, child)) - if errInfo == nil { - childInfos = append(childInfos, info) - } else { - childInfos = append(childInfos, newDirFileInfo(childPath)) - } - } - return &assetFile{name: name, childInfos: childInfos}, nil - } else { - // If the error is not found, return an error that will - // result in a 404 error. Otherwise the server returns - // a 500 error for files not found. - if strings.Contains(err.Error(), "not found") { - return nil, os.ErrNotExist - } - return nil, err - } -} - -// Close no need do anything -func (f *assetFile) Close() error { - return nil -} - -// Readdir read dir's children file info -func (f *assetFile) Readdir(count int) ([]os.FileInfo, error) { - if len(f.childInfos) == 0 { - return nil, os.ErrNotExist - } - if count <= 0 { - return f.childInfos, nil - } - if f.childInfoOffset+count > len(f.childInfos) { - count = len(f.childInfos) - f.childInfoOffset - } - offset := f.childInfoOffset - f.childInfoOffset += count - return f.childInfos[offset : offset+count], nil -} - -// Stat read file info from asset item -func (f *assetFile) Stat() (os.FileInfo, error) { - if len(f.childInfos) != 0 { - return newDirFileInfo(f.name), nil - } - return AssetInfo(f.name) -} - -// newDirFileInfo return default dir file info -func newDirFileInfo(name string) os.FileInfo { - return &bindataFileInfo{ - name: name, - size: 0, - mode: os.FileMode(2147484068), // equal os.FileMode(0644)|os.ModeDir - modTime: time.Time{}} -} - -// AssetFile return a http.FileSystem instance that data backend by asset -func AssetFile() http.FileSystem { - return &assetOperator{} -} - -var _appJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2a\xcf\xcc\x4b\xc9\x2f\xd7\x4b\xcc\x49\x2d\x2a\xd1\x50\x4a\x2c\x28\xd0\xcb\x2a\x56\xc8\xc9\x4f\x4c\x49\x4d\x51\x48\x2b\xca\xcf\x55\x88\x51\xd2\x57\xd2\xb4\x06\x04\x00\x00\xff\xff\xa9\x06\xf7\xa3\x27\x00\x00\x00") - -func appJsBytes() ([]byte, error) { - return bindataRead( - _appJs, - "app.js", - ) -} - -func appJs() (*asset, error) { - bytes, err := appJsBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "app.js", size: 39, mode: os.FileMode(438), modTime: time.Unix(1565946441, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _cssMainCss = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\xca\x4f\xa9\x54\xa8\xe6\xe5\x52\x50\x50\x50\x48\x4a\x4c\xce\x4e\x2f\xca\x2f\xcd\x4b\xd1\x4d\xce\xcf\xc9\x2f\xb2\x52\x48\xca\x49\x4c\xce\xb6\xe6\xe5\xaa\xe5\xe5\x02\x04\x00\x00\xff\xff\x03\x25\x9c\x89\x29\x00\x00\x00") - -func cssMainCssBytes() ([]byte, error) { - return bindataRead( - _cssMainCss, - "css/main.css", - ) -} - -func cssMainCss() (*asset, error) { - bytes, err := cssMainCssBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "css/main.css", size: 41, mode: os.FileMode(438), modTime: time.Unix(1565946441, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _indexHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4c\x8e\x41\x0e\xc2\x20\x10\x45\xf7\x24\xdc\xe1\xa7\x07\x28\xe9\x7e\x64\xed\x35\x10\x46\xc1\x50\x21\x30\x0b\xbd\xbd\x29\xc5\xc4\xf5\x7f\x6f\xde\x50\x94\x3d\x5b\xad\xb4\xa2\xc8\x2e\x58\xad\x00\x80\x24\x49\x66\x7b\xe5\x9c\x0b\xee\xad\xec\xe8\xe2\x24\x79\x54\xf7\x60\x32\xe7\xaa\x15\x99\xe9\x68\x45\xb7\x12\x3e\x3f\x3b\x6e\x16\x7f\x6e\x7a\x05\x7e\xaf\x47\x08\x64\xe2\x36\xf8\x49\x76\xdf\x52\x15\xf4\xe6\x2f\x8b\x71\xb5\xae\xcf\xbe\x58\x80\xcc\x39\x8c\xc6\xbc\x3c\x72\xc7\xb3\xdf\x00\x00\x00\xff\xff\x7e\xad\xd1\x97\xb3\x00\x00\x00") - -func indexHtmlBytes() ([]byte, error) { - return bindataRead( - _indexHtml, - "index.html", - ) -} - -func indexHtml() (*asset, error) { - bytes, err := indexHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "index.html", size: 179, mode: os.FileMode(438), modTime: time.Unix(1565946441, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "app.js": appJs, - "css/main.css": cssMainCss, - "index.html": indexHtml, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "app.js": {appJs, map[string]*bintree{}}, - "css": {nil, map[string]*bintree{ - "main.css": {cssMainCss, map[string]*bintree{}}, - }}, - "index.html": {indexHtml, map[string]*bintree{}}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} diff --git a/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/main.go b/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/main.go deleted file mode 100644 index 5e716f02..00000000 --- a/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/main.go +++ /dev/null @@ -1,54 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -// $ go get -u github.com/go-bindata/go-bindata/v3/go-bindata -// $ go-bindata -fs -prefix "public" ./public/... -// $ go run . - -func newApp() *iris.Application { - app := iris.New() - app.OnErrorCode(iris.StatusNotFound, func(ctx iris.Context) { - ctx.Writef("404 not found here") - }) - - app.HandleDir("/", AssetFile()) - - // Note: - // if you want a dynamic index page then see the file-server/embedded-single-page-application - // which is registering a view engine based on bindata as well and a root route. - - app.Get("/ping", func(ctx iris.Context) { - ctx.WriteString("pong") - }) - app.Get("/.well-known", func(ctx iris.Context) { - ctx.WriteString("well-known") - }) - app.Get(".well-known/ready", func(ctx iris.Context) { - ctx.WriteString("ready") - }) - app.Get(".well-known/live", func(ctx iris.Context) { - ctx.WriteString("live") - }) - app.Get(".well-known/metrics", func(ctx iris.Context) { - ctx.Writef("metrics") - }) - return app -} - -func main() { - app := newApp() - - // http://localhost:8080/index.html - // http://localhost:8080/app.js - // http://localhost:8080/css/main.css - // - // http://localhost:8080/ping - // http://localhost:8080/.well-known - // http://localhost:8080/.well-known/ready - // http://localhost:8080/.well-known/live - // http://localhost:8080/.well-known/metrics - // - // Remember: we could use the root wildcard `app.Get("/{param:path}")` and serve the files manually as well. - app.Listen(":8080") -} diff --git a/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/public/app.js b/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/public/app.js deleted file mode 100644 index c009a1b9..00000000 --- a/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/public/app.js +++ /dev/null @@ -1 +0,0 @@ -window.alert("app.js loaded from static page of \"/"); \ No newline at end of file diff --git a/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/public/css/main.css b/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/public/css/main.css deleted file mode 100644 index 7db3df1d..00000000 --- a/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/public/css/main.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - background-color: black; -} diff --git a/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/public/index.html b/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/public/index.html deleted file mode 100644 index e36f1bfe..00000000 --- a/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/public/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - Hello from static page - - - -

Hello from index.html

- - - - - - \ No newline at end of file diff --git a/_examples/file-server/single-page-application/embedded-single-page-application/bindata.go b/_examples/file-server/single-page-application/embedded-single-page-application/bindata.go deleted file mode 100644 index c9cf99a6..00000000 --- a/_examples/file-server/single-page-application/embedded-single-page-application/bindata.go +++ /dev/null @@ -1,407 +0,0 @@ -// Code generated by go-bindata. (@generated) DO NOT EDIT. - -//Package main generated by go-bindata.// sources: -// public/app.js -// public/app2/index.html -// public/css/main.css -// public/index.html -package main - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(data, name string) ([]byte, error) { - gz, err := gzip.NewReader(strings.NewReader(data)) - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -// Name return file name -func (fi bindataFileInfo) Name() string { - return fi.name -} - -// Size return file size -func (fi bindataFileInfo) Size() int64 { - return fi.size -} - -// Mode return file mode -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} - -// ModTime return file modify time -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} - -// IsDir return file whether a directory -func (fi bindataFileInfo) IsDir() bool { - return fi.mode&os.ModeDir != 0 -} - -// Sys return file is sys mode -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -type assetFile struct { - *bytes.Reader - name string - childInfos []os.FileInfo - childInfoOffset int -} - -type assetOperator struct{} - -// Open implement http.FileSystem interface -func (f *assetOperator) Open(name string) (http.File, error) { - var err error - if len(name) > 0 && name[0] == '/' { - name = name[1:] - } - content, err := Asset(name) - if err == nil { - return &assetFile{name: name, Reader: bytes.NewReader(content)}, nil - } - children, err := AssetDir(name) - if err == nil { - childInfos := make([]os.FileInfo, 0, len(children)) - for _, child := range children { - childPath := filepath.Join(name, child) - info, errInfo := AssetInfo(filepath.Join(name, child)) - if errInfo == nil { - childInfos = append(childInfos, info) - } else { - childInfos = append(childInfos, newDirFileInfo(childPath)) - } - } - return &assetFile{name: name, childInfos: childInfos}, nil - } else { - // If the error is not found, return an error that will - // result in a 404 error. Otherwise the server returns - // a 500 error for files not found. - if strings.Contains(err.Error(), "not found") { - return nil, os.ErrNotExist - } - return nil, err - } -} - -// Close no need do anything -func (f *assetFile) Close() error { - return nil -} - -// Readdir read dir's children file info -func (f *assetFile) Readdir(count int) ([]os.FileInfo, error) { - if len(f.childInfos) == 0 { - return nil, os.ErrNotExist - } - if count <= 0 { - return f.childInfos, nil - } - if f.childInfoOffset+count > len(f.childInfos) { - count = len(f.childInfos) - f.childInfoOffset - } - offset := f.childInfoOffset - f.childInfoOffset += count - return f.childInfos[offset : offset+count], nil -} - -// Stat read file info from asset item -func (f *assetFile) Stat() (os.FileInfo, error) { - if len(f.childInfos) != 0 { - return newDirFileInfo(f.name), nil - } - return AssetInfo(f.name) -} - -// newDirFileInfo return default dir file info -func newDirFileInfo(name string) os.FileInfo { - return &bindataFileInfo{ - name: name, - size: 0, - mode: os.FileMode(2147484068), // equal os.FileMode(0644)|os.ModeDir - modTime: time.Time{}} -} - -// AssetFile return a http.FileSystem instance that data backend by asset -func AssetFile() http.FileSystem { - return &assetOperator{} -} - -var _publicAppJs = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2a\xcf\xcc\x4b\xc9\x2f\xd7\x4b\xcc\x49\x2d\x2a\xd1\x50\x4a\x2c\x28\xd0\xcb\x2a\x56\xc8\xc9\x4f\x4c\x49\x4d\x51\x48\x2b\xca\xcf\x55\x88\x51\xd2\x57\xd2\xb4\x06\x04\x00\x00\xff\xff\xa9\x06\xf7\xa3\x27\x00\x00\x00" - -func publicAppJsBytes() ([]byte, error) { - return bindataRead( - _publicAppJs, - "public/app.js", - ) -} - -func publicAppJs() (*asset, error) { - bytes, err := publicAppJsBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "public/app.js", size: 39, mode: os.FileMode(438), modTime: time.Unix(1595516291, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _publicApp2IndexHtml = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x34\x8d\x41\x0a\xc2\x40\x0c\x45\xf7\x81\xdc\xe1\x9f\xc0\xd0\xae\x43\xc0\x9d\xd7\xa8\x4c\x24\x85\xd4\x09\x32\x0b\xbd\xbd\xb4\xd6\xe5\x87\xf7\xde\xd7\x18\x5b\x1a\x13\x93\x86\x2f\xcd\x98\x00\x40\xc7\x3a\xd2\xed\x5a\x85\x59\xe5\x37\x98\x54\x4e\x84\x49\xef\xbd\x7d\xfe\x70\x4c\x86\x9b\x67\x76\x3c\x5e\x7d\xc3\x52\x35\xcb\xfa\x6c\xfe\xbe\xec\x71\xa8\xc4\x74\xd8\xa7\x73\x84\xf6\xd7\x6f\x00\x00\x00\xff\xff\xfd\x28\x92\x95\x7c\x00\x00\x00" - -func publicApp2IndexHtmlBytes() ([]byte, error) { - return bindataRead( - _publicApp2IndexHtml, - "public/app2/index.html", - ) -} - -func publicApp2IndexHtml() (*asset, error) { - bytes, err := publicApp2IndexHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "public/app2/index.html", size: 124, mode: os.FileMode(438), modTime: time.Unix(1572105320, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _publicCssMainCss = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\xca\x4f\xa9\x54\xa8\xe6\xe5\x52\x50\x50\x50\x48\x4a\x4c\xce\x4e\x2f\xca\x2f\xcd\x4b\xd1\x4d\xce\xcf\xc9\x2f\xb2\x52\x48\xca\x49\x4c\xce\xb6\xe6\xe5\xaa\xe5\xe5\x02\x04\x00\x00\xff\xff\x03\x25\x9c\x89\x29\x00\x00\x00" - -func publicCssMainCssBytes() ([]byte, error) { - return bindataRead( - _publicCssMainCss, - "public/css/main.css", - ) -} - -func publicCssMainCss() (*asset, error) { - bytes, err := publicCssMainCssBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "public/css/main.css", size: 41, mode: os.FileMode(438), modTime: time.Unix(1565946441, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _publicIndexHtml = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x34\x8e\x41\x0e\xc2\x20\x10\x45\xf7\x24\xdc\xe1\xa7\x07\x80\x74\x3f\xb2\x76\xe9\xc2\x0b\x60\x41\xc1\x50\x21\xc0\x42\xd3\xf4\xee\x06\x4a\x97\x93\xf7\x66\xde\x90\xab\x6b\x50\x9c\x71\x46\xce\x6a\xa3\x38\x03\x00\xaa\xbe\x06\xab\xb6\x0d\xe2\xa6\x5f\x56\xdc\xdb\x88\x7d\x27\x79\x00\xce\x48\x0e\x9d\x33\x7a\x44\xf3\x3b\x17\xdd\xac\x70\xb5\x21\x44\x3c\x73\x5c\xe1\x3f\xc6\x7e\x45\x6b\x80\xa4\x9b\xbb\x3f\xcc\xb2\x64\x9f\x2a\x4a\x5e\x2e\x93\xd4\x29\x89\x77\x99\x14\x40\xf2\x00\xbd\x31\x2e\xf7\x5c\xfb\xf3\x1f\x00\x00\xff\xff\x25\xe9\x37\x57\xae\x00\x00\x00" - -func publicIndexHtmlBytes() ([]byte, error) { - return bindataRead( - _publicIndexHtml, - "public/index.html", - ) -} - -func publicIndexHtml() (*asset, error) { - bytes, err := publicIndexHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "public/index.html", size: 174, mode: os.FileMode(438), modTime: time.Unix(1565946441, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "public/app.js": publicAppJs, - "public/app2/index.html": publicApp2IndexHtml, - "public/css/main.css": publicCssMainCss, - "public/index.html": publicIndexHtml, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "public": {nil, map[string]*bintree{ - "app.js": {publicAppJs, map[string]*bintree{}}, - "app2": {nil, map[string]*bintree{ - "index.html": {publicApp2IndexHtml, map[string]*bintree{}}, - }}, - "css": {nil, map[string]*bintree{ - "main.css": {publicCssMainCss, map[string]*bintree{}}, - }}, - "index.html": {publicIndexHtml, map[string]*bintree{}}, - }}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} diff --git a/_examples/file-server/single-page-application/embedded-single-page-application/main.go b/_examples/file-server/single-page-application/embedded-single-page-application/main.go deleted file mode 100644 index f6ff0055..00000000 --- a/_examples/file-server/single-page-application/embedded-single-page-application/main.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -// $ go get -u github.com/go-bindata/go-bindata/v3/go-bindata -// $ go-bindata -nomemcopy -fs ./public/... -// $ go run . - -var page = struct { - Title string -}{"Welcome"} - -func newApp() *iris.Application { - app := iris.New() - app.RegisterView(iris.HTML("./public", ".html").Binary(Asset, AssetNames)) - - app.Get("/", func(ctx iris.Context) { - ctx.ViewData("Page", page) - ctx.View("index.html") - }) - - // We didn't add a `-prefix "public"` argument on go-bindata command - // because the view's `Assset` and `AssetNames` require fullpath. - // Make use of the `PrefixDir` to serve assets on cases like that; - // when bindata.go file contains files that are - // not necessary public assets to be served. - app.HandleDir("/", iris.PrefixDir("public", AssetFile())) - - return app -} - -func main() { - app := newApp() - - // http://localhost:8080 - // http://localhost:8080/app.js - // http://localhost:8080/css/main.css - // http://localhost:8080/app2 - app.Listen(":8080") -} diff --git a/_examples/file-server/single-page-application/embedded-single-page-application/main_test.go b/_examples/file-server/single-page-application/embedded-single-page-application/main_test.go deleted file mode 100644 index 89270787..00000000 --- a/_examples/file-server/single-page-application/embedded-single-page-application/main_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package main - -import ( - "io/ioutil" - "path/filepath" - "runtime" - "strings" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -type resource string - -func (r resource) contentType() string { - switch filepath.Ext(r.String()) { - case ".js": - return "text/javascript" - case ".css": - return "text/css" - default: - return "text/html" - } -} - -func (r resource) String() string { - return string(r) -} - -func (r resource) strip(strip string) string { - s := r.String() - return strings.TrimPrefix(s, strip) -} - -func (r resource) loadFromBase(dir string) string { - filename := r.String() - - if strings.HasSuffix(filename, "/") { - filename = filename + "index.html" - } - - fullpath := filepath.Join(dir, filename) - - b, err := ioutil.ReadFile(fullpath) - if err != nil { - panic(fullpath + " failed with error: " + err.Error()) - } - result := string(b) - if runtime.GOOS != "windows" { - result = strings.Replace(result, "\n", "\r\n", -1) - result = strings.Replace(result, "\r\r", "", -1) - } - return result -} - -var urls = []resource{ - "/", - "/index.html", - "/app.js", - "/css/main.css", - "/app2/", - "/app2/index.html", -} - -func TestSPAEmbedded(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - for _, u := range urls { - url := u.String() - contents := u.loadFromBase("./public") - contents = strings.Replace(contents, "{{ .Page.Title }}", page.Title, 1) - - e.GET(url).Expect(). - Status(httptest.StatusOK). - ContentType(u.contentType(), app.ConfigurationReadOnly().GetCharset()). - Body().Equal(contents) - } -} diff --git a/_examples/file-server/single-page-application/embedded-single-page-application/public/app.js b/_examples/file-server/single-page-application/embedded-single-page-application/public/app.js deleted file mode 100644 index c47a1fd5..00000000 --- a/_examples/file-server/single-page-application/embedded-single-page-application/public/app.js +++ /dev/null @@ -1 +0,0 @@ -window.alert("app.js loaded from \"/"); \ No newline at end of file diff --git a/_examples/file-server/single-page-application/embedded-single-page-application/public/app2/index.html b/_examples/file-server/single-page-application/embedded-single-page-application/public/app2/index.html deleted file mode 100644 index 680dd242..00000000 --- a/_examples/file-server/single-page-application/embedded-single-page-application/public/app2/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - App 2 - - - -

Hello from app2/index.html

- - - \ No newline at end of file diff --git a/_examples/file-server/single-page-application/embedded-single-page-application/public/css/main.css b/_examples/file-server/single-page-application/embedded-single-page-application/public/css/main.css deleted file mode 100644 index fb72e54a..00000000 --- a/_examples/file-server/single-page-application/embedded-single-page-application/public/css/main.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - background-color: black; -} diff --git a/_examples/file-server/single-page-application/embedded-single-page-application/public/index.html b/_examples/file-server/single-page-application/embedded-single-page-application/public/index.html deleted file mode 100644 index c52c1613..00000000 --- a/_examples/file-server/single-page-application/embedded-single-page-application/public/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - {{ .Page.Title }} - - - -

Hello from index.html

- - - - - - \ No newline at end of file diff --git a/_examples/file-server/subdomain/assets/app2/app22/just_a_text_no_index.txt b/_examples/file-server/subdomain/assets/app2/app22/just_a_text_no_index.txt deleted file mode 100644 index f1cc1278..00000000 --- a/_examples/file-server/subdomain/assets/app2/app22/just_a_text_no_index.txt +++ /dev/null @@ -1 +0,0 @@ -just a text. \ No newline at end of file diff --git a/_examples/file-server/subdomain/assets/app2/app2app3/index.html b/_examples/file-server/subdomain/assets/app2/app2app3/index.html deleted file mode 100644 index 750f10ba..00000000 --- a/_examples/file-server/subdomain/assets/app2/app2app3/index.html +++ /dev/null @@ -1 +0,0 @@ -

Hello App2App3 index

\ No newline at end of file diff --git a/_examples/file-server/subdomain/assets/app2/index.html b/_examples/file-server/subdomain/assets/app2/index.html deleted file mode 100644 index 8193d822..00000000 --- a/_examples/file-server/subdomain/assets/app2/index.html +++ /dev/null @@ -1 +0,0 @@ -

Hello App2 index

\ No newline at end of file diff --git a/_examples/file-server/subdomain/assets/css/main.css b/_examples/file-server/subdomain/assets/css/main.css deleted file mode 100644 index 7db3df1d..00000000 --- a/_examples/file-server/subdomain/assets/css/main.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - background-color: black; -} diff --git a/_examples/file-server/subdomain/assets/favicon.ico b/_examples/file-server/subdomain/assets/favicon.ico deleted file mode 100644 index c370da518ec542579b7cc0d5d30f4778b4a96318..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 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 index \ No newline at end of file diff --git a/_examples/file-server/subdomain/assets/js/jquery-2.1.1.js b/_examples/file-server/subdomain/assets/js/jquery-2.1.1.js deleted file mode 100644 index 07f93514..00000000 --- a/_examples/file-server/subdomain/assets/js/jquery-2.1.1.js +++ /dev/null @@ -1 +0,0 @@ -console.log("example"); \ No newline at end of file diff --git a/_examples/file-server/subdomain/hosts b/_examples/file-server/subdomain/hosts deleted file mode 100644 index 69c1a384..00000000 --- a/_examples/file-server/subdomain/hosts +++ /dev/null @@ -1,2 +0,0 @@ -127.0.0.1 examle.com -127.0.0.1 v1.examle.com \ No newline at end of file diff --git a/_examples/file-server/subdomain/main.go b/_examples/file-server/subdomain/main.go deleted file mode 100644 index bae492f4..00000000 --- a/_examples/file-server/subdomain/main.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -const ( - addr = "example.com:80" - subdomain = "v1" -) - -func newApp() *iris.Application { - app := iris.New() - app.Favicon("./assets/favicon.ico") - - v1 := app.Subdomain(subdomain) - v1.HandleDir("/", iris.Dir("./assets")) - - // http://v1.example.com - // http://v1.example.com/css/main.css - // http://v1.example.com/js/jquery-2.1.1.js - // http://v1.example.com/favicon.ico - return app -} - -func main() { - app := newApp() - app.Listen(addr) -} diff --git a/_examples/file-server/subdomain/main_test.go b/_examples/file-server/subdomain/main_test.go deleted file mode 100644 index 96eb882d..00000000 --- a/_examples/file-server/subdomain/main_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package main - -import ( - "io/ioutil" - "net" - "path/filepath" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -type resource string - -func (r resource) contentType() string { - switch filepath.Ext(r.String()) { - case ".js": - return "text/javascript" - case ".css": - return "text/css" - case ".ico": - return "image/x-icon" - case ".html", "": - return "text/html" - default: - return "text/plain" - } -} - -func (r resource) String() string { - return string(r) -} - -func (r resource) loadFromBase(dir string) string { - filename := r.String() - - if filepath.Ext(filename) == "" { - // root /. - filename = filename + "/index.html" - } - - fullpath := filepath.Join(dir, filename) - - b, err := ioutil.ReadFile(fullpath) - if err != nil { - panic(fullpath + " failed with error: " + err.Error()) - } - - result := string(b) - - return result -} - -func TestFileServerSubdomainBasic(t *testing.T) { - urls := []resource{ - "/css/main.css", - "/js/jquery-2.1.1.js", - "/favicon.ico", - "/app2", - "/app2/app2app3", - "/", - } - - app := newApp() - e := httptest.New(t, app) - - host, _, err := net.SplitHostPort(addr) - if err != nil { - t.Fatal(err) - } - host = "http://" + subdomain + "." + host - - for _, u := range urls { - url := u.String() - contents := u.loadFromBase("./assets") - - e.GET(url).WithURL(host).Expect(). - Status(httptest.StatusOK). - ContentType(u.contentType(), app.ConfigurationReadOnly().GetCharset()). - Body().Equal(contents) - } -} diff --git a/_examples/file-server/upload-file/main.go b/_examples/file-server/upload-file/main.go deleted file mode 100644 index 0d34dc16..00000000 --- a/_examples/file-server/upload-file/main.go +++ /dev/null @@ -1,128 +0,0 @@ -package main - -import ( - "crypto/md5" - "fmt" - "io" - "os" - "strconv" - "time" - - "github.com/kataras/iris/v12" -) - -const maxSize = 5 << 20 // 5MB - -func main() { - app := iris.New() - - app.RegisterView(iris.HTML("./templates", ".html")) - - // Serve the upload_form.html to the client. - app.Get("/upload", func(ctx iris.Context) { - // create a token (optionally). - - now := time.Now().Unix() - h := md5.New() - io.WriteString(h, strconv.FormatInt(now, 10)) - token := fmt.Sprintf("%x", h.Sum(nil)) - - // render the form with the token for any use you'd like. - // ctx.ViewData("", token) - // or add second argument to the `View` method. - // Token will be passed as {{.}} in the template. - ctx.View("upload_form.html", token) - }) - - /* Read before continue. - - 0. The default post max size is 32MB, - you can extend it to read more data using the `iris.WithPostMaxMemory(maxSize)` configurator at `app.Run`, - note that this will not be enough for your needs, read below. - - 1. The faster way to check the size is using the `ctx.GetContentLength()` which returns the whole request's size - (plus a logical number like 2MB or even 10MB for the rest of the size like headers). You can create a - middleware to adapt this to any necessary handler. - - myLimiter := func(ctx iris.Context) { - if ctx.GetContentLength() > maxSize { // + 2 << 20 { - ctx.StatusCode(iris.StatusRequestEntityTooLarge) - return - } - ctx.Next() - } - - app.Post("/upload", myLimiter, myUploadHandler) - - Most clients will set the "Content-Length" header (like browsers) but it's always better to make sure that any client - can't send data that your server can't or doesn't want to handle. This can be happen using - the `app.Use(LimitRequestBodySize(maxSize))` (as app or route middleware) - or the `ctx.SetMaxRequestBodySize(maxSize)` to limit the request based on a customized logic inside a particular handler, they're the same, - read below. - - 2. You can force-limit the request body size inside a handler using the `ctx.SetMaxRequestBodySize(maxSize)`, - this will force the connection to close if the incoming data are larger (most clients will receive it as "connection reset"), - use that to make sure that the client will not send data that your server can't or doesn't want to accept, as a fallback. - - app.Post("/upload", iris.LimitRequestBodySize(maxSize), myUploadHandler) - - OR - - app.Post("/upload", func(ctx iris.Context){ - ctx.SetMaxRequestBodySize(maxSize) - - // [...] - }) - - 3. Another way is to receive the data and check the second return value's `Size` value of the `ctx.FormFile`, i.e `info.Size`, this will give you - the exact file size, not the whole incoming request data length. - - app.Post("/", func(ctx iris.Context){ - file, info, err := ctx.FormFile("uploadfile") - if err != nil { - ctx.StatusCode(iris.StatusInternalServerError) - ctx.HTML("Error while uploading: " + err.Error() + "") - return - } - - defer file.Close() - - if info.Size > maxSize { - ctx.StatusCode(iris.StatusRequestEntityTooLarge) - return - } - - // [...] - }) - */ - - // Handle the post request from the upload_form.html to the server - app.Post("/upload", iris.LimitRequestBodySize(maxSize+1<<20), func(ctx iris.Context) { - // Get the file from the request. - file, info, err := ctx.FormFile("uploadfile") - if err != nil { - ctx.StatusCode(iris.StatusInternalServerError) - ctx.HTML("Error while uploading: " + err.Error() + "") - return - } - - defer file.Close() - fname := info.Filename - - // Create a file with the same name - // assuming that you have a folder named 'uploads' - out, err := os.OpenFile("./uploads/"+fname, - os.O_WRONLY|os.O_CREATE, 0666) - if err != nil { - ctx.StatusCode(iris.StatusInternalServerError) - ctx.HTML("Error while uploading: " + err.Error() + "") - return - } - defer out.Close() - - io.Copy(out, file) - }) - - // start the server at http://localhost:8080 with post limit at 5 MB. - app.Listen(":8080" /* 0.*/, iris.WithPostMaxMemory(maxSize)) -} diff --git a/_examples/file-server/upload-file/templates/upload_form.html b/_examples/file-server/upload-file/templates/upload_form.html deleted file mode 100644 index aa60740f..00000000 --- a/_examples/file-server/upload-file/templates/upload_form.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - Upload file - - - -
- - - -
- - - \ No newline at end of file diff --git a/_examples/file-server/upload-file/uploads/.gitkeep b/_examples/file-server/upload-file/uploads/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/_examples/file-server/upload-files/main.go b/_examples/file-server/upload-files/main.go deleted file mode 100644 index e1094daa..00000000 --- a/_examples/file-server/upload-files/main.go +++ /dev/null @@ -1,116 +0,0 @@ -package main - -import ( - "crypto/md5" - "fmt" - "io" - "mime/multipart" - "os" - "path/filepath" - "strconv" - "strings" - "time" - - "github.com/kataras/iris/v12" -) - -func main() { - app := newApp() - // start the server at http://localhost:8080 with post limit at 32 MB. - app.Listen(":8080", iris.WithPostMaxMemory(32<<20 /* same as 32 * iris.MB */)) -} - -func newApp() *iris.Application { - app := iris.New() - app.RegisterView(iris.HTML("./templates", ".html")) - - // Serve the upload_form.html to the client. - app.Get("/upload", func(ctx iris.Context) { - // create a token (optionally). - - now := time.Now().Unix() - h := md5.New() - io.WriteString(h, strconv.FormatInt(now, 10)) - token := fmt.Sprintf("%x", h.Sum(nil)) - - // render the form with the token for any use you'd like. - ctx.View("upload_form.html", token) - }) - - // Handle the post request from the upload_form.html to the server. - app.Post("/upload", func(ctx iris.Context) { - // - // UploadFormFiles - // uploads any number of incoming files ("multiple" property on the form input). - // - - // second argument is optional, - // it can be used to change a file's name based on the request, - // at this example we will showcase how to use it - // by prefixing the uploaded file with the current user's ip. - ctx.UploadFormFiles("./uploads", beforeSave) - }) - - app.Post("/upload_manual", func(ctx iris.Context) { - // Get the max post value size passed via iris.WithPostMaxMemory. - maxSize := ctx.Application().ConfigurationReadOnly().GetPostMaxMemory() - - err := ctx.Request().ParseMultipartForm(maxSize) - if err != nil { - ctx.StopWithError(iris.StatusInternalServerError, err) - return - } - - form := ctx.Request().MultipartForm - - files := form.File["files[]"] - failures := 0 - for _, file := range files { - _, err = saveUploadedFile(file, "./uploads") - if err != nil { - failures++ - ctx.Writef("failed to upload: %s\n", file.Filename) - } - } - ctx.Writef("%d files uploaded", len(files)-failures) - }) - - return app -} - -func saveUploadedFile(fh *multipart.FileHeader, destDirectory string) (int64, error) { - src, err := fh.Open() - if err != nil { - return 0, err - } - defer src.Close() - - out, err := os.OpenFile(filepath.Join(destDirectory, fh.Filename), - os.O_WRONLY|os.O_CREATE, os.FileMode(0666)) - if err != nil { - return 0, err - } - defer out.Close() - - return io.Copy(out, src) -} - -func beforeSave(ctx iris.Context, file *multipart.FileHeader) { - ip := ctx.RemoteAddr() - // make sure you format the ip in a way - // that can be used for a file name (simple case): - ip = strings.Replace(ip, ".", "_", -1) - ip = strings.Replace(ip, ":", "_", -1) - - // you can use the time.Now, to prefix or suffix the files - // based on the current time as well, as an exercise. - // i.e unixTime := time.Now().Unix() - // prefix the Filename with the $IP- - // no need for more actions, internal uploader will use this - // name to save the file into the "./uploads" folder. - if ip == "" { - return - } - - file.Filename = ip + "-" + file.Filename -} diff --git a/_examples/file-server/upload-files/main_test.go b/_examples/file-server/upload-files/main_test.go deleted file mode 100644 index 91eb8742..00000000 --- a/_examples/file-server/upload-files/main_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "os" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestUploadFiles(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - // upload the file itself. - fh, err := os.Open("main.go") - if err != nil { - t.Fatal(err) - } - defer fh.Close() - - e.POST("/upload").WithMultipart().WithFile("files", "main.go", fh). - Expect().Status(httptest.StatusOK) - - f, err := os.Open("uploads/main.go") - if err != nil { - t.Fatalf("expected file to get actually uploaded on the system directory but: %v", err) - } - f.Close() - - os.Remove(f.Name()) -} diff --git a/_examples/file-server/upload-files/templates/upload_form.html b/_examples/file-server/upload-files/templates/upload_form.html deleted file mode 100644 index 0df62418..00000000 --- a/_examples/file-server/upload-files/templates/upload_form.html +++ /dev/null @@ -1,12 +0,0 @@ - - -Upload file - - -
- -
- - diff --git a/_examples/file-server/upload-files/uploads/.gitkeep b/_examples/file-server/upload-files/uploads/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/_examples/http-server/README.md b/_examples/http-server/README.md deleted file mode 100644 index d588a0c6..00000000 --- a/_examples/http-server/README.md +++ /dev/null @@ -1,205 +0,0 @@ -# Hosts - -## Listen and Serve - -You can start the server(s) listening to any type of `net.Listener` or even `http.Server` instance. -The method for initialization of the server should be passed at the end, via `Run` function. - -The most common method that Go developers use to serve their servers are -by passing a network address with form of "hostname:ip". With Iris -we use the `iris.Addr` which is an `iris.Runner` type - -```go -// Listening on tcp with network address 0.0.0.0:8080 -// app.Listen(":8080") it's a shortcut of: -app.Run(iris.Addr(":8080")) -``` - -Sometimes you have created a standard net/http server somewhere else in your app and want to use that to serve the Iris web app - -```go -// Same as before but using a custom http.Server which may being used somewhere else too -app.Run(iris.Server(&http.Server{Addr:":8080"})) -``` - -The most advanced usage is to create a custom or a standard `net.Listener` and pass that to `app.Run` - -```go -// Using a custom net.Listener -l, err := net.Listen("tcp4", ":8080") -if err != nil { - panic(err) -} -app.Run(iris.Listener(l)) -``` - -A more complete example, using the unix-only socket files feature - -```go -package main - -import ( - "os" - "net" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - // UNIX socket - if errOs := os.Remove(socketFile); errOs != nil && !os.IsNotExist(errOs) { - app.Logger().Fatal(errOs) - } - - l, err := net.Listen("unix", socketFile) - - if err != nil { - app.Logger().Fatal(err) - } - - if err = os.Chmod(socketFile, mode); err != nil { - app.Logger().Fatal(err) - } - - app.Run(iris.Listener(l)) -} -``` - -### HTTP/2 and Secure - -If you have signed file keys you can use the `iris.TLS` to serve `https` based on those certification keys - -```go -// TLS using files -app.Run(iris.TLS("127.0.0.1:443", "mycert.cert", "mykey.key")) -``` - -The method you should use when your app is ready for **production** is the `iris.AutoTLS` which starts a secure server with automated certifications provided by https://letsencrypt.org for **free** - -```go -// Automatic TLS -app.Run(iris.AutoTLS(":443", "example.com", "admin@example.com")) -``` - -### Any `iris.Runner` - -There may be times that you want something very special to listen on, which is not a type of `net.Listener`. You are able to do that by `iris.Raw`, but you're responsible of that method - -```go -// Using any func() error, -// the responsibility of starting up a listener is up to you with this way, -// for the sake of simplicity we will use the -// ListenAndServe function of the `net/http` package. -app.Run(iris.Raw(&http.Server{Addr:":8080"}).ListenAndServe) -``` - -## Host configurators - -All the above forms of listening are accepting a last, variadic argument of `func(*iris.Supervisor)`. This is used to add configurators for that specific host you passed via those functions. - -For example let's say that we want to add a callback which is fired when -the server is shutdown - -```go -app.Run(iris.Addr(":8080", func(h *iris.Supervisor) { - h.RegisterOnShutdown(func() { - println("server terminated") - }) -})) -``` - -You can even do that before `app.Run` method, but the difference is that -these host configurators will be executed to all hosts that you may use to serve your web app (via `app.NewHost` we'll see that in a minute) - -```go -app := iris.New() -app.ConfigureHost(func(h *iris.Supervisor) { - h.RegisterOnShutdown(func() { - println("server terminated") - }) -}) -app.Listen(":8080") -``` - -Access to all hosts that serve your application can be provided by -the `Application#Hosts` field, after the `Run` method. - -But the most common scenario is that you may need access to the host before the `app.Run` method, -there are two ways of gain access to the host supervisor, read below. - -We have already saw how to configure all application's hosts by second argument of `app.Run` or `app.ConfigureHost`. There is one more way which suits better for simple scenarios and that is to use the `app.NewHost` to create a new host -and use one of its `Serve` or `Listen` functions -to start the application via the `iris#Raw` Runner. - -Note that this way needs an extra import of the `net/http` package. - -Example Code: - -```go -h := app.NewHost(&http.Server{Addr:":8080"}) -h.RegisterOnShutdown(func(){ - println("server terminated") -}) - -app.Run(iris.Raw(h.ListenAndServe)) -``` - -## Multi hosts - -You can serve your Iris web app using more than one server, the `iris.Router` is compatible with the `net/http/Handler` function therefore, as you can understand, it can be used to be adapted at any `net/http` server, however there is an easier way, by using the `app.NewHost` which is also copying all the host configurators and it closes all the hosts attached to the particular web app on `app.Shutdown`. - -```go -app := iris.New() -app.Get("/", indexHandler) - -// run in different goroutine in order to not block the main "goroutine". -go app.Listen(":8080") -// start a second server which is listening on tcp 0.0.0.0:9090, -// without "go" keyword because we want to block at the last server-run. -app.NewHost(&http.Server{Addr:":9090"}).ListenAndServe() -``` - -## Shutdown (Gracefully) - -Let's continue by learning how to catch CONTROL+C/COMMAND+C or unix kill command and shutdown the server gracefully. - -> Gracefully Shutdown on CONTROL+C/COMMAND+C or when kill command sent is ENABLED BY-DEFAULT. - -In order to manually manage what to do when app is interrupted, -we have to disable the default behavior with the option `WithoutInterruptHandler` -and register a new interrupt handler (globally, across all possible hosts). - - -Example code: - -```go -package main - -import ( - "context" - "time" - - "github.com/kataras/iris/v12" -) - - -func main() { - app := iris.New() - - iris.RegisterOnInterrupt(func() { - timeout := 10 * time.Second - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - // close all hosts - app.Shutdown(ctx) - }) - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

hi, I just exist in order to see if the server is closed

") - }) - - app.Listen(":8080", iris.WithoutInterruptHandler) -} -``` diff --git a/_examples/http-server/custom-httpserver/easy-way/main.go b/_examples/http-server/custom-httpserver/easy-way/main.go deleted file mode 100644 index b6f71e8a..00000000 --- a/_examples/http-server/custom-httpserver/easy-way/main.go +++ /dev/null @@ -1,32 +0,0 @@ -package main - -import ( - "net/http" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.Writef("Hello from the server") - }) - - app.Get("/mypath", func(ctx iris.Context) { - ctx.Writef("Hello from %s", ctx.Path()) - }) - - // Any custom fields here. Handler and ErrorLog are set to the server automatically - srv := &http.Server{Addr: ":8080"} - - // http://localhost:8080/ - // http://localhost:8080/mypath - app.Run(iris.Server(srv)) // same as app.Listen(":8080") - - // More: - // see "multi" if you need to use more than one server at the same app. - // - // for a custom listener use: iris.Listener(net.Listener) or - // iris.TLS(cert,key) or iris.AutoTLS(), see "custom-listener" example for those. -} diff --git a/_examples/http-server/custom-httpserver/multi/main.go b/_examples/http-server/custom-httpserver/multi/main.go deleted file mode 100644 index 083e8e6c..00000000 --- a/_examples/http-server/custom-httpserver/multi/main.go +++ /dev/null @@ -1,47 +0,0 @@ -package main - -import ( - "net/http" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.Writef("Hello from the server") - }) - - app.Get("/mypath", func(ctx iris.Context) { - ctx.Writef("Hello from %s", ctx.Path()) - }) - - // Note: It's not needed if the first action is "go app.Run". - if err := app.Build(); err != nil { - panic(err) - } - - // start a secondary server listening on localhost:9090. - // use "go" keyword for Listen functions if you need to use more than one server at the same app. - // - // http://localhost:9090/ - // http://localhost:9090/mypath - srv1 := &http.Server{Addr: ":9090", Handler: app} - go srv1.ListenAndServe() - println("Start a server listening on http://localhost:9090") - - // start a "second-secondary" server listening on localhost:5050. - // - // http://localhost:5050/ - // http://localhost:5050/mypath - srv2 := &http.Server{Addr: ":5050", Handler: app} - go srv2.ListenAndServe() - println("Start a server listening on http://localhost:5050") - - // Note: app.Run is totally optional, we have already built the app with app.Build, - // you can just make a new http.Server instead. - // http://localhost:8080/ - // http://localhost:8080/mypath - app.Listen(":8080") // Block here. -} diff --git a/_examples/http-server/custom-httpserver/std-way/main.go b/_examples/http-server/custom-httpserver/std-way/main.go deleted file mode 100644 index b4817d2d..00000000 --- a/_examples/http-server/custom-httpserver/std-way/main.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -import ( - "net/http" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.Writef("Hello from the server") - }) - - app.Get("/mypath", func(ctx iris.Context) { - ctx.Writef("Hello from %s", ctx.Path()) - }) - - // call .Build before use the 'app' as a http.Handler on a custom http.Server - app.Build() - - // create our custom server and assign the Handler/Router - srv := &http.Server{Handler: app, Addr: ":8080"} // you have to set Handler:app and Addr, see "iris-way" which does this automatically. - // http://localhost:8080/ - // http://localhost:8080/mypath - println("Start a server listening on http://localhost:8080") - srv.ListenAndServe() // same as app.Listen(":8080") - - // Notes: - // Banner is not shown at all. Same for the Interrupt Handler, even if app's configuration allows them. - // - // `.Run` is the only one function that cares about those three. - - // More: - // see "multi" if you need to use more than one server at the same app. - // - // for a custom listener use: iris.Listener(net.Listener) or - // iris.TLS(cert,key) or iris.AutoTLS(), see "custom-listener" example for those. -} diff --git a/_examples/http-server/custom-listener/main.go b/_examples/http-server/custom-listener/main.go deleted file mode 100644 index eb156fd4..00000000 --- a/_examples/http-server/custom-listener/main.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "net" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.Writef("Hello from the server") - }) - - app.Get("/mypath", func(ctx iris.Context) { - ctx.Writef("Hello from %s", ctx.Path()) - }) - - // create any custom tcp listener, unix sock file or tls tcp listener. - l, err := net.Listen("tcp4", ":8080") - if err != nil { - panic(err) - } - - // use of the custom listener - app.Run(iris.Listener(l)) -} diff --git a/_examples/http-server/graceful-shutdown/custom-notifier/main.go b/_examples/http-server/graceful-shutdown/custom-notifier/main.go deleted file mode 100644 index 3984aefb..00000000 --- a/_examples/http-server/graceful-shutdown/custom-notifier/main.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - stdContext "context" - "os" - "os/signal" - "syscall" - "time" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

hi, I just exist in order to see if the server is closed

") - }) - - go func() { - ch := make(chan os.Signal, 1) - signal.Notify(ch, - // kill -SIGINT XXXX or Ctrl+c - os.Interrupt, - syscall.SIGINT, // register that too, it should be ok - // os.Kill is equivalent with the syscall.Kill - os.Kill, - syscall.SIGKILL, // register that too, it should be ok - // kill -SIGTERM XXXX - syscall.SIGTERM, - ) - select { - case <-ch: - println("shutdown...") - - timeout := 10 * time.Second - ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout) - defer cancel() - app.Shutdown(ctx) - } - }() - - // Start the server and disable the default interrupt handler in order to - // handle it clear and simple by our own, without any issues. - app.Listen(":8080", iris.WithoutInterruptHandler) -} diff --git a/_examples/http-server/graceful-shutdown/default-notifier/main.go b/_examples/http-server/graceful-shutdown/default-notifier/main.go deleted file mode 100644 index 06acf4ab..00000000 --- a/_examples/http-server/graceful-shutdown/default-notifier/main.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - stdContext "context" - "time" - - "github.com/kataras/iris/v12" -) - -// Before continue: -// -// Gracefully Shutdown on control+C/command+C or when kill command sent is ENABLED BY-DEFAULT. -// -// In order to manually manage what to do when app is interrupted, -// We have to disable the default behavior with the option `WithoutInterruptHandler` -// and register a new interrupt handler (globally, across all possible hosts). -func main() { - app := iris.New() - - iris.RegisterOnInterrupt(func() { - timeout := 10 * time.Second - ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout) - defer cancel() - // close all hosts - app.Shutdown(ctx) - }) - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

hi, I just exist in order to see if the server is closed

") - }) - - // http://localhost:8080 - app.Listen(":8080", iris.WithoutInterruptHandler) -} diff --git a/_examples/http-server/http3-quic/go.mod b/_examples/http-server/http3-quic/go.mod deleted file mode 100644 index bc0e2b95..00000000 --- a/_examples/http-server/http3-quic/go.mod +++ /dev/null @@ -1,7 +0,0 @@ -module github.com/kataras/iris/_examples/http-server/http3-quic - -go 1.15 - -require ( - github.com/prometheus/client_golang v1.0.0 -) diff --git a/_examples/http-server/http3-quic/localhost.cert b/_examples/http-server/http3-quic/localhost.cert deleted file mode 100644 index f440f3f1..00000000 --- a/_examples/http-server/http3-quic/localhost.cert +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC+zCCAeOgAwIBAgIJAI5gi8BzcdQgMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV -BAMMCWxvY2FsaG9zdDAeFw0xOTA3MDkxMjExNDBaFw0yOTA3MDYxMjExNDBaMBQx -EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAM1eSGwoYznwYtt+/hrv9o4FYxJFlxIMX6WN3c2y3rr8uOwExkz2RuU9SzgF -qn0ctP1DoIKWNO0/L5j5Bjy2do0k8wHYPbTqb9zG64NGZj1lhkHgYXWyCD9U41DX -V1DiJ2JiCRBadowFRRf3/KIPf3xnrCBSCoQwdfIeJJtAF9El2/TnTrGq9N98FJqR -dCNyi+zY/iuymcA3aDOyYNjxSiuV//7ONEql5dxvRlhkjCHgrQ/rIbH/lSFAS+NG -H/6ksEBX2+Q1LlQBaFiGeEnjVpCymrRfADw7bKyqMav39Nndw4UZ1r5MSG20YtXM -dE4lA6VfAKzIZs2n87WF7OO8Y2sCAwEAAaNQME4wHQYDVR0OBBYEFKYItamcYz4Z -NiDy3I2zflU4A7ywMB8GA1UdIwQYMBaAFKYItamcYz4ZNiDy3I2zflU4A7ywMAwG -A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBACSoSrEArlgPJ1ftlSMkThUR -atTqJ/yB0rSyRxsct0C04qX880VP7avnKc0UhaDruXRjdAVn4X8KI+j6azQSKT40 -KRSVBinnonE0D4DBMCUVDFtkBW3FZJXAYyIYdF/6J3Khn/ksm7VDcVxYI1rjg87B -U6aJytOkoGA2WGQOB1L0HtnTsarg/SKP/LSDUFT+XK6zTE7uogAUrpbwlpIaxc+8 -3jXvgxEdPj9Rq9Nt8/zjCkCGB2EusPPnqxcbqZb5WcGPCIlg3ChKq7vpaQld6KqG -70jT7BZ2fqWSVJ5szRoS8WpKy1SZEx/+AA7VojMzkkw4RLb66zr1v7029b51ol4= ------END CERTIFICATE----- diff --git a/_examples/http-server/http3-quic/localhost.key b/_examples/http-server/http3-quic/localhost.key deleted file mode 100644 index ee1cdae6..00000000 --- a/_examples/http-server/http3-quic/localhost.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAzV5IbChjOfBi237+Gu/2jgVjEkWXEgxfpY3dzbLeuvy47ATG -TPZG5T1LOAWqfRy0/UOggpY07T8vmPkGPLZ2jSTzAdg9tOpv3Mbrg0ZmPWWGQeBh -dbIIP1TjUNdXUOInYmIJEFp2jAVFF/f8og9/fGesIFIKhDB18h4km0AX0SXb9OdO -sar033wUmpF0I3KL7Nj+K7KZwDdoM7Jg2PFKK5X//s40SqXl3G9GWGSMIeCtD+sh -sf+VIUBL40Yf/qSwQFfb5DUuVAFoWIZ4SeNWkLKatF8APDtsrKoxq/f02d3DhRnW -vkxIbbRi1cx0TiUDpV8ArMhmzafztYXs47xjawIDAQABAoIBADvaKok7DBAquuT1 -keEP5m9lqoX8uhaMfKOnQOleJAOi+9HtYk2zyN2ui2l8XT+xSh41w2XLmQk7zQds -LCEtnEduaVQ0TWeYm5lgb+sGbW2fVQ2F82F1zWmHt+grmkr8XjYSFEor0zjjoEtn -/rzMf38mR8fzoRT9eqJhnpGQkGBnfo0SyDKIDu9yYFM7yJ5s4KOTVsMGfavjQYgJ -ssQm0KQTo8HbYHieS6drEYFRwAgT8U1NFoVq24yU+Voyy7CR5rjfOsO9gSyStVSH -nTkePmSIcpeQBfpfT3jh+STSS12eqhFCx1SqAUptUehQpOJhnWAyeSGjVLlrHqDR -bCtSWCECgYEA62J2AC8bRQ8omoEOc5h1/kwPTcLYjhOCxwwU8ky7qve173MYZUeT -dxWZx3haahccPyUKtsiGBdKYyYKSOIJMSMmwkG4uy6r5nhwNV+btEIL6Npj+XKMe -PaATA4gBLRQNwcbUlZWLYc0Y6CXFnPA+atEa7EOEBfdgUqHOym1HsAUCgYEA31rU -GPyv8R7Z1UXmxu70M8RwxKS4XhlP7RRg3Zuuqx6WWX4M85Np3wS4UWgQjGKICwoM -D4XKZQOya5p+v7a1RUZt/OD6eJ0TjypW5fBmK2yvBUQkQCsVcFjBL3F+yv2Yk1sh -KlPky4wXpDcmWXGmesgmyhpKIwL+qXEAJEaL0K8CgYABWqKlI6A7iHfKU726ioD7 -QoLABsPqJVCWRoqETk6yEBS62OWmB4Bgqf4leJrEi3d9IYBrRsIGnIyGdDrVGmLH -9GkQm6GnSEeBUlX9UHXCp4467CxiagnNfvM9DPY8xSXDHJqydZbErEJda4I0gelK -AgPuogDLa/3g289tuK015QKBgQDKcj9Qrqiiur3jC8rTgX8i9OjptAvQbsz9LL1n -4FZ/j+fjEdeXZ4RMurB+SP7G4ABDUUYBQ9lhmeo8kfpUtryzH9VNonYkoOs7lrrR -DAbvUUGKWmspJmP2QtxHrm2ofBexaKY1AXmd7Ur4c2x1IggtvgE6qn2MIojE+EGS -n8bWzQKBgQClc/j4GYNNMUYOknxXMH/ec8PBDUtn098YuFL+s7DmRHimtkkjRo1A -BtV7F8KpLruWohxXWy4QZ6HsAO255gIJ8DCbEAFCj96EHNx8KADSm3qbslu2fIB0 -zCsVaETGNAjV/d5hAEdYmgynCY49gNXV55ehV1UqzFoEfZVM9j5hUg== ------END RSA PRIVATE KEY----- diff --git a/_examples/http-server/http3-quic/main.go b/_examples/http-server/http3-quic/main.go deleted file mode 100644 index 54eebfbc..00000000 --- a/_examples/http-server/http3-quic/main.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - - "github.com/lucas-clemente/quic-go/http3" -) - -/* - $ go get -u github.com/lucas-clemente/quic-go/... - # or if you're using GO MODULES: - $ go get github.com/lucas-clemente/quic-go@master -*/ - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.Writef("Hello from Index") - }) - - // app.Configure(iris.WithOptimizations, or any other core config here) - // app.Build() - // http3.ListenAndServe(":443", "./localhost.cert", "./localhost.key", app) - // OR: - app.Run(iris.Raw(func() error { - return http3.ListenAndServe(":443", "./localhost.cert", "./localhost.key", app) - })) -} diff --git a/_examples/http-server/iris-configurator-and-host-configurator/main.go b/_examples/http-server/iris-configurator-and-host-configurator/main.go deleted file mode 100644 index ddece844..00000000 --- a/_examples/http-server/iris-configurator-and-host-configurator/main.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.ConfigureHost(func(host *iris.Supervisor) { // <- HERE: IMPORTANT - // You can control the flow or defer something using some of the host's methods: - // host.RegisterOnError - // host.RegisterOnServe - host.RegisterOnShutdown(func() { - app.Logger().Infof("Application shutdown on signal") - }) - }) - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

Hello

\n") - }) - - app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed)) - - /* There are more easy ways to notify for global shutdown using the `iris.RegisterOnInterrupt` for default signal interrupt events. - You can even go it even further by looking at the: "graceful-shutdown" example. - */ -} diff --git a/_examples/http-server/listen-addr-public/main.go b/_examples/http-server/listen-addr-public/main.go deleted file mode 100644 index 1e17cd0e..00000000 --- a/_examples/http-server/listen-addr-public/main.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

Hello World!

") - - // Will print the ngrok public domain - // that your app is using to be served online. - ctx.Writef("From: %s", - ctx.Application().ConfigurationReadOnly().GetVHost()) - }) - - app.Listen(":8080", iris.WithTunneling, iris.WithLogLevel("debug")) - - /* The full configuration can be set as: - app.Listen(":8080", iris.WithConfiguration( - iris.Configuration{ - Tunneling: iris.TunnelingConfiguration{ - AuthToken: "my-ngrok-auth-client-token", - Bin: "/bin/path/for/ngrok", - Region: "eu", - WebInterface: "127.0.0.1:4040", - Tunnels: []iris.Tunnel{ - { - Name: "MyApp", - Addr: ":8080", - }, - }, - }, - })) - */ -} diff --git a/_examples/http-server/listen-addr/main.go b/_examples/http-server/listen-addr/main.go deleted file mode 100644 index 551fded8..00000000 --- a/_examples/http-server/listen-addr/main.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

Hello World!

") - }) - - // http://localhost:8080 - // Identical to: app.Run(iris.Addr(":8080")) - app.Listen(":8080") -} diff --git a/_examples/http-server/listen-addr/omit-server-errors/main.go b/_examples/http-server/listen-addr/omit-server-errors/main.go deleted file mode 100644 index d2a62a6e..00000000 --- a/_examples/http-server/listen-addr/omit-server-errors/main.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

Hello World!

") - }) - - err := app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed)) - if err != nil { - // do something - } - // same as: - // err := app.Listen(":8080") - // import "errors" - // if errors.Is(err, iris.ErrServerClosed) { - // [...] - // } -} diff --git a/_examples/http-server/listen-addr/omit-server-errors/main_test.go b/_examples/http-server/listen-addr/omit-server-errors/main_test.go deleted file mode 100644 index 89bc6bf9..00000000 --- a/_examples/http-server/listen-addr/omit-server-errors/main_test.go +++ /dev/null @@ -1,73 +0,0 @@ -package main - -import ( - "bytes" - stdContext "context" - "strings" - "testing" - "time" - - "github.com/kataras/iris/v12" -) - -func logger(app *iris.Application) *bytes.Buffer { - buf := &bytes.Buffer{} - - app.Logger().SetOutput(buf) - - // disable the "Now running at...." in order to have a clean log of the error. - // we could attach that on `Run` but better to keep things simple here. - app.Configure(iris.WithoutStartupLog) - return buf -} - -func TestListenAddr(t *testing.T) { - app := iris.New() - // we keep the logger running as well but in a controlled way. - log := logger(app) - - // close the server at 3-6 seconds - go func() { - time.Sleep(3 * time.Second) - ctx, cancel := stdContext.WithTimeout(stdContext.TODO(), 3*time.Second) - defer cancel() - app.Shutdown(ctx) - }() - - err := app.Listen(":9829") - // in this case the error should be logged and return as well. - if err != iris.ErrServerClosed { - t.Fatalf("expecting err to be `iris.ErrServerClosed` but got: %v", err) - } - - expectedMessage := iris.ErrServerClosed.Error() - - if got := log.String(); !strings.Contains(got, expectedMessage) { - t.Fatalf("expecting to log to contains the:\n'%s'\ninstead of:\n'%s'", expectedMessage, got) - } -} - -func TestListenAddrWithoutServerErr(t *testing.T) { - app := iris.New() - // we keep the logger running as well but in a controlled way. - log := logger(app) - - // close the server at 3-6 seconds - go func() { - time.Sleep(3 * time.Second) - ctx, cancel := stdContext.WithTimeout(stdContext.TODO(), 3*time.Second) - defer cancel() - app.Shutdown(ctx) - }() - - // we disable the ErrServerClosed, so the error should be nil when server is closed by `app.Shutdown` - // or by an external issue. - err := app.Listen(":9827", iris.WithoutServerError(iris.ErrServerClosed)) - if err != nil { - t.Fatalf("expecting err to be nil but got: %v", err) - } - - if got := log.String(); got != "" { - t.Fatalf("expecting to log nothing but logged: '%s'", got) - } -} diff --git a/_examples/http-server/listen-letsencrypt/main.go b/_examples/http-server/listen-letsencrypt/main.go deleted file mode 100644 index d49be671..00000000 --- a/_examples/http-server/listen-letsencrypt/main.go +++ /dev/null @@ -1,42 +0,0 @@ -// Package main provide one-line integration with letsencrypt.org -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.Writef("Hello from SECURE SERVER!") - }) - - app.Get("/test2", func(ctx iris.Context) { - ctx.Writef("Welcome to secure server from /test2!") - }) - - app.Get("/redirect", func(ctx iris.Context) { - ctx.Redirect("/test2") - }) - - // NOTE: This will not work on domains like this, - // use real whitelisted domain(or domains split by whitespaces) - // and a non-public e-mail instead or edit your hosts file. - app.Run(iris.AutoTLS(":443", "example.com", "mail@example.com")) - - // Note: to disable automatic "http://" to "https://" redirections pass - // the `iris.AutoTLSNoRedirect` host configurator to AutoTLS function, example: - /* - var fallbackServer = func(acme func(http.Handler) http.Handler) *http.Server { - // Use any http.Server and Handler, as long as it's wrapped by `acme` one. - // In that case we share the application through non-tls users too: - srv := &http.Server{Handler: acme(app)} - go srv.ListenAndServe() - return srv - } - - app.Run(iris.AutoTLS(":443", "example.com", "mail@example.com", - iris.AutoTLSNoRedirect(fallbackServer))) - */ -} diff --git a/_examples/http-server/listen-tls/main.go b/_examples/http-server/listen-tls/main.go deleted file mode 100644 index 50d56540..00000000 --- a/_examples/http-server/listen-tls/main.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.Writef("Hello from the SECURE server") - }) - - app.Get("/mypath", func(ctx iris.Context) { - ctx.Writef("Hello from the SECURE server on path /mypath") - }) - - // Start the server (HTTPS) on port 443, - // and a secondary of (HTTP) on port :80 which redirects requests to their HTTPS version. - // This is a blocking func. - app.Run(iris.TLS("127.0.0.1:443", "mycert.crt", "mykey.key")) - - // Note: to disable automatic "http://" to "https://" redirections pass the `iris.TLSNoRedirect` - // host configurator to TLS function, example: - // - // app.Run(iris.TLS("127.0.0.1:443", "mycert.crt", "mykey.key", iris.TLSNoRedirect)) -} diff --git a/_examples/http-server/listen-tls/mycert.crt b/_examples/http-server/listen-tls/mycert.crt deleted file mode 100644 index 9db93b09..00000000 --- a/_examples/http-server/listen-tls/mycert.crt +++ /dev/null @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIUfwMd9auWixp19UnXOmyxJ9Jkv7IwDQYJKoZIhvcNAQEL -BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM -GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA2MjUwOTUxNDdaFw0yMTA2 -MjUwOTUxNDdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw -HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQDlVGyGAQ9uyfNbwZyrtYOSjLpxf5NpNToh2OzU7gy2 -OexBji5lmWBQ3oYDG+FjAkbHORPzOMNpeMwje+IjGZBw8x6E+8WoGdSzbrEZ6pUV -wKJGKEuDlx6g6HEmtv3ZwgGe20gvPjjW+oCO888dwK/mbIHrHTq4nO3o0gAdAJwu -amn9BlHU5O4RW7BQ4tLF+j/fBCACWRG1NHXA0AT8eg544GyCdyteAH11oCDsHS8/ -DAPsM6t+tZrMCIt9+9dzPdVoOmQNaMMrcz8eJohddRTK6zHe9ixZTt/soayOF7OS -QQeekbr3HPYhD450zRVplLMHx7wnph/+O+Po6bqDnUzdnkqAAwwymQapHMuHXZKN -rhdfKau3rVo1GeXLIRgeWLUoxFSm4TYshrgt+0AidLRH+dCY7MS9Ngga/sAK3vID -gSF75mFgOhY+q7nvY9Ecao6TnoNNRY29hUat4y0VwSyysUy887vHr6lMK5CrAT/l -Ch8fuu20HUCoiLwMJvA6+wpivZkuiIvWY7bVGYsEYrrW+bCNN9wCGYTZEyX++os9 -v/38wdOqGUT00ewXkjIUFCWbrnxxSr98kF3w3wPf9K4Y40MNxeR90nyX4zjXGF1/ -91msUh+iivsz9mcN9DK83fgTyOsoVLX5cm/L2UBwMacsfjBbN4djOc5IuYMar/VN -GQIDAQABo1MwUTAdBgNVHQ4EFgQUtkf+yAvqgZC8f22iJny9hFEDolMwHwYDVR0j -BBgwFoAUtkf+yAvqgZC8f22iJny9hFEDolMwDwYDVR0TAQH/BAUwAwEB/zANBgkq -hkiG9w0BAQsFAAOCAgEAE2QasBVru618rxupyJgEHw6r4iv7sz1Afz3Q5qJ4oSA9 -xVsrVCjr3iHRFSw8Rf670E8Ffk/JjzS65mHw6zeZj/ANBKQWLjRlqzYXeetq5HzG -SIgaG7p1RFvvzz3+leFGzjinZ6sKbfB4OB72o2YN+fO8DsDxgGKll0W4KAazizSe -HY9Pgu437tWnwF16rFO3IL47n5HzYlRoGIPOpzFoNX5+fyn9GlnKEtONF2QBKTjY -rdjvqFRByDiC74d8z/Yx8IiDRn1mTcG90JLR9+c6M7fruha9Y/rJfw+4AhVh5ZDz -Bl9rGPjwEs5zwutYvVAJzs7AVcighYP1lHKoJ7DxBDQeyBsYlUNk2l6bmZgLgGUZ -+2OyWlqc/jD2GdDsIaZ4i7QqhTI/6aYZIf5zUkblKV1aMSaDulKxRv//OwW28Jax -9EEoV7VaFb3sOkB/tZGhusXeQVtdrhahT3KkZLNwmNXoXWKJ5LjeUlFWJyV6JbDe -y/PIWWCwWqyuFCSZS+Cg3RDgAzfSxkI8uVZ+IKKJS3UluDX45lxXtbRrvTQ+oDrA -6ga5c1Vz9C4kn1K5yW4d7QIvg6vPiy7gvl+//sz9oxUM3yswInDBY0HKLgT0Uq9b -YzLDh2RSaHsgHMPy2BKqR+q2N+lpg7inAWuJM1Huq6eHFqhiyQkzsfscBd1Dpm8= ------END CERTIFICATE----- diff --git a/_examples/http-server/listen-tls/mykey.key b/_examples/http-server/listen-tls/mykey.key deleted file mode 100644 index 39f7b3af..00000000 --- a/_examples/http-server/listen-tls/mykey.key +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -W2TzuSMYNDu876twbTVQJED3mwOAQ3J7 ------END PRIVATE KEY----- diff --git a/_examples/http-server/listen-unix/main.go b/_examples/http-server/listen-unix/main.go deleted file mode 100644 index 73096504..00000000 --- a/_examples/http-server/listen-unix/main.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/core/netutil" -) - -func main() { - app := iris.New() - - l, err := netutil.UNIX("/tmpl/srv.sock", 0666) // see its code to see how you can manually create a new file listener, it's easy. - if err != nil { - panic(err) - } - - app.Run(iris.Listener(l)) -} diff --git a/_examples/http-server/notify-on-shutdown/main.go b/_examples/http-server/notify-on-shutdown/main.go deleted file mode 100644 index b35a4818..00000000 --- a/_examples/http-server/notify-on-shutdown/main.go +++ /dev/null @@ -1,59 +0,0 @@ -package main - -import ( - "context" - "time" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

Hello, try to refresh the page after ~5 secs

") - }) - - app.Logger().Info("Wait 5 seconds and check your terminal again") - // simulate a shutdown action here... - go func() { - <-time.After(5 * time.Second) - timeout := 10 * time.Second - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - // close all hosts, this will notify the callback we had register - // inside the `configureHost` func. - app.Shutdown(ctx) - }() - - // app.ConfigureHost(configureHost) -> or pass "configureHost" as `app.Addr` argument, same result. - - // start the server as usual, the only difference is that - // we're adding a second (optional) function - // to configure the just-created host supervisor. - // - // http://localhost:8080 - // wait 10 seconds and check your terminal. - app.Run(iris.Addr(":8080", configureHost), iris.WithoutServerError(iris.ErrServerClosed)) - - time.Sleep(500 * time.Millisecond) // give time to the separate go routine(`onServerShutdown`) to finish. - - /* See - iris.RegisterOnInterrupt(callback) for global catch of the CTRL/CMD+C and OS events. - Look at the "graceful-shutdown" example for more. - */ -} - -func onServerShutdown() { - println("server is closed") -} - -func configureHost(su *iris.Supervisor) { - // here we have full access to the host that will be created - // inside the `app.Run` function or `NewHost`. - // - // we're registering a shutdown "event" callback here: - su.RegisterOnShutdown(onServerShutdown) - // su.RegisterOnError - // su.RegisterOnServe -} diff --git a/_examples/http-server/socket-sharding/main.go b/_examples/http-server/socket-sharding/main.go deleted file mode 100644 index bd5d7e4a..00000000 --- a/_examples/http-server/socket-sharding/main.go +++ /dev/null @@ -1,21 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12" -) - -func main() { - startup := time.Now() - - app := iris.New() - app.Get("/", func(ctx iris.Context) { - s := startup.Format(ctx.Application().ConfigurationReadOnly().GetTimeFormat()) - ctx.Writef("This server started at: %s\n", s) - }) - - // This option allows linear scaling server performance on multi-CPU servers. - // See https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/ for details. - app.Listen(":8080", iris.WithSocketSharding) -} diff --git a/_examples/i18n/hosts b/_examples/i18n/hosts deleted file mode 100644 index fb394e4b..00000000 --- a/_examples/i18n/hosts +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 1993-2009 Microsoft Corp. -# -# This is a sample HOSTS file used by Microsoft TCP/IP for Windows. -# -# This file contains the mappings of IP addresses to host names. Each -# entry should be kept on an individual line. The IP address should -# be placed in the first column followed by the corresponding host name. -# The IP address and the host name should be separated by at least one -# space. -# -# Additionally, comments (such as these) may be inserted on individual -# lines or following the machine name denoted by a '#' symbol. -# -# For example: -# -# 102.54.94.97 rhino.acme.com # source server -# 38.25.63.10 x.acme.com # x client host - -# localhost name resolution is handled within DNS itself. -# 127.0.0.1 localhost -# ::1 localhost -127.0.0.1 mydomain.com -127.0.0.1 en.mydomain.com -127.0.0.1 el.mydomain.com -127.0.0.1 el-gr.mydomain.com -127.0.0.1 zh.mydomain.com \ No newline at end of file diff --git a/_examples/i18n/locales/el-GR/locale_el-GR.ini b/_examples/i18n/locales/el-GR/locale_el-GR.ini deleted file mode 100644 index a99e7fcc..00000000 --- a/_examples/i18n/locales/el-GR/locale_el-GR.ini +++ /dev/null @@ -1 +0,0 @@ -hi = γεια, %s \ No newline at end of file diff --git a/_examples/i18n/locales/el-GR/locale_multi_first_el-GR.ini b/_examples/i18n/locales/el-GR/locale_multi_first_el-GR.ini deleted file mode 100644 index cf043c86..00000000 --- a/_examples/i18n/locales/el-GR/locale_multi_first_el-GR.ini +++ /dev/null @@ -1 +0,0 @@ -key1 = αυτό είναι μια τιμή από το πρώτο αρχείο: locale_multi_first \ No newline at end of file diff --git a/_examples/i18n/locales/el-GR/locale_multi_second_el-GR.ini b/_examples/i18n/locales/el-GR/locale_multi_second_el-GR.ini deleted file mode 100644 index 6569d65b..00000000 --- a/_examples/i18n/locales/el-GR/locale_multi_second_el-GR.ini +++ /dev/null @@ -1 +0,0 @@ -key2 = αυτό είναι μια τιμή από το δεύτερο αρχείο μετάφρασης: locale_multi_second \ No newline at end of file diff --git a/_examples/i18n/locales/en-US/locale_en-US.ini b/_examples/i18n/locales/en-US/locale_en-US.ini deleted file mode 100644 index b2a39433..00000000 --- a/_examples/i18n/locales/en-US/locale_en-US.ini +++ /dev/null @@ -1 +0,0 @@ -hi = hello, %s \ No newline at end of file diff --git a/_examples/i18n/locales/en-US/locale_multi_first_en-US.ini b/_examples/i18n/locales/en-US/locale_multi_first_en-US.ini deleted file mode 100644 index 9e264821..00000000 --- a/_examples/i18n/locales/en-US/locale_multi_first_en-US.ini +++ /dev/null @@ -1 +0,0 @@ -key1 = this is a value from the first file: locale_multi_first \ No newline at end of file diff --git a/_examples/i18n/locales/en-US/locale_multi_second_en-US.ini b/_examples/i18n/locales/en-US/locale_multi_second_en-US.ini deleted file mode 100644 index 97826b69..00000000 --- a/_examples/i18n/locales/en-US/locale_multi_second_en-US.ini +++ /dev/null @@ -1 +0,0 @@ -key2 = this is a value from the second file: locale_multi_second \ No newline at end of file diff --git a/_examples/i18n/locales/zh-CN/locale_zh-CN.ini b/_examples/i18n/locales/zh-CN/locale_zh-CN.ini deleted file mode 100644 index 0a7c91b0..00000000 --- a/_examples/i18n/locales/zh-CN/locale_zh-CN.ini +++ /dev/null @@ -1 +0,0 @@ -hi = 您好,%s \ No newline at end of file diff --git a/_examples/i18n/main.go b/_examples/i18n/main.go deleted file mode 100644 index e0a859b4..00000000 --- a/_examples/i18n/main.go +++ /dev/null @@ -1,95 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func newApp() *iris.Application { - app := iris.New() - - // Configure i18n. - // First parameter: Glob filpath patern, - // Second variadic parameter: Optional language tags, the first one is the default/fallback one. - err := app.I18n.Load("./locales/*/*.ini", "en-US", "el-GR", "zh-CN") - if err != nil { - panic(err) - } - // app.I18n.LoadAssets for go-bindata. - - // Default values: - // app.I18n.URLParameter = "lang" - // app.I18n.Subdomain = true - // - // Set to false to disallow path (local) redirects, - // see https://github.com/kataras/iris/issues/1369. - // app.I18n.PathRedirect = true - // - // See `app.I18n.ExtractFunc = func(ctx iris.Context) string` or - // `ctx.SetLanguage(langCode string)` to change the extracted language from a request. - - app.Get("/", func(ctx iris.Context) { - hi := ctx.Tr("hi", "iris") - - locale := ctx.GetLocale() - - ctx.Writef("From the language %s translated output: %s", locale.Language(), hi) - }) - - app.Get("/some-path", func(ctx iris.Context) { - ctx.Writef("%s", ctx.Tr("hi", "iris")) - }) - - app.Get("/other", func(ctx iris.Context) { - language := ctx.GetLocale().Language() - - fromFirstFileValue := ctx.Tr("key1") - fromSecondFileValue := ctx.Tr("key2") - ctx.Writef("From the language: %s, translated output:\n%s=%s\n%s=%s", - language, "key1", fromFirstFileValue, - "key2", fromSecondFileValue) - }) - - // using in inside your views: - view := iris.HTML("./views", ".html") - app.RegisterView(view) - - app.Get("/templates", func(ctx iris.Context) { - ctx.View("index.html", iris.Map{ - "tr": ctx.Tr, // word, arguments... {call .tr "hi" "iris"}} - }) - - // Note that, - // Iris automatically adds a "tr" global template function as well, - // the only difference is the way you call it inside your templates and - // that it accepts a language code as its first argument: {{ tr "el-GR" "hi" "iris"}} - }) - // - - return app -} - -func main() { - app := newApp() - - // go to http://localhost:8080/el-gr/some-path - // ^ (by path prefix) - // - // or http://el.mydomain.com8080/some-path - // ^ (by subdomain - test locally with the hosts file) - // - // or http://localhost:8080/zh-CN/templates - // ^ (by path prefix with uppercase) - // - // or http://localhost:8080/some-path?lang=el-GR - // ^ (by url parameter) - // - // or http://localhost:8080 (default is en-US) - // or http://localhost:8080/?lang=zh-CN - // - // go to http://localhost:8080/other?lang=el-GR - // or http://localhost:8080/other (default is en-US) - // or http://localhost:8080/other?lang=en-US - // - // or use cookies to set the language. - app.Listen(":8080", iris.WithSitemap("http://localhost:8080")) -} diff --git a/_examples/i18n/main_test.go b/_examples/i18n/main_test.go deleted file mode 100644 index f625c29c..00000000 --- a/_examples/i18n/main_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package main - -import ( - "fmt" - "strings" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestI18n(t *testing.T) { - app := newApp() - - const ( - expectedf = "From the language %s translated output: %s" - - enUS = "hello, iris" - elGR = "γεια, iris" - zhCN = "您好,iris" - ) - - var ( - tests = map[string]string{ - "en-US": fmt.Sprintf(expectedf, "en-US", enUS), - "el-GR": fmt.Sprintf(expectedf, "el-GR", elGR), - "zh-CN": fmt.Sprintf(expectedf, "zh-CN", zhCN), - } - - elgrMulti = fmt.Sprintf("From the language: %s, translated output:\n%s=%s\n%s=%s", "el-GR", - "key1", - "αυτό είναι μια τιμή από το πρώτο αρχείο: locale_multi_first", - "key2", - "αυτό είναι μια τιμή από το δεύτερο αρχείο μετάφρασης: locale_multi_second") - enusMulti = fmt.Sprintf("From the language: %s, translated output:\n%s=%s\n%s=%s", "en-US", - "key1", - "this is a value from the first file: locale_multi_first", - "key2", - "this is a value from the second file: locale_multi_second") - ) - - e := httptest.New(t, app) - // default should be en-US. - e.GET("/").Expect().Status(httptest.StatusOK).Body().Equal(tests["en-US"]) - - for lang, body := range tests { - e.GET("/").WithQueryString("lang=" + lang).Expect().Status(httptest.StatusOK). - Body().Equal(body) - - // test lowercase. - e.GET("/").WithQueryString("lang=" + strings.ToLower(lang)).Expect().Status(httptest.StatusOK). - Body().Equal(body) - - // test first part (e.g. en instead of en-US). - langFirstPart := strings.Split(lang, "-")[0] - e.GET("/").WithQueryString("lang=" + langFirstPart).Expect().Status(httptest.StatusOK). - Body().Equal(body) - - // test accept-language header prefix (i18n wrapper). - e.GET("/"+lang).WithHeader("Accept-Language", lang).Expect().Status(httptest.StatusOK). - Body().Equal(body) - - // test path prefix (i18n router wrapper). - e.GET("/" + lang).Expect().Status(httptest.StatusOK). - Body().Equal(body) - - // test path prefix with first part. - e.GET("/" + langFirstPart).Expect().Status(httptest.StatusOK). - Body().Equal(body) - } - - e.GET("/other").WithQueryString("lang=el-GR").Expect().Status(httptest.StatusOK). - Body().Equal(elgrMulti) - e.GET("/other").WithQueryString("lang=en-US").Expect().Status(httptest.StatusOK). - Body().Equal(enusMulti) - - // test path prefix (i18n router wrapper). - e.GET("/el-gr/other").Expect().Status(httptest.StatusOK). - Body().Equal(elgrMulti) - e.GET("/en/other").Expect().Status(httptest.StatusOK). - Body().Equal(enusMulti) - - e.GET("/el-GRtemplates").Expect().Status(httptest.StatusNotFound) - e.GET("/el-templates").Expect().Status(httptest.StatusNotFound) - - e.GET("/el/templates").Expect().Status(httptest.StatusOK).Body().Contains(elGR).Contains(zhCN) -} diff --git a/_examples/i18n/views/index.html b/_examples/i18n/views/index.html deleted file mode 100644 index 32bc8a6b..00000000 --- a/_examples/i18n/views/index.html +++ /dev/null @@ -1,9 +0,0 @@ -

Test translate current locale template function [dynamic] ("word", arguments...)
call .tr "hi" "iris"

- -{{call .tr "hi" "iris"}} - -
- -

Test translate of any language template function [static] ("language", "word", arguments...)
tr "zh-CN" "hi" "iris"

- -{{tr "zh-CN" "hi" "iris"}} \ No newline at end of file diff --git a/_examples/kafka-api/0_docs.png b/_examples/kafka-api/0_docs.png deleted file mode 100644 index 2c81a744de08ae097b2d3021e52e9f733f9719a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29953 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 VaNVr>)4y{}locTgMRIQf{|7dqf589% diff --git a/_examples/kafka-api/1_create_topic.png b/_examples/kafka-api/1_create_topic.png deleted file mode 100644 index 15f172d6bbf08418a50771ec2eda0103b74d0454..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26684 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 z 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%0D`= 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 R=^$i57#jkef71T;zW^IM;U)k8 diff --git a/_examples/kafka-api/3_store_to_topic.png b/_examples/kafka-api/3_store_to_topic.png deleted file mode 100644 index c0fc81142e25088d685ec7d1ddcd032b5f606708..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38028 zcmcG$by!yK)-}4Y0R;m=8kBD725FHJkPeaV25D46xl}!tpKEz$miiSh1NoB)u6$7Akfn z^_tK_5xIL?{&zD}1;0qXx`%QvYDU!GpLJe-FHM4tBvDa<)JxEL!fUV7;H2ZQWqYGC zlkxejnG+XRB1gmSB&Wp$+=E0GLyAbrj4NJug>I30$x&KWYap-p9Uj3y;45dHuQ7uD zeJ50h$ye;(7h9PKb{ga2;*O7<%he`odq^&S(Eelld|Yg-s+wAbw$$ScfsYDW9RvK4 zPeUk+h?-kXsZ&KOl}`%Y$Aff_7Os3rWM-A7jgkx!Yhsd>d@(pUsHS4)VG3{kPEhdW zdijlSD4ua~co@FA`uYRw)+Bx+Zww8G#$LiZIUk>;yIZs31u4>8_dMuZdbk)VU}!?5 zEa#ytkeP$)sTpx?J@O?L7G9@78hM*%i5%5h5g9tNvbyTR`}p!kQ!TzvTS-YtaZA0P zu{pnItUZ+2wULr~PKwIf(-x%v?Sk3j-;Xt-WBB&zTA^eoxr!TJHqj_BUr-i7XDZAHb;jdDW^=H|vH zk9<^%-*}6qFP|!pVwSk^Va-KU%=WO>dt97nyoh1YsIqDaCPed2t9)_=`8(}P%%D{# zp%oJunWt91GTr1`kAGh%+cyuN-sJd4ucXMn14%Z%m2<($b#(03c^l*|1V{1Pwc%nN z9i6!+K05z-wy2#Q8>FbT6rbD9$j**c^sHJrQNZJTXTF_{jZI8UOiN4a0i{fx^Zv@w z?qa-n_w?FmdF~>6s-tGT^T5Q!#J6uKNJ&WvGc)u1_wTtc_PxBktY?2NYl(}A9Y{om zNP4W=+1T1fL_`Su{d4u5pw-L|KW&dQ`{TXkp+ap&TH3KP;|QVDVfZut@-^m-j`P>` z{CI!0Ty4F=d`wRCwehnVzKG|yp7S~`J^n7gr{Hl8NV?PQ9!f*$B%E1 z=3}@By53#A3ERo)ur@r2v2rmmI0%=p?MmQcXJ@Y`L_cl`lgtRfVT6C(Kx}Pyi*;Kt z9x_=y3 zKKzC?-zVX#o*zCm73nnL;p1CQ)>Ydsc9Fk`-dpawiMYe2!ak3TjNHLz4{Uy;uct@A zZI}J|vmPuLVs*4LpDrG9d~$+Gz**GLaK157d*xkJzVzLK66VqL!!g6X7erIXP2r)7;%FfQ-+TJGJrz9h*J6ec8HjQkb zhcnUOals$ZjK^(9)kgNnhs$=MV<1;KN>X1$3$;oZ4S5CR_v{4om6g++URNMVXzm%WcykIH>p7>rs zvtd_4wfk9(QttllZalkroFGYSXQz3&aHaW}n9RNB5fHdBI-jT&GXMVlyEaiya!ADQ%IW&oDo89MEUagEnDgz{pO@)kgs@svSTdiO zP!OZI%Li!*A)eYNA-~`D?ZZv-`=~MPnq@{|iHV8l!9ylbBG6b^ST^BZ;OHt1p(A?4 zvsRqb)6*IZIEW(6z)W+1CE&d;ItAXxhoaRESf3@aY@C<2>Vcfy3^j!(6Bm~AJ1)1V>}62t+4Uj z`DY+*r`TBxo$4DXOzyLld4^}l`*W*k-ZN7d=ZBHh3U&g#kO>>CXKyqyH9-h*+32+g ztJgc1KQr{XRo*>3{1z^WgeE69nvbz7D=WLWoJ?YTar`?{6e7z(otIvz5rw~-{mg^Pi50t~~RG*L5lb>%2H(uIYL zhy+>q>FFu##*0KaC0goFi=WX zmNFIvVP$2-!og|W`9+IBk%~`BYH;2+fxHHf?|!_T1rPkdPXrdT#`*`mii((+3$*3s zzt7t|mr1wXTYCB6K|~Nf2Tjy3di4qwRn`5?DFFyWdV2HDI5wfwqT=Fv2pv5=;1zo8 z02XHEU_zcjI$sOiijWZ5TsAmsd;3G$j&^pDZF*Ruej<<0@@?(xu+Y4b->?&XS+W;9 z?Ti){7K`1<9_!^pNJ?6o5Kf&6T~|lPHP5A`B`9jR`1tMfaGZDAA}EK3h5|$$^CuV5 zs%mLLiV%p)w47?-vz`&TtTeMfgLV%N3JMFgOAR{zeET3REsa7VAmB0m-J1@3^>?Z; zoRwHsFDTSGacMI zI=whu6o9a&Tnx&0$S$bRZ3#xb_Fg)ky@xfw$4DlL7x(`C`wt$Z_ZZo!rnrYd)rQ{@ z4Zt247^uHEKbdU_@qlyl5Utt&A?*!JB7%nx%WW5B!u|CP4Fj5IK7IN$K0aP>?RnoG ztX-1JM)mpG2?slS_Z|mOi~`m(*Pdf{Cktq6!p>Xwo88Pb zc3$jCjG&aoKtrp6a|eY5n_f*sQb|$q5=cPy7<4;a8!2UuT^mr=zU~S4194zET$EZ@ zcN)Oh@OLgkHZ3h}W_I@ZMto!>*1dbvtE;&$JofE}|8}mBPW76U*E+1@G3(vpT78lX zY2SV8+f7z!xWKoGiF*AOohw1kA8TuCb8}5aMZN3m&&o}Qx)OP^lyaq|q!zjoO?7pl z%(~3~dWeo503{6;jEj}EY@pch>({Tfj+=x1{hT~JP`Z=2Y{fF~7U zJYAw$)n#f8YSM4Q7vPwrGUHdKAN^3OllPKX-QhW3J>|>o0sHHS6vm7j$H?Cd;okCe zQFr#W@7&IvTqA9H0=uoMXGiV6==9!sRRs1r`4vaMY6g;Uf--%#;^}$q)VU5RRlD=c z>gp0Qmth|aa9D7CssYBiyEiD(JVf(GK|z7!1z~h@u)e#y`{aleIXyqw1bp=tg0)Ix zV}EssnD?ziJn{+(D6hw>tjXTpKrnoTgKNer zEw6g2&!Kp z{tUe5CxRs!`{@(nSzXN)oAGCJbBfu`m~BnT6g!|fhEY3OG6Ue&@d)WXEG!Y9Zh$49 zp6UWdE3us7XJlk7G0BjBE=G*v*)mHVC0R24?b|m>nFLPv)4y<-u3vfQ{`4$7HZ~T{ zFI)xr`leXo0sM1hY;35%KlD4~y}39sz;`18`^$Kx04QrF!aInJb3dq=+xC8cA|8x& z>l&7*^e3iwtQciIsmD`soYs%yI~Q!Kg;M3{u(LjYj*N-1;x=K3;L> zQP;FoQ&YP*KWj7i`Qt~K$8ydH1}xckgVN_`FJHcdeELM8GB-E3@%(sIwbUSt5P(od zX69sro6BIH>Kqx_)2G|9hDj)hi;GLK3Sb^$T-?~`Xt9P#lk{cNtnINci*Uj+GBS>L zOCQ|7FBXK?JiC4E%Com`-@?lH68g$j{x&Ih+!%*!LmDHZp{WUrf4-cRdbhsB5>WICSBx?RBD|4QS@CcrfS!sUuIK^^jJ+t2%8A-5z&OTf6zK8R&jTiKUNki{yo9D9 z9RO&=foOQ}pbtvy&fN147HB3pSq~bM2z`}uAx#eK@9#ryM)CCYgr>T(os~zG6esY@ zmoLa`cmpVBQ-DtZq{F&C#KZd%PdOplEpTxPiSiZALuBi19RSA$^)Kt#dYNcQ(TLeu zY*qf_^a?LH1RGOyX(c7{If~poJXet>rna^=Xq$!@1r7L@Y*f+F(QO)`1=B1I%Xc~4 z(5$k0SEge4-6D4Z4p{=^T)_NpCkKhVPR!L}Q}PA|3jksV^VM7CZ9)jRY?gkf!oSh3 zU8&ZPxe+*T!-Z?iZ$0A$twoWJu&{7bfo82y+`-`?C8e>K1_NdBvTR#^ULLR8F)ONH zN3-Q%(mF?Gety26-*b0&{`gL8H1AHI1A90fX$=ipj!NccW_dkE5~KYxzTp()i--uE zrI_}Ka?==Z@8)*KMmp?({SRbz^Qv^w1?ANKk82_2D+&p{4+wanrZ$SsSoeFMM16yc z9zS(JY%p1Ta>W@R56=#ri$JFR0n_i=TfgZ7M@L8f{m~|*gY>LM$H#f8sf_{a&bfNB zwnN83M@QGn^+_nz$i!r{NayNNWF3IngRQM9+r{9hsE5hjP%0sTYn4_LKuDICl)QJq zZ`9|T>qEJE1F%G%b|XItiRYfKx%oPDiXntNHxRra3cw@WE1X_6*~P`yZQ|*(8a;Q z3BMZpE(-MlMd)@MWoMLYr}EH4^c$!@kGC9t(jHJy$Mqw~?oG5up2``X0_)> zp`qY7zba!uE0u#d|r-c?`k5fQ& zSyHjRD^4#ZB_$yy+afY$5^L<1d*LwnH^1={5elcD2$-9jYYxCERiT6S6}IVgyM_4b zjoWg$15i)rR`2`$XlW78Q8duk@BH-iLw_S2KLEI4-+G`^EH~?3Suxou^vDfDMZ&_u zAZrp}h&w)P$S^Q3XoPjhtiiT0Gt(;_(QC2D5^k%?v#9+DZ6dq?X>W{_8Ui@&eD5{r zKApEuzfObI5Qk7Far!1G zGmchPMn|vj3J3_Cg`wsv)xK%=2hN3pfx)6b`{k8)f@JseRZBBR8o55)xFabgRaRa; z&^g^RKhjw?b%~i^58(xiat!FJK&w6u*tht2**Mmmk?R}LPz^Yk+1V|eOk3vLV*tN) zG6hOe^buA=fv-8M%P;mj=$_-@D(VfG6zH?#d{wQNZPldG^ZnWT#e)~6H09@SDm<^g zB34`Re>l`rGZcG)j}#cEp?r;$Me)pfSS$ZC^co&w5oO}c?MvZgd+N%9JlZuEuAi~) z_y)kGC?upCxFyT+sxTl4$8EcT6#O!<5*Zo!{ku@Cl$cmz8?UjWqa#BMpv2Xgneh1d z_IVpVUS3GYMsYH*cu-L1$9qr20v~P9O&!5b(uGN=HQexoo+LbX z+R4cYO1hrp2GA6(S10xgciC%y$cEI`-Z-JS!va|b4MZ?Ov2V@MZ^y2*dLu_myKe942Z``=CVsPhqhJ5(@%QIe9 zrigP8MXL<0j8ZP2%Ym7dRna*%Tdk2y!I!M8tjY*s4pZAR`k=r-UXSxSq14xp768fj z4UC)ku6X(QoF9x?>M`3vkx*5|Ju-xrJwKupJq|i6YX=8@`;|xw+L}k7OG``TbI5Fq z=PnVEQT1$jU+a1v2V@-RT=aed3V3{SBfgXU=~Gh7S(m?CIx;fB1*vl9Ez5&a-FFL`6mQES@jM*JL=X_yq>q zIXFN>)M<0B1)HJDf_!;(dNpm0j@!*$7q=+11k7n?-an=4pdi>(z zd6LwGbA{w8z0%>D-I74q5kCE*{T`LN`q)$5pHfM@syT`j6cks!0*nA&4%%R?x6{|p z@Pj0J6Jlb-DQw<4IazZOFf-rB#%6zoS&fnt;LNbSI$~|4pr9~8&&&;&wejp=3{n&P zZmU8uD_&=gLKforS)5gR)qw9{b!Zd7?D5stnpw3^FHkwmhKmS!9LDRMY$xlS-o1N= z!>C18NyWv@4Nxuf^JfA+=g8(aKpFW4${83MqI(N5#L(XNYaRJ0mi}B;)?+y%MokGe zuwU300{~rM_aY`Pv)5^YxTxr>SFhamdc=VlV`jEl>CXYyLjz!3PR=si0FVVd4;*sY zTAG`IC*FR`Yieq0la+El7zLm&GEzibJmk^SnXTz2V%IGc(U;iR*uW4WOt4Gg;rE$o zFLBbGd!DkE(>z=ZC<5fq{JdyESKVIkiz&CmiE#24B9D9WR7(Mr3JHCO!)I4q|92(; zI=lO~t|cWU9jkt9Y`lQe2@t{6&8EPdRBDNuK^Q9D;IMKM-mPwU%s56v6;drMqB!`pbQM%_t# z=-6~i(Ig{g2f+Ru!H*O0z76eOyxbgm$GQqU)vSSiZfR}RkCMI8Ah^cRUwXEMC#1uHSf{6Fg5fT<|>kQ-K;sS!h&D_SL9~H zi3RlA&=vDL?=3;&U8a_=LZ?+_Me5r`s*nq~kDi`B6@9eO5LiwqY1UH>ZYPJE+Un}H zI!!mcg>>}vSWO4%n6C}z&E8#kDWB8d->*n=H(T)w6qCwVnb5r+Jbd`Dx~d95$gf|& zECQKew6*&xgPB|?mMiUc)vhWKODhv!b-dLiL0VAWM zF@W7Y{SKUG8$3!+PZ%^f&|gJIGiW!AH#L25b%ZM^7ivw^yHuuj&o4c^@Ar9ZjGcqy z5U@1`?!%Ru%V@^uC{PvK=iHa{g)<3d7{Eeh#C+`|y+RI~N?;6ApaHXR)-LSVHEK!q zh%7jr0bv42lu*O5Wxzg(JdOZSKgGobKYIF@lyo}Lanksp@G>9)yGZ?{V8sK%Q$yX^eL=s2po!;g~k{G^~!I1!POK=6ZyY2a;#;~nK)HiYS0 zvdi4V2pmkwZoS+mnw%aTY|;!puE}|OrTX0)jCXCmISHHF_oYh}zn&|PEXpEkRk+Y` zvF(eWp!>WzT5bv_8t@eG;ZW^UQeFdt2P7b+Y!V$cH7@WazD?C`Ck}A3t*opR6|oSe z+ojM~hr71?{27jQ3Tg)~E-qvk*eA)1l9ZG`myGP-`G|kD)&7e{w7$f+^t41b69u_;8 zw;SJH9`cF0vOSSH->`M|BG4SHFH%r|Q>D|YQ#p*D`*wNwv-$ug(JzKCd#nPu8>&y@ zb+T#qmQ7jpUir2$K61~MDE?RBK!eK{;}+@bNMwKCY@?+Lhg#V(?vooNS!yTWsxgSX z668Ls?x^?G_IzhdV&jg;SKE3qTN#mD5swS7z5UlO5IBVU%5rjYHl8K|Zt@QZsCC}| z;^)_v^6bMNv5V--$jVAb6B82&iH{5~0I4v=w0CxOQFuK1(bkqzOGMox?9AkQ4vR5* z{4p&XItol;{<;BKVCDpXk*H|k0YV(oyo0dot+OY+c8uwizvVgJ%(Qipti(#6G?=C;4)_Ql2A zFJcALKg%;4848ppW^9(gBO(9bnR#4 z#oISWV=VIu^@QIac%^X<;L#yWEG(Z~453VFtlf4eWX1B` z#WZP?v7ozo$?KY$n1DDtU}BFczAsA_CgIF;4TRB)TNer11Pn2za4?OHN8F2pbpL9w zYy4MIZcL9ku@)d4`}VP3kVK9q3NOe{KkxDS2z zNN``5A)pC60N0L=mW}?S&>90s2CU+ z9zXux-yc~=PfH7gARg4XK@ zaHy*4>WAxNG2M%Y4swa|N=gfV{`@x6adUG6Hq6b9FTNAfSMbM=OGQcJ;~GI?v#YD7 zzx`{JH8c_~5vy2w4~YKA7TnC?;bwQ%yQ11n>%}`NHozckU2iWK~sFH4((k zHE4FE!i|p}jaYbOK!XYeLQ|E;nH7p_G2mFq3~sAGU*WvqFlY?d?`vnb@+&6T6{ZS( zdAV0<=hmky;gw-}Sdf+hNnci0Hb@L4%0zf$Xju>U@M>l9m8Ky5>ze>WJ-4{HI5+oM zDR*^sl}90}zMfCI&!-^UC5V9Q{-u=wbYJnnM>@Y9FRMHq-K8-imD1Pbur}e|#TzH@ zJqMD`oP$FB!vKSum@Z|7m9fG&*w{6-wK!N<5&-X0A*grW@>*J2B1UFrfgvFv6U{*~ zg*^g3=jZIU&u!c*7x>4$MyyZ)fgk22!bD0+O9TA@K4kX3^$N+wNALw9egDPg@~l20{I*&|CO=ILKQlTir&0DI(T<{ ze0%`$Nl99on$j;Lft(Bp!Bj1WBip7&6D676v$s0b{r&q)4_@vn+5P7R2AN8^ZRW%?|iBS+Owtliz!1wm!-=qE^(eSHrQi}9-I z`T3}@u+#yQOa3_K@+IEK>f40NX_X>J<$4<*=uFTEFbKItCIJMW{+$g$^Zwq|WdVY< zgM$MS8WB-y*i95AIlr**lj$~csoIgih@MAC8@>z5S#Mt-aAk1IurSax z)5o-nK7I-6umsr^Pq??WH8UR_C^WE8P!55~29$qES_lAB-UdxTPtQHIRmZbn2zLo- z=_ttzkJD}6pdjhjuTvPpK?m+V*I*bL9gU-llpq75_GOOZ<1iz*ht7(Eyu3i2M*;$k z@D`A|hKI9zjHvw4P*LyQx&|UkXvYI5F2m=q3{BCiHV8n z@po%_R)7G!Aj`rp(8>%O(rx=5<@=O4%t@VITG{>?h$!LV;c&248Ju9- zFahQ@O@IFUd2W9G=;-Jn4vw;t5-8yb@WrewLjwb7crX#N`+mN@Er6`3{eea&)jqt` z*LJRW;&WKQaYj7lsBU9of(R8YK?WG*O>xz{B(#RN`I7~l_l)3do*mnVNdUof4QXy} zhNhL5sIab%mxaX^O5((C8y_eelG4(I;3JSAla!I^YHI@mYTBlnpPwIg7tQ-I14CD5 zXHfTIRz?P#i#r6Iayg1x4X&zm*jELOjj4^rd~`r2)zi^=wjiTtU;rdKI2UpURsf@i z;Ia948no+`v_wCpiuwf&Jhbsw1Vu%gp}{@@mV9(%q`9R9dQ>M6Q=ilag!J|mOrFK@F(oB z0{~}bjg)FN&V6DxXXEtzc^kA(RT>OUOz==}w&4K4X2XF8B|$!i6;=VlMksX)_5?7; zx=62$Jp}SGp}C$O76AbPF|mN_-z|eFdpo;2(1hjWLM;qK+w>|er-)dMLg6yc-T1bbqf*L%IMN$O2ZltGHUj!pVt?>u@Q*35C=viP=uS z_;_lwNL*%7)(!L8;~J)b5{I=niECe<37XcD^CBshn!itX*bINkC&_X$v1*1MJ-TmX zMC%Lt4Eq99Y){X2h`{+$Ulyk5%f!5%iHXFfX$15t_yI&tO>Jd)`8oFS(GkdzNpru= z*lY8-g2~Cru|&ges~pZ6nwrwaw2!IU8yhbV7we*UHcdl!4j~wUx3<3CW>w|wEvl=l zOUdz>7P^i+)2DHn&uQR&7nYVJd`K@@_>vM=S63?k$JObABur1AhPBVT@@qd1aaM1@WX z7#1t5tw3BBgaqQ0nK?Yr4U9B@;P!y`zzY&1yB{WV2-h3B30dYXua<>HK~~mcXFP{` z(lFT&cDaUbMOjG}#|p35sa0gs$L9uifGD2V zZL>aBO)aercqRukS=nwL$BnWFvh4$^Dk^p*>2N!?Ha0*Bnpjv6-M#x-PftWiI+J@z z=GlIwOmbo(;Ru?zcni>T5obk}WzK&Au0y#yIXWs&s5t+Nc@r#lG{#---N6Lixa{6_ z`qdXs_vGW96l_f}sp6?<#Wx}|$ci&*{aITonb`Ed;#eoUM9d$?oLDWXTgRC;ZcUyF zxvX9>>Q4ajAf?_#VRwv3E>}hC+c*x+72mA-1MT(l3uZjFt)REI>~aeg>&-1pE831W znGNk5yNeQc+bQ!BZ^fp$e0h?rfJe^htk7|>z(5n<-%|Pey5qa{#fB}6cG@Zy`aWk2 zO+`h(i>(Q0ahU*H)X)6Pqc&Os)2Nt>OLB6a$K2d~%bTy1+hc^JE8d+Zra4Mt1k@CUX$sUbcL_dvZtj{9K5qm{5;PA0g%ClUFH#ikU0u=b z^ALk$sS>kG>|QOiVdJ6(Vby z>^8Ty1|p05#n~Y+OqY%bFwGq+=tD=>N|NgyZERs7qjejf9UN$;V9$V-g0b<`#&EDz zFrG)y5lBth_GR2TI&Y(qd(aJns}DhNaAN-ad40BHQ(Xr-Bm+Zm-MmdTlV%ZLX*(_(iXI9pik#8HYd4)$nsaiP^;&z7#u8?BAI z*l_&H6t}5dN?G>}<6|0aK)*KQH2wH9)zetPUZ>@iDUUy$Q)ocL4d|NCvbI!gVY`Z| z4uA0&&#rb&c(9+a@LlKpm+;s5rvvkZWWSNJ&z>)-?NIG*-s>$hx$qsQZdYkIi=8o> zkLFPQ)`TMHX2YRx(4@V8m7ZE|Q|+g=HS#wNLp?K!KrKg+ot0H8fitWQxD7yMSOLvg zqRa9s6R-Ysku1|a&j-QXDO{LmzOS#3kB_g-GeR;0nDt958mM?;>0EBdcJb=pr{%CR z=uX`?)ZlZ>>JKbq$-ncbro3PamLpgP}-I zq?BIoXTDHsmD6q}NKYr;wdeqFSPVLV`O#yBDx?ZT@@To_HY0^PTc#!6sVSe z1HoQp#Edg*oQk)%Q-5B>@D>v@1oj$o1%L9?&Knu^n;(TzNf?ddl&G*=`5SS3)71G~ z0nax!HUgxF-V4I@%GIm;l^MzymuLSMQ;_{@lL@m__F25zO*!V0_6?kTuF4SV_NzVy z!x|2PSV)nXriz=dNnfE=n)VeWvqH#aT6`n#PGs1K_R90d?;9MEC0JJxo*mrI*iD_k zimz?U+7^e;TI7`u2wNy~vpV8@hYY;b?%WDgZ8$^mv^mhPK0As}tG9nvbj*Ylt&LNe ziq|X=weyrUu~qK4F3rrmIXl@{Utb5@HDFQ>q$C61W8wa5G419a@4Z0Sl99o{)v9;g zBx=JMlUG%xj%efMw3u&P+HH+wEhMw-hVLCqNlSy}v*5w=n@|jZnGM%q2faHXP9Ccn zsuMp+M4Mg2XZ3;teQ`){-a^kXo)QL$0TC_CPzTorz7EPCn9AV3clHkq#ZUwxU`Jlq z+S+z@bU^XRrFG_2<8y7T#tmp@W?^}v{%dyIPTzUnO7K={R?yd5pUXRO29@6}UraTN z#E$&7$6T)QJzl2MH@LI^YOZ|Y^qClSmKQw*Nx!nO!i*xmVK#f09Pv>?Pqt_CLj69u z=BJEtCQaKT72lqhLb{=YWjoJu?@5}T-%rgUM?57lcEkoMDxW`+dPUtwwr*Abdxg^u zoUU)*R&CG+G~W+shDr}d?Y`e!Z^jD%%afB0Usk#uws&`5NJ`GwRGag8{~8%lrHBAb z_!3Ls++2F0xndp~IGgHIAg&OSySHxK!JC_zxsQX>GP@1BQR^Q&b=pfY3L+ht8wmW| zTw15hZxO;|_r1Nm$jHg5vC!D#*B2KdnPc6(8~W)}t3fG9=&ft!$kJHlCNwobLAEUJ zg4iJu4LE`-rkzo<=5vn`tfq>JN-0+gt2FpXVCAs`^i562`Y=g8Ty*+E@AK`O4gf<0 zw35T))j~jvAT;ZT>Pf=H-NIa>LptJ1=~OfjYmmkG_!3zaK^Ov12V^wN-M%+_SQEp-NTVdF{o#5mQ;h=8 z--8n=9(+G84B{v1&L;=vHp1|nk1jnB(f6o!^wg@E4;O?U1$G4FGJx_S zyZ>V8{#be;`#N*Wd7&&fd-3o27KnWTz1T5NrSzlr?=%yF%!?z{Qu@UUtvKVV$)_1a z3bYPCSQ1co_hMc~JB%A|KD{&W#ZpObP-e~Z;QZ|^{l%ZZZzo2Ky56@{zqgWz$y9O! zL6Yuz{jAHVeP=j4v8cE?N$GVy4V`A#r%zR|wv!m2ITHEZoPT`0Cp$`P+t$^UX;O6>vx|&L#yJtdkoL?9S4cqw*o({F#qcC$??b@E&h125JRVKXg;dnIkI`QxqclP z$YL3pT`W1lII`v63X*d$rZ8YOfa)`yu_V5eg=GKC%xk#@+*WQS9R84Yw*PKZlUG$?s>Xk9= zJ(KcZclxR?)V}SY8AuXQRW`IGHpCI~O1ZhBH&0trbX;Zk&7sNYFn`x%ZWuI|lyI;> z{-i%0Os^n=LGLm)_AX_RkCfv+Oi8SW(p4gptI0-PYp;_3aujhzW?bFu?2Igbve@h$ zSD*VRD!jzzPeTO;6*gj}rCrEXqPn}wemB-ClkUlb#0%wn@wQ4V?P+<153I9Ll zDgJMQ?OS8<`}5B#ym^(vOYZOKWB$WC-s1DN`XA;tvY}U+42A~ia)6}qCh!AD$|IlU zb%}p8=iOtTOIG&ZcmMZCLH>K|P0Ow?!QL7s0eg+|b$EEV>+)65a^-~QTl6z-&`=?J z!k_T^`R@f~4*squRF1dW6otDZLTP4_^7RIJ@;_Wt96h+*FmKnRZ z3yiU(iVs?2(1%F?M>cj`R!|`GIIQgWCAf1y9|PqNJT-?)C=TDjJ^_BwzVuw9fhUzx zn`y?*U=oH_daPJiyzp9RVj?*FS6YhF;31*&-k=|e{`pf(Gulimdj8_1u_?H4=i+Q? zL0?r*=h-uqSjKIyw{!J}88KQb#VP+bC@7e5C^{y_Q6*&nH4-#^Gz^R+uyITGg*?)9 zq@t(KFoq7kdd$>)E_zvWd3hNo8o)HOG2!m?3tS4JIB@AC4ves&v}2oYd|#XN%ptD7 z5zOxH?)BI++V-21E-U@i-a^|m0gMh@3=k7bo2jz|HBH}GVxl~l zIwB%oO1bMkMKvF|xASI}Vi1JpdJ)&x1;n#0s}aR_D7LWgp{Ss#>cIvd9@%9;)>>4V zXAjig2a`@X$Sldp9w7cgvjM{H2F$g9LbtEdXQ>7_oLk z=L{C#x8NoO!w`ttyP)Q2mFNMaeqMS-bIMg%J+q|5X5h=KWRLS|ux?J&Iy$b8?gKZn zvN6T&yq7JR5y$Vwjev3t6?3|iW9ph`H~$G84b93bBsMU^9=XCO$im7%?xiVRN9U!Y z;vVFOPqDG}Ti?-vccY0~0oySU2IpXq1;-V;1C%g$pwH*Pjl;f6Qbd5}=m@nKz6b=4 zxq$%%jCFu;0FLh0c?upfphM%HvF_&0|WVw{j7JY z1~he$7iHpDQITKm?a+=@fqf4qw00M})m2q53l3;RKz`QjKqm+0DxjT!!2zxrTC~fz zlA?fjgXK+?>xk#*Zf{3N!XqNU@2jG%ZE0#+YurbH`~`OeqefNAfXRpV?+w8Be)kqa z!oaWr`vM>cI3V81WUkBcqH-4zWJGt1Z+ z%=G~7f$j!Y({wOz1cs-|%h?cU(3a{CCrc|UDW@K@=;QjRf)NZN;~4B-r6X$~(=);O zWo1=tJhyB-8*FOQ1#1@AJ;8)Y`Meq?P3GDn&d$zOS5{yyO~7WZl~mY=jFJ-U;9{bp zC@}rji3YJ`Uz1;xrEg|#PAMH%2FfrDWnE5Wou3{ZV+!87eVf;A=`PYbzXN9lCKF3e z;d?Nj=MxhHJKzA)zJk2`_{0SK33h8I2-L4%1;fK`-n=@!N>!@ z8-H$-t`!kmUm%q`H6Vb-%g1+lS7v6ef4;uEoHzphbluKb`HFj4Jr2@ua_RAa=vGkZ z`|>ImCb^Ce)^oK}^bb+K!Wq|sNjpTP-r4@mo5x&4_O-F#j{?@%-o6~31ln&nY+z^Z zi^?}mEO~A{XDdBP=udgKuI$q~VOq8QOZy{$hZreT1F@USqiDghpN{i{@>h`d~Tc z(!o=|>fr_gJ(eiIdl-L#DT$I1Gh}OP%gD(E0^|OX+hxafwcygm-ukHwWE*H+AqYw> z?Nz>#gp4!80RWHHG#qn00)n;K+4PGrm~pYTE(YU|wDg_Zw^=zj7=e+brDXx8k&O+$ z0;6PCJRuohrb4j$UqQlUmiZ;0Kab_Ko`EV47=@{?#{KLV&H%OleKhaOp+}o}G*u!j ztj`|3;Ao=2LPPo5)RYbxo{ZYETzmBU>~^M9tPr>2B0Lu48n6svi3Wk2f{QDbZgZ-! z(a#SRdF$d5VO$I3H2i>`5C+$JwZrDrCu!hf$J~-@#-3csnQrpF_rR zeFoAu8IPllO-W^CBh(&9Rk)~+5R>umac+v6!&$1a274h_0FQ*%9e|vuckrKJn5&1$ zvhCTHtDX{M{!me*q|B5qqremV@$sDor6VvuQNw~gVe!+T^d=^e>;B3sL_$(>WvGz2 z`pfTnEXsz=4zoZ3ZW`A!-J^yO!I2-RL8(%7{T#BrQO#fe_Pt+RwEZq#e0K8|MZNys z`J@cRZ-mLXmkhk}jUsf|x>sQKS++8`C3Ssm4YK_hUI}dB>ekP6$N?{2yqHjjA-qc; zY0b!HnZ;7Tr8D*M4sdSF12!<2h`iR-ErnqZA04}N=Y@rZIhtyb$6W5GoH=zMpUgKe zVW2;n3sd(=%ZBspw%v>a5a`JZyZ8erXHbe47ZxZWPl<}g#>Yd42}kzY_3J2tuV4QG z=QNxzF!y?*Ts_#B09piiZ74fWu+Tt}ELSs!ZkM*O&Ia-|aM%ECE(vMim*;4lz)Ty9 zD+GhHK#iLIEI4de)^^Ldpg&u97|=|=*rTMZtli+sMNWPlWVOMJPc`psu>&$LIaH{f zBcJb`CI0&HLnL2`7Rw*TzbAxX;)Go~RjyU91T4kcl>^MNc?02^({pnoT~svnH<@qi zYDJTOVN~|-$kh~XKl!ortL#|wY>?mM9Lg+j6BB^dIkVJ6nN7*Bnp_3;eEOg=)_zIp zD>(r{5grqIO)7twY=%h_((8L1yc84$P~0OZq#>xCVX83QLdm7Stua224+Ej&;fM~3 zs9*|Me?al6M)9B-KQBJ(S_IDft)2@k88fprsAEx*HSwpagPy|MIh-*Wb*SmKQ1p$!? z{HGw)La~EU+V=KUFjGN2BFh54s1{}|Va`K>4EC}X+&xN4Fd$M26YFtogrs+GIk%G$ z|JMruG{TXsGa^{f?Ci8Zs<-g7$O@Ot zfci~x7wX;e@%zkW5G6}u;eEATx4qAQXP!q)*pb(M2hRC(qNu zvzmP30KzdDVAgDi0Jfh9+&;KBy@R>yX^D=iU?z^T_R=U@UG1bEpKc4zId7q2gHAm5 z_S_{6H-1eyPP17)m{rBhy$kZ_O5-6qs%E1wpc%*9pE+Y`7Nl8%< zXx4y#yLtQ3@8&Al2@jYDK|&=n=I%2gV0Yu;CIqvG;5c1j=y0KYuUafw}WictgPLVdKXD1ZpTnZ{sr0 zfoGmfH|^g9aM`O8+R-Cjuf$UxZ$Lq?L@?@*tNku&QPq=^L4^2N;J*KZ= zUPWqnwc`^z9CqZjd7hzFc>Em3;NhwDg9S+7+(vaxBZt1k!tkqQRAS;p`WbtXN**lb z2A~zNX+kRkNUZ`a+Q45}LUe1p?GGey*}@@7OHT*K3d(C3v<2`E<0`PfHFlR1-N~Sw zz{dqd)2k1fyenYI)`!#pGm(IagkJWKSvJ-~1p;Ts**!^O;$+xUsK*hNP#&Pn)+lmP zQ7yp?ErbYi7aO|*me1pCRl6nxWa~QkC zR9qb7@vdZnjDRwE0`hijFIc0n`(&upe|8%(~(u-Umy7Tj2(L~kb-}%oc zhSb0BUQ~xOr>bh7$plml;8_iZMJrC`*uc!?q~Jna1)jo|IG}3__=)wYyLO$m+)fd`ay+@e^1q}4` z(&;^R8A%o|RY{MW#};Ux#}Xw?9=8WcOUY6q(|tyDhpF>bt9vZ?Q27>OW%R*6Hy z6dLABWlg^1)>bamyEt6Cc0IYqDxzuH?p&RaU1(9?aAJRJXQN7EY;=?HA0uaxm5~}@ z8-G!kRTS{#H=Gr)IvnimFmrHhO7h)2*ho4YZP)b`XV7GFY%aNec6Fl9B1_Lu|3=l= zmjM%biu0cX@4oSy4-{>6LPN9kqHpiVQ{fMFYud4=bgJjQw(0NP5|aqIvR8C63bq#U zhb$(ydMdg(t~rg=s-XL$qa%WY!+(!y88I++L(sN055L*?=pcU<(*?Scd1l9RwBOgQ z!PQDjM?10>I}&P^BQWhOeKFS#`@)D35^`$y{?MXUcdc|^pQ-wYNtq{W6K9*1hK-V1 zn->-_8~gB1w=s5!2^KESXDUaRHJK~i_FB#;WeL!?Z83IA8r|nHkx+J4x=%c|uZz0> zFkP%`n~{05;RV$uZhtsAOv2^=I@adeqh31t_gM3mq75DxvtEp~* zt}g!Fj@=H71&(fB9v@>88gA!+_*m)=dXjb3L@4>h$(kqZ5tR=}5~-WEXlQYmRZW>kppp%qCQ$ zkA9hs=svGDSk*Gb8LH|(h5zOSEJKG1H7fZS*rvKB8}z3q-Hr>6mrvI6I-YFfj*wGq zYBdObB#u67A8EF~DE{Fl-rcXLJa1r#N@~yPPR~%L+AZ_$jCU6CNoQ$e0ACch+hBq~<9SK%lT!2D<0#sOv7*^ONln|$qTbpb z=N{%!ku4RJ(uwDA(YAa-Tt1~++uz0tUxeFjiR@%*J{6!lG3YK>7rK?Nv^qV#-;s86 z@@UJFy82;2jO&0>IbOL~?g0Jy-m2r2>wIZpOl`Fb0iUbUV1m=lgEKWH2c5fa>tB-R zLKY?(Pm?oHZU$4fZCZ>}Iqd&>sO~__Z^hfDXn8y)zKKc-;;E9D^Iy-_SNM+ge|QHERUeOFjKuuDo- zVYJ^oo@3nUkXM|N5?o~$!T}X#D!ElY^s6|$d!N7*?`ZXjUH711U43rE<`V&z z(Z{<&`4*e5w@~lcI#{nSZ|E3WGJ3FL1P4E$kX1iv4-xwK!>j7px$pOM`sniaJTBYy zwe?pt1LG$|Wg1w^b~SAZS?Ht|iA?iSr^ZgM$MQ!`i{V{AI%_XOP;~q3uqds&p}YZ6%P*fF^4aHQL=6QXVAT z9#y)TBye%=tL<`BUBqwUaXkA%(y)5Tu7+o$&SjlZKr+1Sc=4fQcdfQoqxA$M3&j+( z{#p@El6waobrP3?yvE*qR`UOoPEIX}3UZA3j4INrvVSvIR{55e>IZwNWnkPP{vC#Q zTP$5Ndyl*Rt`IqcE356M%hn=sG%Bgm#c5N5%UGR&)$^+wba#pzt@@3i`qpb%GCiW9 zQA=*sRteqwvqTnyCB(_eU6K43LZBcC|B3hT$e8RWUh}5W+82~%x2IMtL^ny z)QdY3^4eQnZ0zSM)8yM8OzaNkpI`2{Nx2$POlMn{^M;=<|LGiYyho7J$p_idDUJLd z*7*4O`IQwKr_`+YlLy^(R%HCM60SdsSyXv26XZr|hLS9zht<^Nd;2;kc9e2&rhX8c zural^))7-%IUbcNpR-0S(}*RBmgVg99l>S(jlGq~_@Uca*wCs@kBSRORxvrq)GmaBOrm zBZCY+L*SM2tHi==qb#57Z%up7P2nK|3AUS8oZMTF{B1t;{GayTJ1DBG{Tf9b1w{cP zf(U~mhzJM>NFLk3fC3^(vJwP|k|j0z5@!%l5Ks_M0a2ooa|dir-(TNLO%*deO`p^I?ES>G*3&8VJFsnA`5yOlTMnDB#~O^iH#?;O-c4tr zT}-ikbvBD!+H(4vV!hA=Q?f^a$Gzx-kv+mIxnpGFMgh~C;#8}?@i=a!l1umYr6DeK zX(-tW(lVHxrPxT!d~I(R;1#+^r+V|ImGBE6rm&>`kK;)*DJjXdcjqXHhDwD~gdK?0 z23ZCzwKk5n%l&xMv;Bxcziin?d4%U&BGU=}g-M^$ca%&4;`7}!G=I=KDf!hmG>`#3 z0h}1zA+#B&9gf~!0b=UR?9-+zzB}V>SUNN-EGkv_O2gxlR5i3E?l`JHcvu+`WL?h_ z>)KI57Tj=~e?@Haz9duPIjB%e2(UY7E5e$#>LwL@^k}yGNc-Z_gOR?uTpJxTmdJhk zIL_HsPaV7}Ul%K8(_ik77E-L+JdyJY{M#%|2+3=`EHly2kM=>Yl;z({Mw81`GJVqA zkAvOr_s29DSBi^@@8+xsj&p2S_f@Oh7eYtr&n7OU9ejIQhE8zv`#yzGKl$JKh3r~S zhRDfSeKAiI%^r$fVYDJ=mI+&45u4fcced#noUxIzUJodCkRSvo@%S)@okeAgxUoZou5~#UwM( z&@^hOhjN|b;u>98owm4G>6LW9-P+jDW2o-?$@mNl_gCuHN_8IsO8u2z=6uZ2D70>V zv0UKN?<_5}R_$Cjb7(uw!*q>MPww;Cbvz%md(SyYI9ro%s;VkKEM?%|oJDP+*Jv?kk%T zh|bZx+RMUpin#6Ud_ zz>b)%vHs9jmHN#yyT2#o5ydBiW3Lvqj5L&lWvAu7FY9<)>HfXN`uu9MUzFC*4(1oh z*%oy@ck*aE3v*LB3kpZ$v!v9L19Q&g#O2J*J<8kFQ?Q%UMs7AFWLIxjN4o~yFU55? z-L&sZWd}3zV}Or9vHCCp*j}tji9tq_Ik!rz2kPNe9`Z2Vt>T#cQ*Y0z83+h#lrYPB zz6xuwG!q+ci|u%)PNI)G*H|S__sg`RY+=QY5b!7MOvkEH)4ReuFXur~LIVdZUZ6H1 zg8-?t+WPwG_1EU-#l44uB6J*Vx~eM)NQj4DIfGyPqdRq>aG$@#)Mo zMbf{HJ2o~l0=8YJt`X=W)beAh8W)D&YW?W&k~4W7lG8$NS@d|}I?Gsg&@fncDKDUF zTW)%wnlpcm1a5Z710!oHl#kt}lmwW^YbzW#m{R znyF^?{<7p15fK4A1QL=E_x$+rmp=!Qj*e~=Sl$uFuWMC3pV_3_&V;XL=B3rFJ`Efk zA|*~ci+9s=_AB<tG%!d9hf~M;#*Id3HoHU8qe@0!15H>gD7G5twpZgJJe42DaSP-nBcmS+ z_k{q{;e}R;tmo=CK`MC1rcV+Y57XA+sS3gka>esgjrT0VSGR61vGF&wzZbpq(yfHu zEm}3r{b%jlO$LLk;$3=Ki!XskfZz=w06;!;o^QT~H33ql>!~&N0ha<$0k#F1rKLpZ za!AG~)7?4Gx?}rxJnO>b95CN->abH&&iwW;1sn+cR9T7D2vTJbd@eXo-nw(=J5VBT zRpJbEbbz!bK{yWGYK1Uvh>2A|8!IVkVqp~uI?#Ciiq0nBXwV!63GIQ6%`^zN>Sr{d zN(GcuNl8g0zpj|$Xd?(4xxMd|(^gEEKg;ZMCeSg)Un1(8>Nx#XQhz$+yvhQdJO7=Z z#wGGod`j*)WE0LW=8>{q0ft&Vy|>evYD81N$%<9vWSo)@o?vmzmUh2V|B=~S;PDCm zy2o`;;gcRvcD2g1qzWOUUkrw8oCie#%4&9YzaU2)|K<%qJAhagpq;k5y!aGOlMfI;90OHU=E8+#=oA3^O`rp{ z4DFZhpD{9oSeDF{NC!k z>(S$q9IviO{cQAFZHWUkfR&XMk}N$CS(%0^;@En9`hl#jVkp7k0$2m|2v-h{bD`t- z>eZ|I4hIL_Fc-;hxn>-?9q~h5*mCQppK9+`tv8Q}l1-1he)0O!vMsMxc78!UF6!~reJ&#n!BD%gxH zHr)XS1WG;FWxz)+E-dVW?AQJK0e}D94Ok2M^pCF^J3B98GeOS^z&@~Z|wo}^4$3Z#+4iR8G5YXbld!f1!Kt=%8fohx;z>&4jgi_jqdU;qohm6oP;bUB#H0>=s0NQ0wHsdfV&++UkiGVX|a0= zbjQ-ZH-{4fyb@--zIY|*yz^m7-=*t1q{TvO<}PobPPuWfB8HY^^{m!+L1V_JpZL|& zYE1b1)r=149U0+^Q)-~M>xtegcUVWcA3I^ zEpIyv+?D#r<3nU2So`grYJ6eB*GM1^K*$CdigHb=h<>XA=p5x3Newl%_%@5r<>erv z_%OlB!o#5>rtw}KYRLFX{3*#Ge!~e08C`~A0z_)i;P+($Gz5eS6vbio@Eze5z_rHr z#Vdq>+1dLm7xdgAD+lxUZ00ENXMdDhMgaI08rt03Yjy4@=ww#L#wQhSqRkAMS>+^4 z328|AdP1VUuu#&{ast3K9bMhX@Nn3lTe`X+NW;WJ6gQV#7v~TRXQxUhG)m42Zass& zM}9VL#Ce&qL@7UhB>hd6TJM^E^p56;YwkK)T2R{lh>rva6RHlDmeIHgfUY5Ne$jiE zw({!;P;!s|Lzf46OHhWwtZ|f$?Ioxs9TP)=V-Pz4qA5bn98e7qEf;6V866W;Z2)Y- z*jO8}Xej05$pdGY-q*D4VGRqE{2{A`t~S8Ha$746Q2g`p_0{gr$;*>-90k5Z_{H_0 zAnV|*DguE3(fg-iVF#I*eph+@EGZy6Ira7MSeP8S$MQx({L<^@y$XL)+_Ihwc5*3f z@t%F}Q~33$MHZK6o`#X{QL{vW#{aEe1U5N zup0NSo12!A0s1=RjGp1dco6A1Ei5fnVx@U)so@IZU|3DWUW}~gzkwe1`t`-c@m2Rf zjvwOSur)OmHE(={vj`SzFo&E$N}HsF1OOQD{y+`kPoWxWa`!Ht6(qne{sY#!+^-o* zMb<%P6XZ+yRp4R(oFdSvB18gk4iXQ^>dE>=&N(f0QEyitM>Pj3m(7od#x=yO_mO6v z?Q^CC@z+fD@9nct!P9}!N5|b*EE*_U>|7v4!O$uxF78fFN==8v7idLIQ#%`%mJ#Zsh^q)yLcD@E1iMUzyD>eZo(Z%Z~apqpf zMzB}5xJB;1CV!}Bi(AZLJ&@q#zlMcNnJ|Zx;E!*60sK_srNit`+h?Blv{m3M*a?HWG2HRca5$mDOrc(Vk zpl-(=?t(J~t#78cK!lUCO!xthLUW3TUXQHX(^cJeTdK8d=DxP(h=^l!-Z|i8g5=p>_8^_=MhBp4vn(B16@C_5p58ti^9WDU9t@)!_WOawM5=d;q%#cfYl(wiF_@86re z0L?|kM9SfC)(D7=fU_W<5>b^>h8p*zYDfVN1n~{-ekHE`stPyW|aw>=GBG8viOq0q?N#;?kGCEsFXAGPP<^72sNOhu^LLxHzwIOgt>0~fOmYe%(y_R*%-ZV*_*yBb^aZ-bZ zi5!liow*#Ze3^3U_ElCpY@gKY5p3UY9ej!OtKt}L7A_q;RWC@{klklWP=AT2EC)*o zGN5!#!j9D)M+gC+U7Xd<91ND4zJMf!Kd-lW#V_|#Qp=0$Zv!=}moA?b47wU$WfGe4 z>x$Xx3=~==ab%0B_6#=+okTPbKvJ{jSB0U?CfAM|Q5NJB$QYo_z#CF1**vB5gsyZMVn z+I{M_Jx0W4^^itnq{yn{-cEa-ywifp2R)}%j^Fs(8pdh^jkLv9GTAV`=}ScgVh~s_ zQcSeGTghf_kBz03Rd1#n@zM7byLmpwvX*=3aPl`9)Cllnn#d>}#KC4Jpc|{}fK#8?p zX+YG(9Y=HRim$iVE^e_j#H{K&2l^3nYei)6-*I z%nO{=ygUxb!r5f70(A)2W2L2~bxly?R%wH0lZ4qc zO&nVDKm<$(06PSHJ75=c=k{3xe&AqW5PQnB`tjBHQylc1U`iorSx*J!W|zd?oZ7Db z{(b`k1K??oNjY292x-MPjZRSaXm=*i>@czi4jpo&3|7JSMdW3tv%qY%i~&g6BHWDu zOC}~JRP~FbmZ6c68s=S;1#i7S7^(?$kYa$PUD+}`f{QUvy@|2uHrJ`DRF<4@E!ida zYsTwyo6>@{C*wfWy__Th-O4>FWQy{^Y%I8kH3xe~$ruvJ3pzST-&5pE+xGCgObAF7 zU5b5YE&Kv%Rwkf?>x)cod!+$E!qAh-*B~KuhkYD@{t(@1p9h$_Gvpf(K;J;lS$B#s z+Y5@GkI#CCNQXd_FyDmbgqzzB4gnpOq1K5vv=IyEJ2xzE@I}{bx6+q8{$MF_f2Rn0kwJzF@@@)6(rH}1rW#Qf z)rneq4-em6iGAkL^-444I2+qphvIY@TiY2>7z(yQIf-&zFTUwr%NV4yhulpFbmHQ9 z(4fldI;#-sA#vL01FBLsHW6{Z@#yHSXSWi?OH$eD+hS}(fnLa;a}}-IM+ms;Fjwus zQ+`}}Q20fTX-WD@_{J5Tse7iTiM=Ozcz9edW_09jU5+!|3c z$W|pD9(R;niPd*-$SSt!}i}?tih8qgc>oYPf^jDH>2z_#HS#- zUIY#)2tNSGq-n~nO=f{Wl~`p0icRE@qB@-rIBwL!Nxf9jB(IQ`;=C=z^;Z+7N`nbA(xvs9A;r zxs!>>AOZuN%d7Fb85p2M2U-%pfB;5~fF(p>7AU%cm=>klTEo#ZhNR}{q-K}ZjkBc07>{KmVEOu4jNG#fIWa$H?6 zcoZy4jUq3U6gKsys#*HY&u(0r^{r_m3IRI1 zstWR`0hmaZxBzezRv*U-@P0$LLBX`fo*tBqZo~aa#?*uQgzWmw9&c}Nz*^q4i~)g; zIRcu7h8dbEXbJEdPHv-lIPs#|-hotu1h)iZj;=+VRZS`S-ob6RZ~ckG+1J8bX^rh( zvx%v%@3z0r$bC$FGZZOJZEToR638jfZM4#KM2YJUw$Cd~D$fLDX_;dr~e$Qo$7YReB2rY}6N({`&t0 zP3W{Z7#9}pV-^wU@9R^-U(s}bx$uAQv0l|sS8x4)bYRf?>FYaycMe=F|F`?{KZRD7L?X<~MODS5lJa-hF%%Wl)v}jNqL;1L3+Gdx{pOG>Sc*8_yUx6a?Uhx(uIxHe> z4%3gTq=w*W`!10YZmFEY6e;npJHOEkaDQ^y^Zx=vv33#1nvQKQ&}!WEprw!AD34-) zFp`{0OGD$x&cd1>JbTET=F?WN*ZNNmR7k8#qyV4??n(b*4r(u`+wh-0%|yrtXBsUI zqzzjA)nZRxKT1h?YG+DAqjQp$TB^N97G@1Xn5D>f{>62Wh{Id5n96UT!@xh}aNOM7 z!yq_|vj)Xj-M{t^I>wO^MhJsQVx?Uv$QPMQu;=h|%4ZhY`P|&ZpVnlLIi)*yUjN&o z8d3ru5Dbd2@bDarM@SE9(h7ZT=suML-wtIbWW*-loq%?YD3Ftm1-&mrYHFP!agu=UjAMC|6b7H|xB<;i;*i zx)GHhxENTnxjGS zq;GKPz|Qfgl+LGN{ff6X*N{#0#l1Ggd*HSx31Mh%setSPzPs3q>r^@Lixa zk&YRj;C!I+de6$Lb<7cTBz|7rr(9K_4Pj~k_5|em5K9~&Ky4ASqM)$o(LIfh)>TtG z>GItIG-=FCNl8nCQm3rr=nVwRAYI~fQOAc)^v#>0RVLVx;837&1-dl~!lAZwCKzYe z*5>-)0Z6Y^%>2k~a1o?9_^!}{=(se~ZHHQ4LIRgUX!+;QU{>AG)-HfX0}243D}Z1y zg?s_iRKT{%z&N?nrxDui-Me@4b{(kAAY>Mrn?fTGYLG>R2e+D@j@bWs^;nf)sw?Gl zXjo61B~XUqLaxqEDLbHXkKu=P!YYN=^j!TSxOg!j1B8C;a7vU$iYCU7Vvs?dm6+FJ zml^ax85kMK!1`ku;RPF@O??~lUa04Fs2t2>BE}4WxQRiXaFQYtm*9`#IrXDy_!XKl z`2o9q5OsPOdB~zN{lMMfd!y!x-~-n{!znfOdYWcO8+B|TY~}o9*If7c45Sr>h28b_ z%5Aj}PFF@O+U+*AVe(=)d5#P+RzB44p8PHlw^@|2AXl+Wlz8o92s%J1VA`f z1MM)$bPTWr)g6f{Mqfl!=-#~|B`Jxynh?-JCkDX{4i*9~aGx(-TIdW zu!`_P|1@Wr}Tbep7HOd3H(yExu90hU>W z>QoAbESy5U2qhm03GIvydQOCxDBvR50Kfn&$@LsD3BRc8Z`qN6jy9d-gU z&vva4RP3GXKbUGdA_@cUl^WSZ>ZBps`iM<{b9pzb0M*$yA5C2Ay-jB|f|IDL0g=@% z)GJX|^`YYFBepGocn6)vaO>i0Rkch;cZQZ z#&D1PS1w<+LZ}8dBDlO;S8Q>nbp;xIizcegdfuxu6MrvC!T6*MqrXC%3AmD zzk|^g6eNkwUGFx7pSQ9?>%ybSjh5CQM+nJ->rKTP3Y17uOyk!w$ScYE_z_)z(JNYi zV+-PZQ$tojHlWzRwYj#gTHV&>1nw<`z@yuv(A~x%Ugxn$(p0!9p0ktY;W1r|WPuaF zLx3!AB@Szi%YYJhORS7Lk`!Mi6cqLIix_0WlzFjp5oX|^?BRsHGrNxsjO6b5b?$=4 z@E@jk^I~FRFyaQM(tj_Dy=Zq!1dJahvS6+pb{ZaWxS|HcJXkWE@D=eF$;tNr&J5Vj&%M%Rsc^i&JkAO5Ql@ zH6wqawxf%B;>5@Z^YP)d(VIc^MR#O9}It9|>^X2B}#~0jOzqO!2kL~RC;CZ%UB7{Jw z?NWFwsz=u-O}DqR1L?omF+HToeDChv3V(vRlcAN;h8!2}v%`7@!VvI$SR zIyn&e1qurgW|pTDx?B4k6BONDT~}6D0R`aKFLZ=N18QD8cAxab3mfwjKumqd%3!wWWbLcYD}zTdY&GoJGp>*}tl&;sT5N1; zR|Ne!{pD+XXB0w#jh8Z1}>Gr z7lx@Q(uP@Le99nmzx2?Zs?Jrtw~L5~KLw%H<1p5oI2Aee%{Dc=!9=)7LXFO*|TO)w}El;!n*-%Cey~ znUQ$xRF&+T%$^JH)-X8(F%>XB2&wo1xtOT9J5YU&p)a&~Gg)QwoV@esSnFc|xbN$a zZSD;^#>!Hdn9^ZLMPhY?r%?V$4F1P^e(&KwE-x+<#nfce*oQS23UVe`QrEg7+bEhA_uZP zA{d0%eLYk-+$-Iqdv_sJFf$toKBTD-stzT4Ev=+B3y`D1plGupUzzONakeH&h5aC5 zJ|v*9f{J4Mv~?j!C!m5=!@*PDC|ie46;PWdb8JOPmRC5j;?~{IAj|Ys^z6p!T;Aq# z=+Kb-3`uk=y+^7gA((#Nu39RxNBL3he0C*!eqNY6i?}dlgd@@^Gc@ozyGVj1pVe5P ziX3rMJVdW6*UMw9ATYON{wR0MUm<%J3n+^@mUD~)V-hqphZqztUsU%K{d{88AhBAi zG-J7iCnJ@G?6tPgoUzqZ=9#9u(DG!{(?dUv;Gtj7%~Q?SprxMQlhPyiF{31Rwaree zF(c2weMNAllo!p4W$zEN(`BXgB=^N%P(}z;jCgj4anAyFIj7IEQ)T=2{g1X8Fu3#y zz5Xyzz16UbCZF?sv~Ob<#%j7Ge84imi32?JLSHdd-N1kdu@`ju>RUxd`giXBl@!7e zbeI5m3vp$P$ID}4Ls=|UBs%Ze%V&)%ikq8X^NcH1rafeiXoQDrMLa2-{gyq{#1rQ^ zoJX=PczZ4QPUSuh*BUKyda>P7_{#@xf3B?#Om%pzQ7pB;I{l@6>d{3`ilVMmQIHg4 zVg90eHaW%9Cc7;oSgkwbKkLO#DMY>b=n-Eg+NGJ5;gp8lX$kwYoO}yb&7@L2d)4nD zau3|Ue-4qlAgQULDZ4Ve&M3QimN&)mkHJ^utwr$|D>0gZ)efs8$6xk%e3$Z#VS5C< zaq664;0594%*H=v<`&L8k{^0KO4=CeyC-s&cIVPTf;v8IVRYm3$?fu2eAlNkW~zO+ zR#wPy9?P<>u45frPa;t=UGKA2tLIi?kxI?T`6_#?KO=IXc1wlduR(VK z#6f@B2iR4E9mjRg@>wRQaJ+OGdH3$g{-+mhOBU_dx`sC7NMiQ4XYtxj7nMlbD*H@f z|9y0)c?Cjsb0(t&heCPH!tVBoIfH!J`F#hdGFD@gwYslfQvmEdD6D@$Kztv?M`)|g{;Ru{~?h#NzoCOzHZ-P6^PX1Hy!LnCSzp~LE!`16rXMa1vc#UW&pl(MOh!%K4u-_dDpgg^I6-Y` z*oJt2pSJea^@+e!OJtGHH>u08I;9qp+a{wHsK}6r3l03&hD}Uu`iiGtUs0jwT%7LT-z{e}|J+U|ZEGS-xKWm&rGMqB3SFfwMC9g&%>_xHM1m3FImFvWRspZWoAg~|Cn@BZp~t4PDSPfc|1ncY&ylZRQ%rf{J(_VS5Izmei`0pX~Z}!b^q+W zjxse|o{upuZ^$L1m?bjGtLgW7#+uEc$sdJVw|7zNus(-l12H|X;Gxv{hU5r3L$bAT-sk2(5i5uja$US9;;=b$?Y@R zmt;#=f1e?@wdOZPE4(LprqJaPlTpv`0HX*+aJ%RMo?TL(GT8L`6*#5|>vOkQ`CDsF6`yMOyt<+WBq9r)?*GbkF^% zxB7-BZf&3;BPXj!^WOQW49$jpFTCShO#R(OErK*tbl1l^ zW=dD8%?t%y9F{J)EjOl0%rQ)^<)FbWkmcN_;xH^=o?@sgmabo7|23k|A6F4>i{4yp zawpIQT@4F=$}ao6eOrY-mDpGF-6F>@ko~39La=t_!K}#5{KY&Kxu}>IcU<{IPq}XO z>o3VU-kEzm|4equr!X~=CcZ_OxK*u2&t^J~DEG&VLYkkOlKy73=>c9c>U85mmb*7oOkUXv2-l#=Y1 zykkH3ijxrFY=2Yr&P8SC;lcMUzDy3o{kGa$!$n@6KVwLHI8V^-yJuy7THuUTieHaS zTmi9%7^7@vX3N1U`+HU&XOE`D1&QM_9;b%~WEDdD*UbM4$uQJCg)>V}X|V49fFY%; z->;~I#GTJc3w0f_S8L$z6WQ9vd71QK({slqhRR81LZ{RPO)!QBvjnTJg*R_v!3|rds^xBW&PmS8aSuP$KAuNFQg&xEx;;Z# zNr8cGucjN*d7UXwM(Hy?M`gz&CQ~2RM37puSzPdt(Sqw0JS(15H}T}85bcS0zXz^s z$oq<>OEO~i&{O6P9Q<)adKpj)qk-RXmi-y0v|1CW@7%=@u_U?{yF#h6PsoM1V*;IRoB_muu4q~JTkCFEEc8App;Snb@qjZ${eAo-it-m7 zmp){nlrpBNYA`%7df^V`{ED)&5kb$hV(r>%29^HB6_B02r{Gp=~<}VgD z)OB9aBIR3Bihu#M!IRsfVx)5O&#R)Trjgdv+P016 z6ZuKq#`GWjC*s$-x_T<5g=+0DMB1(31-RJFCo8e3I?`aZJS_nfPJ%&{%wIk}>z($>YO z{LzMcEW7v^nU(||@aMG(#opDHF*XcEWg?gwt2uaUd7ih?6Fv1_{e5cd?ej;*9T_67 zrm35MYe;$bZnQalJQ&)Gr+jzr($*Jdr9aLV)!!ab_GC$o5>jTZqv+Lbnd7%EttGy+ z%J^NNO*CDHd@S>wD68*{PFWK^pBr?(^Y2+!TJuc=C+f z+0Dweat~+JC|iOGHP6>cD|M_g&uDA+aGUqr0$Gp2u9dK-M_UvkWx|bv<><37Utb zBspWh^s)UsW|xQtDee7)fbHI|Epo3XCcjHnJQgV!ogAr^BI=T=mgI2m#oqu^s-Fpe zpWm6;Y)A1?4SQQmsr9MqNY|gUw>C=j6KAe_|1P!DbAT3&w|teQT|w6$$DMatPk7Iq z>2*xp?N6if#YdO?Iy5rnO&mkMjq*hbHn?wu=N)PAobV3MITChvTTM+(;^`Z=zvW#Y z0X{KGxBhWhR?VECQk?Kq#MfTQ81JTAr)BDE(i~U~=$g8F#Mjmfyt!M7wr+_M9aFok z7^aTcCG8h~8Lm|xp_+0eAvpn?=^x{UO1kcAckjM@99?va?xREH5e_-8 zv1LZ`7LTBK(yG={dw=QLB3JId@kX(Cm!`kIwA9LQdys1}+eJgO{&jt<-M%&1h5YDP zd-?&wQF?mP_0A)Gf|vv5;v@xcBNmNugo{&~H*I3-1>Bgm@^G(&0F{o^?CY|Jj~w0J zlfz8-l3@t-ZYWRZbXRC6DMPT>Q0zqlzb7{9*26!-6~o<@Z>;{6y-RPz)3)nP+OG*; zCIL4sj9cP6Md~7%Ek2I)VOrEliwwya%Gd1aymjk|yAWW8*A+Q!rt3V{*Yj*v(c75+ zv%0J0g?{;XZI0(EV|T9W&r|VD)B^h0xY9%i9p`^85lD*N7||RR>Hcw*m>;F%x}sNG zC3cv3OutVjm!i1&%iWg4a;{Od;q_TJt-Mq<9$%(4lH%F0E%!fSB>msAZIUz0l))kL zTpJE*zG!CV*>oyC+e+NdtZh-4$1L)p*pyiM+GV<@agkE4>!)jgXS0rxavxq@n9vp1 zux<(*Wm#~j{(kVDyf4#xf5xwUW3r4o)<5SBgTY?&^WdY;oXFVrQ%73RM%`-5PZUGL z{X*EXZZA5PM7u9IDT-FM6&cnt_xuoyzK*94SM}HQv6JCv1qI0k#(_*m9n88t+50lH z@-lKb#g~SOo7M?3IodB+RQDeb^4&=YuqAc5@yO&eSb1{d10hJmbcLHUfbV8 zDtprkyMBbOWHdyPvRCs0XDi)IO@YU8v(?t_qPRpZvYfl6W6nVHFkg#B5*34gYVq%1 zz4{$kbza`FJo5Aq|2?x>o!es3m%KfU*k{D-D1rLr<-SZZC)}kZCgRJbf{%%Ey^%L@ z^)2oh$3Q3-IlUamrpZNOUHBP|EPsxt!zaz^4VKHlBpIt8U4y zIOA%|x1K)ERPPxV+Qr?R+)AFNa}`b-CyTfzJB1zU-z-J&E6RAhYtOAWF;x`5zPuP+ zlJ!<)-+Z%REHjVKQR(@rl?ypKBPD z((Rt);&e>R{`xIia&G_X;TrN&hIGB6dwAM+raTQ}B<&Xbtn;Qylhfr*<^!4<<|hub z4o;Nv2)#B_=ivPEs*?wMQEKOdU=|_s8PP zqx-uB8n10FhOX@H`MINHen)%?!K2RMbj@RJ`XlwRLJ3|O@$xry+*fY7el;tVmT0^t zcb0p6J;N+f#P-}^-mKNixTV9Iywem*w*XhFg>`y;*`4a_j$N0Xj|=6y&@-yk)Ujx# z_CL>ekRQoSTU*?-Z}-&QAvT?RDTXGumY#f?oi0gm7#;1j8tPV3i#yiRL^iId3EQO^ zO-XHgC-jqXlHAgKrAJP9lCZc^*qyvkfLQ9up67oD;xX=W8-rBVDNDTrYIaY5Rg`|( zbyUc0vco;hFN9TX<940hm8Bq-LsBPJKMvR&=dd2{w4wyIB!&vOb^N?1|G9fD{nlo% zCEPuK`;;B5&eKb)Z`bXomqw4$&^QUb zl-ke4bidMwu|kJ|hVcz!zqau0#>QQ?U)OdJchk{4^m9G8cxd~B52%wnKFIcs3?Y+b z*Vc(kD7?Fe>4e+=`M&@xnW_r_ diff --git a/_examples/kafka-api/4_retrieve_from_topic_real_time.png b/_examples/kafka-api/4_retrieve_from_topic_real_time.png deleted file mode 100644 index b336205baf92f7a912aea49fa907e547c5324696..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48712 zcmd43bySt>*EP&h)D0LLDFsOpkW{*3i*$pOgoJc=BM8zhU82$@QqoEz-3`*x-SsWb z?|H`a&->3e#`BKx?lBH$OYD8$*R`&-=9+V^9UvzodIysb6AcaRj<}ex0vg)&Ry4GK zq7c{MJFbg)V(>ooSO5JJO?Q_F4UG&5IN^&J3bliXN$RDd8cNgaw6-199<;e@pffyv+H>3vD?ZMfi1CQml@0 z_`t!_^LCwkH!I49JgfV#fz;8pxVXD(&APj*%K{NC;R{!A_26q*u;J0{a;dle&%d|A z8Xx}s&r`Ic*9zH6zP`T9@wdq-@q;kpFt08j4Nb87xuVeb;^M@Fgt&!gc zy}{dJdH?+TufKN!KbK6SbnpDgi3E-;8a?L!hJgYMR@dab-uD_Z{p zoTGp5DaGc|T~T^`0cNj&&P$bfZ+Az=P3$}SOl>(uTAOPPjf4j8u72;&rfZ|8myW_D=DbFLfoqE;i^)U^8`C9~+#Q2u6OUSs5wPYmZ@gU175@n5$y_ zJYC^?3el$jJ(9<8rRyoq)26}}e$bCG{wp-{_3jPc)EG&?^ZT)(G>)uUvN;E-%(Pzp72iXDH z{tx~N3fBGEGhGiNV2Wv9K#)g>QAUV0hmn##dK4`1+4$sSe|5M}yD%pQg-}yh7ZDZ~ z77@AM*zjV#FI{rDKr^?naJawU*4{pu*V#rxV0rTKY% zbMp}7@3ywKj*h+k{q^IOfPerTDycVGe!jl@k{@f*YaD~Uy}dtv{CH2`OpXkh#P5Dm zKJAgnW;)cF$U#R(S8g`?S&pX6Y;^YT)x+s{=PiF~o%NhZh)A*RQrE!10Nfg>fXBqI zUpm{fP4Iw?9{;9uJ*=f+kdWx=amZW!?j2f)NJI6YMTY~UR&`uN1l;TxgW*_pKc73L zH<>|qO6Lr3b8JZ>8EJN^x7*lVUi=_DLc)_iNhWK~qz1ox+BGirXGh!Di3cuOSy|Uc ziw!T%ju#gfuM=Y(4M();!>;!a4~rrmK71GgSJN6!4!Xn&_03CUs6i1F|S`}*#alGYh^ zr!2I`-Xmm1knhcf324>0zz>*dX#<;d-x?T@@VS&!SGx`6sUgx#hYON9t?S#{P5<_! zL0TCd9lhrDb9#EZrw2*?F)~s?Nr}~bjMbY=HP5s46Hj7iXiyN3=S8)8{@uHGQ@Csm zbaiK8(JiNI-QniMqo`nGzvt)YfBR;&Hd16@U;v?sgXtR*5@J)~wla{-&(DuY)2wnh zK0Or`5uxx&NKDMl&7GW_v_6MjwyZtQIKW@9IWE#`*_ffbxwU7DMn z{V4I)$mnlJJPQ^URv0nQP+woYZjnJ((kNr`<^u;6wxxvyxEmB>EDri}+r^HuGIoQ_ z#qQM9m>6X(Eq=?X>Y*WJMMXs~!FR~-MMdJWvZ9E|T6b62BwmuRmbs8eT+C0Ow)OTF zm6i^UjU|vF?)p8B5QB{NQXV$xb-BgcBGs<0u7iUEE-tQ%iwiNj8dGEA1G5MXU%gF@gD z5O^L=I;MJ@WWRs^!p?55%zS)o|EY!Tx<`_LXRR;=m*>S9tS=j3NM_~|-1v=aLh#5W zuC!f}ahvi_WaZ&W%vfIT&#bDdBIUIDR9mZ+uPiDo%zL_4yzX*Vb2t?g8rs#_>Av;n zS8K#$@yL#j4l`rphx~3wanJQ+k~qn6F{z~!e6AAFq~kQKp6>Mfj}qykp^qXY(lrZYm!E)=xy8izq|G<%~GphV=|@SkKowexqbWE_3MKs z_OD(=tDiIRVJsguj&*dP#m8V91_CE%Zo%QWS3-R8Fj=xA4@$DHZwDWKd+06PSEk^0G#^vuk{*X1%axMd|JWIj?-Qj495)DdFLEG)7qyrYao8xP8= zs$4VKQaP<>_lLF1i;9fR&7UApl=qD{li{e#(Fh~%5VHQAsIaZOILZC;We)PZmg_p3 zkDR?d8&0(_MceP+D8x$mF zU%Yq`6%}Qzo1Bmk7-cUjE9--lzFhE>%;;obU?@Fgh3KTCGlds&Cq<~xMdbqKa;%WgW5iY^Wx$1gh zzsSY;;k2HvEPgZgfX^NRLkgLqcO0siuR@#~B&i49c8yXsL z?%%gUB_$<2A|zaynfW!}I7Tvhw7&Ao)R;A)#`Q4t!SidWn6t9Q-@o&pZM_Km%x*q5 zKR-WEG)IGjT$wtGY71&DS5`DiqcDV^;fT6$}8E~*;Tct zuu8YIv=HFowdpgb$^BhlC%%8bZ)nJ2>yHpbND?W9&&APP*y-VB-NBft2IC>bJ%FuD z8c2I4jsDmoA|mb>Yi-mXvKBuGv^DElUi9_#AyI%$eyXvd{2ONe6wU%nL!#~n_)xY% zN?2w809h?DKHiw=ISY#`;dc{=!hXG$P&h1P$R8CIuT)eVwWr3$#(w?!hg{#nVqQ8ubzpd1CSf4o_GKs@)e~6x0FNeE+EEW?#0HTrdI`s?= z;#sO^E6rL<_#net6ltTKTCQKa1`+5Eh1%aA;U)Msc|Svls*moF(PBq;wT-5Dxo zR@Rd5-vNfS_`(_69t>-36?1bl(Id2l!0ylqpiZ?L6iP1RvY5F_=;+tH$*7>d5Z$ux zO&c?nPT`I3G_bAENRy+95K~Z8gplWabT>-f_>l81-qlU$zj^bnn8Qo(jfsi6wzj3I zY5US{P*9Myp?y+LZxC7g@82V4>{D5_wfum~LVAoJyE-{N6Ua)o;NauCDsoO7aIsZ& zVuKrKj7&_1#iKtiwzjq=CNy}7s|yM?5-n@v0Z8-zRHau|S097jTI@;=>XwR(j7)J} zeCQJ%9UU!9@sySp6AMdHR<aS&@0%j$ z-9^|NtshqZOcT9F($dqrEhRhhpZxs-#Yy1eNUtdn4}e*8o4%73dRUp+Scx&9eMUyc z>m`MnmD;&Nh?+m`dgt~@V_p9CE@fUyA~h}=4$O)b3lHU`wi@VT+C`@8vM$X(&!(s9 z69)2ceI8L2BlGb#8_|{?GF9kVWh@;mm&d9{KPNo)PJPYt)w6Aq72` zZ(ndSQe%vrdk#oL78)j~R%{#`o0C+Hf| zebik~T~*b;X%-fXJ&^$yb6gYsjosLys-hx}?L~fJp==~&S9;~L+{D+TMzo;dU;vG< z7;Nn99?R*ml=lN1!XGH6H0eIimqw!Vm()Wd$H7@&U+?elPxZVwuDvz7-MT!2NM`?j zFtI07K0YzgK|gQBN!BcD^!=QlZ{D9FeWZA%tgSsgI(iH+E+Zqujei=t1`dw$Nu_W+I_0>8gwGa4b$Wb9 z{p2q`2#bnZPWxIrZvc`)oSB9O!Iv|K_V){f0(2q8qh_yPkC#um zV0rGxU8+`BS2MyMXxmmyK({cHx)^#L|EO*?JRIpwhVcGYRAg;y+dvQxw`hI$o#^YU z+;Ph~g?%`vwa|hV{~k`T0`exne8pAxexQVxr2iFe9V+*RNj< z4PO9MRaZ|;P1WY*Ndbzgs)Ep1TU!I5B_JT+gN$wGvt0~UqAe{gU6(YI<=kF9Y~-e< zUV^GGir99l4#1(lOUzwDZHnPrA5Eu{k)Ezu?PT4Z!Uq^oGKPMc7SEL)&<4bQOBksr zLOPi{I-Y%t^{>;;r<$*mnSg{lRx2yHdB>w8!oz=ljXd0#EdKV*$nm*v_Yw|z@7P!% z%RAtBl0qL460)1tN=gD|(QOJ8{V@5e^P1P63IHdI@rE8J%b8cG z;$&|*IfXtQPL_zs?7VSv@IyM~yf`=v!W7UMa9-Ebf_tZbT^8J=3wT31fpxiC;PMf( zzQ20Dg{f&nu4KA`qoZTGLVQ#di|c`z#$~PhDZI#gKY0$bk)9&H)s>YkSyX070P-r; zN=q+Tadx~s3mq%1I7lIU@ZcH41ax->#oJz!(tfkp8U}UWAdkc2$B!T9r-y(~3pB&C ziW|gVtE!FwByo3lCw}y3Yw#=o&C!jkBasy(;xX?4&^?Ym=`)SnMx#M-Y0Jy4lJroW z2M-^ry?*WJMjw!wnR)QwgUA=P8kc>b5TNnrG3a>UB?zE-DF5~F#$^(8Ay1w>QBzfY zruZ&yzAAZxs7{kFF8k`S9Q=@__H?5PQn^iq2Ar;^iWwzU{8L49Xg%c6IfRx6X+ZnY zmCVB`U0znkJgs4CYrDv~Y4Y>)Y5yrnXxZ&ghu!7Gl8TIBNDD$Hb!Mrp334@=kY>qx zd@H$iQ7WmT?;?TD$@`Ztn)c0cQLXP}$$T`VM%nUNyC74S)3sj6rH*F$9W|xt;dL!fKda1K=e#~aTuQ1et8@m9Bgra)xo@=CR0a8CzerDfd-dV z`VyD`sm^2vn#VLWe-EcUTX6Cc6BB`v+P;(qvW71ysV7vGzO1;I2kx_&!2Nb#SCfaUPfuZAe}AENU9Htj{oD4Knd9@ggV8xS zxx9RQu?(-F!)IP69op!Awrzyv@x9-&?tF;!*P*6*w86o4OlysFGsV!YUX%~gOYVy| z$&NkFuH{bJcWYhygga9KbF?lKA-12U!UWory^f z5FNYS0)_6o_q)DA->}V#R8dj6>-XMI();~;L!)0DZ2P@YQfDXbjblH5zN;Yc!$u;v zPB-gP1w5zv`*8%af+*XH4ZA6Pth$8daap4Jrl&9e_I??A@z%YC7yr*wfd5ym*wN7u ztk%iVkw%5hjcKg6dU|s+GZ6_1F3=U@2eElxxbeos$Hr3QVpeDrh*8#O(ol*U=<8P> z%?1(Er2+s1c&k#N(YCZJ8vMY^a}IheQ&ZC`^j4})jE~O_Kn6(G0?n$SpFhbcDC+C$ zKLhMgw}l2@M&@o<3kwTNLpi0%rsm6+FQHY`*Pn;;5=zW-FylvhA6>`H>=6#mdn6&V zzL>K!SBlazhc#8Vxna7(YMZ^ky(1&4KH<5!bhSTrXM>nLF3%6!W0?p7gaLQ}kq>1>zUyQ7HT>!?g(D5Lg&e7!c6XjyG5_&A4q!YW zH#k^X0ZofT@3*|%nao3Q55H`c6YV5gii+jgGb93?HhKkmKF#Q5yPuz3)6>%-IXabG z)j&h+RYcH{HoIGWPE%)&>-^i z@<)c2Ks?>Nc@t_qJw6>9Tj}S|x*#I}XX!Ng!tX9H-B&Q%Iu(b0%sla80eP;@SVyN17e6)= z=K{ridMKGTwpALL9z`T~EBcMvUTC}tSCF{~|GZc7rkjW!X%jJ-@u9M8s-x%A!X2M) zbtJb2_T(LRC&wq>eO-s#1nUdCcFpV4_wV0-{BVLGheBuAmGqQ}iS)THx?e*Du&~es z3knK4IdP)=GnPRynGNQpqPn@X0BT1&2pHSjMP+5mw9&Bi-TbF!9I^ay%Ngfslhr*A zapLpq8A^Mn{`M+b?)$HJc&dQjgKXqWhM=R%Rnc~5qoBCvxiU9r3))jhhtyp^2#;cj z1FGDcXnV;L>6K2~6doI#f777lC@8q(EpquZCwPe+)U*ynL%1NBYMI%?U3}^m=p4tE zMj-POXMQ#=+&@_@WGT#)P8_nHQT%HV;PL~7c_GBz{2%15M@MJtkgJ=SQv&+C@5JiC|O?waU6!s=Cp@XHju4VltNyf3FI^T&QF!C#Q%q0Nh*s`%1_t- zcb?tDFW{(P_3OM5B3Xez0+%6g4s%ul;ZuDTQShR!f|n2 zy-yo0QQrISm7;CkYwi#V3=139y34`zA2s}cYeD{JS*@-~E&sO{;D5gRzx}LIHqUah za{te->&YsomdZ*>A5&8Jd*uK2f#w6S_ZIh+djSnibJp&18`?RbTj5d3q^zlFZeY-C zP<(n{0*j*LKGc^wZUYPWlC8&#iGF9089)n|<3%iM!nG zcn6v|{Gg^8E1>dqb#=ym5`NXdioTClO7*ZO-FZkSohLBJ2^fDH8mjQCoOb9 z>w=mCR6}AXI|~ceojdOOd;s<-#a*17c!xgN(Xq2Dr^)rON=H)0w!cJFK$3HI-q+WR zmlEk`-Ce&5p_I6d`>TtK26z1wm6Z=#8wsf!-KFxHbgen+7A7qRIyXh46VSNkqpzOP--#iJgRG_Jw$81KFGqbWNQY?IkfM1NK`S_Uz+6rj!VNpQ6P*MV(1``t#+6PE|P%A`&A4H_4YAY*$K*F)& zC1Ika%>lyl@#7ci3fSl~OG_Z8jG41iQ@4Pa0MsP72K4m@1_$A1fByX0*a+nS!QRv~ zS0bH49MJ1Dpgk3aqaR-tjDd?4`2tij76S36NR>94mW}NdRg^sL!u-5XH{(Z%1t{Wg znd9YX21o+B+uNb@_+kvS*l1JJ4RX8HAqEwdVJIXaA}qkU0V1uhM+JW7d~_9#zNi_T zk*6eK1SBLLdw=E6*xA_jGgCdFtpOTmcc~ki2w}v+($eO1op!nc7dLkwYX}k&g@}j%hbr0Ayo4t`*#t;wMiR&28MpZQR?u!qsHS%0&>?oR3^xPfJQzedHkP z$F_r#;|$C@oFY~FjS=iIi2qx62tP(d=olE_12Ny%XS38rT%o~uKL8X3V7gIR@W)I{ zVHw6mM2VG^mEXQSyX$8QdB zH3$RO|6x3}eIX$}e#TcJdk=UnNK};f0fLu~SAl~gA%l;PZ+B-$iT0JGB$jw2x)A!! zo0#a{K>5mW?CIN`oeT^OK^I`eO6U^~*h@STT56z-pv+R2FAy$aw9=F2UiBDUWNs6AeO-ugUJ9+0c@eHY&QfQ zV1S6nqBfjK(3Hze0BkGBmLJK>R@J@kL=15v~6H+q$$1bS0Qo{O%IxDA5*bR#8QW zAyEKXe>^l!sCC)TDJpuN;t~-Zjfan)0bGG{F7T=xK*X>oPL7S8H1;9V6&?~05a2?) zn^RD5)hz&7{#a779kda+7mLZt=+9XY`b?_dz`IZfp!WSe{s-K4MoLNppr~8vCPzoV zH8vi#VD66S`x-ialJUnSt1VadO(rhpOCcdIU*8)ZiLtR)Z?Lp$H;8?^LPHA-111AB zjIomab|{p0SXfwk`ddiXK%hA}{g9#pAp*$y`png_9Lx1U{q^h3i3%38k!RPhUr$#UwcadwrK}8)7|2j~G1yIi zfBypZJ#@R1{kGOt1O~?QXU~38PiZig=j33fhTk3-2551ila;`{KfL)(w0pMO=^lo# zlK5R6gZ>uoQT_&Gdat+>f_&xR?ar_zXTQqU#0#Xfe3RPs$X8!1?wf*@%ftk}(?{8wG_cll*CnbRhbH#0nr7QTzfyxmSgrx;7lJj!klO)yR(Y1m_>6ln>Re1I5 zE)w)Y%rV9~7B9m!1DpKV2U@}0TvIi*hXucW|HizR1T-3?i#;pRli9ISQ>h?%T;JVd zI9>34-Z!AUhet)tZEVOO(Pe0ET=RlPuzkUeA7YSyw}S;i&Yv2#q)z4o2_L%Ftu+ET z(<>_`N!?(%SYBP7t1&221q=xqHVolaP~*m8~sHP*eRKZ@-^U1K}(HQT*#xSx`_rl(DLS z%(+Dn^<77L!J~0}d~9uP4df{(9&n{j{Z1L^wpuwgj$`x;4BJ{G5Em7;w@Cf2r}r0z zsnRpj((df-t#RUAw0RPP2aYtLdh0rm83nZow@15;i&KR{6rOC#WY|Y@pX@u1Czwg* zii7F%+3R-hPiBLDbl0@)oVC~R4Xmr~G#6HL)D2A328*#7y4^;JMG?zh)RJbuq8~=v zz>-AzWmar!cZOW{eI?x9ciQE^7Qvrv6764^KCm*VZYSBZa`ImwnUMCeGcH&;B0$d; zX172;zf>fRHeXR3&z?1FT(C{`^jje8sVZAxE@EV0h?YoqlDPR&o{fzy`C`K%@Ywe; z;+pJ`nW?E>q#j9FX0MT0q%gvM-!xMp8|0&SDJ<>oCKcChdT*HsK#iX+_Sc3 z<`XXRMQ5>sxl;_;2#_7BGh~pZ*;(&f7pH?Qq@HGmhN6-4z$p}YoS#4+mY0?$g$YmBb$aXu9bm1}wkeJ~S#FYbn6WMoE8QB}nLa1!Wj$_CKlsWqGBu+loqdwH zQ2nF|W6lqQ@>N{g#hmEWXJY@;I&Hqnv;^LY%`31c*Hc{+Y z(cxEo6uBb)k@)?zH=G3vVfBPyYu zH&qo`ck*mD$fZ{~nR*EH{fY|bo%yySb0|$ss2%hND}L{C%5wo0IgZI3teKr8;o94u*IKbWje z`1+L+3K+mlpB^ad0m%B07m<`6zixxY3m25*SRZmJK`{=fJcW= zs;G$XUUIBn>mMW#PLumX0IpkHO#W1XckhRiJ=`H<#>U3_`H4a~v9KtB>T*zfyY)ZW z{cntj{+l6-G^*X3<4o7W{wY3x+!l0e`8P^fku|aX;I1g5h<;7Y13MvjHK~;V8)f&R zba6*^q9PH&*HAYQWu3fEDijCxb?uvB>#o432o_}G7x9W#65f<&r7m`E`O-c*r(2c5 zaxW;n_+evF{@-@raPgl>_fFK(tGeDMZ~SgY* z;7Z9JGy$!J%CP?Z=!4kybq^0;P!Byk_(}W$%r=SZt3Zi?LYJJJy#2aV9aKx12w-vJ zwL4`vO!V}k;I6MkLZIVL@9;Sf4GjUR;mjW}Vg+FWK@KMC;?H1*fQCZ@@E`mdsi(TU zycYq0*vUFiQbTsy=$yHV5RosxqIZwo0IcygU!wQ0o-d_(0;mJ~D|oM;P*Eu>D^vK~ zzklB-p{%^z(asJ$Rn2+@5R*T`kSO5CfQ-L9-}D4m)=<%y$~uoT`^0NT?DGmbzMa<4 z9)mY;KJ^;K$utt{8yl;^+v7|?$#bifK%%F1x3mbFn$odsSI#YRJFtRp0*E`hW-{^b zwY4PLpP`vnp^ZK{Ie{wxfaA2kL9I;g1BGHsUR_S^jge97+&1@QPgL*n@U7HuMXK}w zQ>!zNq^_4Dd{p0BgSMrDQR?G35gBEY7`!^tU@-Us>v z2opd?jg9$*EG#d_Cna?(*i^YZi%Cw_1h(7Ej9v%{$kD05Tm`T+b!>Z~Muj)>J^~#S z^y2dJu#k|2Z6{c4rw3KJAt%SjP`E)~PidIpcsI)i5qhM8m zQV9hUfR-8i_`m>eH$oHvl@wf>r?X8#phyo5;b&R^uVhnk2COfo_>NOG^h^%B5>Epq zq@`ccMnf+QRC`@&z=sRZP&Vm)2r=+93t!ohYr!Z8Xc2ztet`bMZ}?RZRv0uZ_r@*j zUeVwJ*?YA7TossjknE;CFV91x!y=v5_EH_bvOZN&oL)yYq+Ppq4cb3w&}V07A?`{`-%{-!ot|cX{R*{;KehW&4KYV%Vc~SaRYkC| z2@DB|7Nhj?x|eDwEU#o>kRe6&7y($`5}F83mV@10NhvA)6wJQ!lqtXo)5iqhutv^q zI}u;?A%G9NyFIu5`~yyi{{DvYZf-6v2>Y1mXlU<27;!N-`wqVS78j%~WA4a4yMrGh?mCkTVM3gz2#qeFe+( zm&8@2=>n<_v(c%^^9Y>!zK9GXT7mrY#=iv=1Ki@DUMFIs{HcXe?o)y8{=>uL69HZ| zL>TX2k)bbwm9_hH{h=7RGKtts2Ko>U)wbTt1D}d^}xbkMT{WIwy3Vxpm=s3yI3P-dD16fe#SO0 z`CLi6rh#OKo@ebL^MR<_E`_Fc{@D3l%L_xFbR31;zl-W9GZfpFj&?hBrhY zn^uK|SMQK^c3#?K*0tMgzo2K||CIE^8qNcEfZP{(i-ab3XSQ~>cZ_v~6WdgdL+TEK zA5R7xyc_1E)cr>uRhD@_`!4v%g5$ORhLFi&>{rt5Sb~54!m(cg2{|Yr;31ggmr^1V zaezL#O&0ToV{>1&ZTHqdW}S%HT^-#{S6e!037vH?oc~-`Pp6d1uP8JZM8_g;basF2 z>_&IoE<<_WHlwgHD)X|Af_-UWaHTNT=pF+O)%}e<$5*246l%n?Tby%?-_Av{JSTkA z36Vh!I|!Xq{uAuBq`&d#+F}=u1h1%HYVf!7`4be^?jpG8H`eYAQkRpbC%s+hxcl(E z=^q*OtPA_Fo&H$tY^n}(XG^zGImZBdl{bxqx8s1l0rA)r_z1DsBg8k7lJK=PdHt! z2;yWiql67{u1LzwsTv?HMl32KA|k@V?)mLHVVnqHl-%x7hW-a;B&;jI(FPvcsL)0E zKYwq)pPo?g^J|@&%Vv5*gW_??VkUl~EeLzGs-VXCs^}bl3;B5{|+vN;1uzaHl90N-ad=nTk zKC*x27Z&n0s}3;CXsD<%Dk{{ci`@p!yQcgYxni@XYbE6fa;Qm zCstz~szN#ix&mf0h(2K8g7sM5FS8|(Vk zdtDFK)O=Cf^;k@MT#WFBe>QVO1NI;LjRF+m(bR(86c5iAjFLBZwjUQ26@k6xJVN!b z^6gFKw{M@MZ1Q|N-?{fVs%;A^H?Mu2|NHOCV4T%Vlg7$nQP9_j2|j%IV8TjB?30eQ z@)au(XB>$VOBXb|t80ry&31c;KGKp^&dia-PS;W6+BXfqx?yKKTU&)pM?n$+4_+3Q z;;gK{V7me1WnosjT}0DfUazIL4lfM%daBHI^0n%1oIaF>&l18it+ zo*xyZC@kCv-kLmxY+zo%JU+&VWoBXmowbUya|LLBKwN0iM705>2NIxAPLLkh0|V-J-^y`Qlki;(#MV+|Jhx8Uqt1*9tgO*&u)2Zw{-(R4tqUWv*;Sb^pa zcK|kQ3LlS)W5Wosk3c-e$5(*52rLgg&&i?XCFP)^TAXi-vZ;7PUZUHC2{*D{!vid& zm)Eb4PZg0UaLU6p$`q`Pmev%w&S8qJJDG>WunVY1*9!zvAAbrj8$Ckrqx0n9T9fFLaiAe>|VdC2tKKQ}0y@&G@993{&s;i;i3xI>b(sHvv;(##fLtw&K7&?n2cjw!2cP#L~ zxt;78!&@2|`6oKUVbHWc0myOsz=5N(vKU_O;;`lz`{EwgnZkDpo~2Z`9gL|)fW!Ryt>Hi?O}*^8L)?9b zI1CxN`MQai*=z37X+LYO`y261p{oJIKi2y+MMJ~Gn+A+jj6K#f;AsL&OiS=XFpQ(* z2S5!6dpbZvS~|L6pxVF{55@(b9xy*lyKeFU!CZ}>;x5_07l=pa0dpU+{Kr0>2A+Gp zqL2-N1sU7Fnr{L98G^|a8iP_3ysm-$y}bd4c@X#`-mx!HiV*w)y_RN=vwuK$=pr4$$RP%Ch z9ENaAS=rlnwzq?009;HOxa1|ShZc|}!5dGD8wgH&@R{8vV!usp2V!JX5J90<4PhZ3%v!+$8&#B1-c8cR`NnZf&=f`rwrD49BLU}yT9OC?P_mtz=GI6gdf4!1>^;o zrAg+p{m|A|W;xA>9|R){V0i^k>Ia~6!9`(kezFgC9f(78q5txdjhC6v?H*sjQ?Qrd zGis=6XrE zR{!aPSe|R+xAWtelM8as8LX_WN2{HSp-90I@jTxjzJY~r*T3wJ@xxJ+2_=@V3?4QB z`Q`cf>%gwUBJc0+_A~Yrogz_>MS`8+53o^S!;+SesGk;HeAaKo3WoKp+*}sWC}?ou zSh$19`Q*D}vSQiOP){NJsV7d?eg(CUSa{8^)8&|E3QIaZ_LfV&^fJj>{BbLH&QoQ& zLPCR^!fjnI#`pY7?#sU*%R+~@j(>7`I>#afS@!ZiUjoKY{hAs^IVGjW1)CQr6cPo1 zA9ORF6d7i)%&ZSWk0*je4{EZpvI0h!Cb3fl!NtSlSRF>o#r5#g=piBDY?>N$@lEw# zhJmevHM%lu4!P)iwe+pV#6Q!i2T`9N#;IT)5P0qNu!+e@Ab-Uor6eVHx3`}&GsC!L zeqJ7KP!nuD1SRm4h%`8!0+(mI<(AVTh?z%0$24qg_K@OX71E7QB9@0CSU`anLHdA) zhSzxq;%nOmc=&aec(9J9$@wE~AV2QzHpIJRp7-IAgmJi^*iEDbgK24N>xxeDCcCm& zL`HhY!laKXJ^o`KaA0pK{ee^ozrdS%D-~<15(LZ`NlX}8Aj6P}q#o!DtmJPPewhw*LOxT4WD2&9&# zCUPGbUN}EL-`>A9sgQK>;Th}j<&n?UzU=%h0g>PAGIFfs?8+^vX(qpwFqY6239M1g z-)cS}GOE)LFT6+$1`%mstc3ZW^(XfO(7&5NlU%;s>t70dJY;*7_pc#QgjF|W*Vaxo zHu^YUWf>I}Kkf3@v8pfiZ;Xg(lr1 z5P?vwEiFq>lptVm5{J4{D zJeI{QI-rz}`*4s8{ned7gWqu0-6JA1sE;_c8vqBND-t46_V)H2mJU_=x&5b~A6!jFmrVa&u;C5eq|Lp~UfuvA-2lY=(F2l^wpn;_yrgb3I=qE=3mX9- z7sdnN7#V@=NJtonv~hG~0^5qXI0gpBj1^}=K>-xsVQ8}hLIH-u$(5Fp0^Y*PY753k zz=8r3By{*e<7~uKNCX_ki|bx6;XqE}Ik4&h+PoBh{yAEejOnxI&mXdxD7Cav5@Qj; z9f=DR`*3CHGe7iez($}$3`=PP8U}&VQBhWQ6X4VU3HqSN$Row?OfUsaOiT>GTD;)f zZ&#)0!z_mzacO@;0dhDDDS9WHM^}ctd1o!%u$Ah zSJSGHKYiq2Z(vR%{?XORgsRaY3c(2y(BxNbbfMd%{AX}lS*6<-cCxgB&t*-jk^!4h^88L)nR+CNR?7+}sR(DTud- zG?;`1_Y2f=*llL6SvX4qP!@qBEYPU<-ha*gP?aGnH8u6)#}dFq-egmN2cfP3?luj3 zTUk}5qNEf|%!6MC!xW4(G;enFVAceDx|KhEkomxEK?iaQ7@LI@rgX19VgW%8av|`+ zOQnu;Fl0Inr4$4+kfuRE*-8#__u9mF->f;@+uH*h!`A$tg1E%QIsnEz4r^I3BX3i| zV$fm4As?+{Zq5f=2To%s?J$dT)uO;1fm#Khl%QKY3Kbio>jh$Te7qZ88V0S**a1TQ zy7El!gWv3ItKpty_4ZBiNB|b39!EMVPflB*@O5D-r$^j@c>u#y_XEg{PR<<3Q;uP$HDLT^fgTB95I8kJl^C0>7|Dj(W;R~N08Si= zh-bGPL;*{2I&J-dsC6aj(3|-XET3{5Be1~GxY$#Q=M!;5w-`^rVo~;Wy~CEtxf@9f zb<(pKq{~eud#3J6z_xZoERaX*us?@I1^)VHCqrG`Yo5#?RsNiQS=C5*u|alqJ>y3EfAZN+9W4+#*jQOA8p^m! z>}!D}%sx<{42s_}tC1F)l&ZVK1T?4vwMu=CO};m##Dvn%aZ= z>^yDr@F4v|Mze_Ib>+7&D+*Bm8t?vo_<-`y9fnE0szK6FRk~;iZ?cp7x1{^w#sFDU ziXWttB)7JAy5#L>Zwi>{7!M9+vPvHoSy#@?EF{Nkm!9v+uCA`wz25aYuc~ps-lY`^ zA4U5s12=cTloW6xAo+J-cC(&C{W0k6hv{Oz55)uBHdUdBR z>BzX(dz7I2VrA82Vbvr$cK2Bu0M79;vj=Odj}|u*tmy7Cow?14))pwweL-CY*Zdr? zT5T@P?iSWOopLoo^jB$wKQAhn&*XLaX{sR}b3Z%rC8~+KFH+=-TzOJukI3SRVWR z7$szIH?>e1tld6o&yA_$;~g=b-dHczO2Wln=^q+9X}FlQHIUKyZFVYfu)+2%fO(zh zD0wgZX?iEF5e{Y?nlCygJK2a;&rLj{u+9RbFImF!M4Hiox~r8{4u_+f-)F~G3fL=8 zkec7H?}fDBV-uw~7UA`LcwsE~?bkI7T(Pk}D!#5$ow4vTaTkfFd6&}!zx5YWOuL3B zDhzhYFP%>UL=oiOe7lW2mIN2az7rMVII$hE-&2`yM_taQ!c)c+YG-D!$XxJ}e>J(( zsxbSo;puU?`nsUXqpg~+>i1~GX0>~T6!Y;AQA|=c&${`gYNu>`&falxfhw=8!kLhK zxIF@5#45sfEuRdA_bWCkSE-3I2%O98i?xS}krtveRQ|0a7Y>r!=?e3cMm_AzCtUmQXwPuo9a_Q%vlh}{l*nBbgs#IXyqH0)kVH$TnE z;gYszmEN#dWq;jmCr?Zz%oF&~o_hV^a>nNQT zj&TI}%*+f>1?pei{}d8wop1l3yDTlg#zxe92kTx~tLORpzNcI5)_Ui)nMPPyPxs;9 z$(My|6BPv;2eSNA^%e>HOy>x{P6yAvHh1Bxe5xQ5qb12g0(EXm<(S-p@OjNWbHr1mVNhko@14GKdOUd{2^@W?2)Ku&-4KowA)9Zy<~yaV9}~xA|H^ z$ua9vZ)!?T`|`45+)%<$_Mw|d(^9|LzLlzz6ZBBw&qwE(on-!S9N%wCWlt z4HFm`m=`#`?Y&-XcuB(HQC;5X-9AIrEseoDd4o4_7Ad1IOiAwZqLRIn?~v~(%^HXN z>(PrjO~+ejRB5tkIMx3&?kt0~5+w%S`mh$;iZg-dR=;(Y`mNXEe31Oox9a}=gt8xT zjEU8hRO}8FJ44+9$IqOI#SlfuH3X@$JjqKVb+W14cy42O@pJ+VQ{N3${y*y8I;hI` zeHZ0pq9UQB(gI2&NS7`JNm06y?(SAufRuEXNOyy@gmia@NOw1!dwssYefG?mJ$v@- zvuDnn^@p=$Sc~_4pXa&rx~`i$vP0L|!q{Ela8Ns&v-$@!ZT4}8U;d56xX1XzePiLL ziGnk&m%-%N0%eQQQ@4%m$TChYXA3uY>2FuP*|~GgoXPpHlc-EE;rIN9e`r=``b)r} zz8fOu-&NYVZGY>6CP^R7b{g%`$aYbrJRs@+r!C$$!&sK zoZd>42gZojsUyLk3pMsvi6?6+=5qUZ+TUDr=3X%8b9(p%WVd zuI)Q=ZTj_ZYmJilSVNAK>%FQrYZEtU^6j}DaoHIS_4M_Z&SGco$Zq_KiQ-yGf8tH# zg@Rz8{!U;26>BDEN_$$~v7$q$7doc_zov*m@^yF7-+so;1N#r4UIzX!u9Qy-jN+gF zvEYh6%4v7LjP?nok;3t*X>9oxP$;i}gXoUS+;iYVVlOb3yH_vNKr8|fi`W@Q`isRp zwDF0Fv8;V50XO&V@S^8^eQx?M40mx?*12Obt|*bj{8kPpr3&0Vp2u=@@CeXe;}`NZPPlNJm6|6fB{B%OvG~DD}rgme$-0mHzoLPL1Q7po- zclbC`;CwlB_xA`!ndi&FBY}e4eQWc+d&Ub{LlbqUR#_J7xtt6Fjz1!>L)`W@vhY^- zOFYH%WAHf5&Xc7C8o$xTMJd{TocZGzGIE#Wobk#Q(Hil?eoS&;w71|qCL6Ag;o{Fj zgvi{)mg{BP+j}9ukER?|<|blY_Z(3BtM9iaAppPS~6E_ zL6>LCojF}P$h<7PQng$BY4)xB^ZV`0##Sovo`X6EcYQsJcium+uCn`nQHLcN&Q(i>sO= znx{Q9NLe`&7yE%asHE^_eMSY^znHNEPtx{BFI3tCv2^~nijGWMU*+SAKmE4CrLyO` z;=JXiKGo`PgZylHhvFfP|J9i|Gm}zLRGMK-S|o$g`B5Z?L==nL{tr~H@JWN}ay@oS zl~4C&a=&l-JzoW+`6;IyOyKaOC56-UR(<|=a4~XTQ%k;`-(G3 z+Q}``?pvSWe{U|2e zk$GLCX0Q47nHq9C@8{**TZNQ&L<4S%+lTh|I4>;n6jVM8m^-a1l=n#a^Hp8VE8MF+ z&J4$9wHw~ZCi|&-sWW}@@OJyO8C>Q%k)FjTw(AKdtpnWL}YQU!A_`dir%qm3uChpqQ-P?c!~p zD}817_( zI)2#mmLmRpHbT12oK1ri)J~gis;wdLjZ`_>5^Rd)mT9_V)OQDYo9onfv7oue^@H z(J9rYPrLc_j1JF+U}e-oPu=A&1_b)aW@5H_=CY1A@VJA48HDJz4EZwos#{v=P%Hquf}EQp!Pd6*6xz?2-Oxe+k_v_Q00#a_l!R`r*6p1KU2*mGVu zTQL4>KNd3cHYL{ac7p%Dr>8(Rq2JVw!+*+czliaWlj$2aF9q`b7ovei61fdu{o!`I ztDT;!^TH$#>GR8(a*XdMY__(VqC1vIt~(S|(&Q;>>G4!_>LOVJr)O8Di*F>W7w2X! zHb0E4)-ROh~I3{}f?f3q7$#OQ5*ISHl@iF_BCowRUX zv9~04mE*efHnFE6;`scnMaL{b?rkQDzn#&=Qi8>1OWo%2@6rcWCM)(P(i4@uM>bG5 zbB;K#o;Ox$&)O!1hoPoOl7xS|iN`rv9x8Tgo#^C$rvv+|>NT3RQQ z-QAcE+7iR820{#xkB8kUtS-9qkG`7KxEoU9;Xik~Y{yfGKh$S9%AnyG< zcPV~Jg&Skw6}qMKq|SMh&xZ@nGnuxC8imP=L9q%47Y2=}ob#?H;yvz%ZJY9kGIK*C z9nE_UKbqRBA_AslYV$o5ugu?`6`jd<{%EWiJXR{_cexs}UKi-tljKYtOtE_L>{relS?g7r*pJ(c7dAzt~PTDjsYo|n8 z_4D27oR;nLFDm!;Yx}nto=PVl6I=aAJXE_n8o%;)ovoj_-0M@6)@M9BI}Hqcjto1W z4?p%Mb99_PE{I@zYgc=|cvW$S!nR7Ru4<<~Qa!d{uAY;zUd1+|=G=KP;cTd9>0XOX zT(O*)+Eu!gyU|v{0+CqZ=FqxN@PT)o(@O3x4Wczk(%n&e!2_#iU;f&VozYd9`&G+O zam^Dq0#od*--{@(I;#z6MKmNOf6s*kH_%WNF#G5xaD)avRy=tcs#q!cpzA2y8Q%g_4>7$#+1im$T^98kgkt!QMrjE@vc#d&Juth!`y zsok3_usr@fJ9_DWjmkN%sMDrK;bYsD`0)1u%_VP5ji0VPqws7>*Z*0gmCQH&q$QVWL>@vEINN6@OZAuLLU=udsSICK--TC`@UaFmX~+ z!aXO~)bM|dK3FL_$c|)A;5Y8BHr{HVl3wUCF&>*6(Cd8Hc6XKQM_avb?Oj_S5*H2BUd;Ih$Fd0-m=G!4pIuo(c^2cV{{3B#$ev6USMROV{0 zd}g>MvXcIGN${Zl&kY26xXszP_jK*WjK&cC7GLecK(Zg{M2X2=06KbhC1$4l_8S!p zA?Wg(kyd#t64(^;wC*VB#05SVmlt)eJYA(`m**nQ~_txU)HX4%>f5?16K>@%n zKvomgm;yiruF#3yM>Y%qmfL|C0f5_~K85u3JTc7Qba=fU=3q{?^B3vR-~0Zp$m`c? z>tSvD52jDE7@6xX>#SU`xA+7 za~1wn`!ZNj=4uC^cz}?;|A1tQ*PE1$rgG~gT-B$mNBpNLjSUR|qH3PA=mw}6^sAt6 zzm+Y>!^;a?Dd_ow?hph#07XB?*9<*wE4*LYQnS$CV!Q@ojeHb^g**4t*IdNn`4`s6 z)HSLME^a5f9F9FrTru+_Q>^|x{uG%Qwllew=vpOLzB~(+Jk{TB)2s#Z?rl!|xua`J z!f+jEgx^Wqo_jYEahgqnRv*aZOqtC9C=eiZF3{EhEgFy${sYZk&@bIsUnd4}3mcn~ zt0o>%NBvza^Sbj5L&Vpm)^z5ps&|$Oj}n9a`j@mV0#h>n5F4=?NX#wyF463(WDI{a zB{Gib>|+bsOcZg(#ekgPpc6U;6@}rc4yoY|_JhYAPg~qG8m#?ZajhTLUJOj@6J5Ws z!$4i(erLfB*t-AB2pFn*#{*PV%3!F<0mlTu8Du;*UoS3%@{f-lKoX|zR}3~HM859O zNqpLAsQSr$D!Z~joLB8KyAaWwRFv=SC7i8E?kR8v9giK=US5u;TbC~i#Mkn1M3B`j z*YXm$Iy=4m=e9xJ=EQl6y!_C1TC}Xqv^F%6mk_(|4-nGHh4>NbGue-Agbkwf9ItMc{*re!+O%Ziv!H= zV;mgIo$H?BUDK{-$k4QJcDSfdM&7+5>A}Il+1c3v?jg7#V38rQLE5_ZPRh*D4r)uI zonO0|wY+>9FN8o3Y^nOXgZdeoYQ#DJCsZ9C4b21jzmba{UoD_we%KPY`~Sgg|4+&Q zJ>pg!~KJ4InFZYtAHBPd9~>r?$J+JCR*e_SX)7?LGaLz(rH2Hk%v zAF$*!RRV`t))E^5_T=^Gzp44J-!Jw@He3P2bILhAT5TvJAQLlXr-=LuX4QpXwYyywP6>xZfc(s3T4Z0s# z{QJEi+a&Ne%Hsv$ZZq@SD*LT>5)yHsz+`Z{e}ek)=&uU`28e%DU%VF0sZl!U;+!FF zct7gG^S8nlcrc+-d>^*k>5)O|6{TY)Ob!d->+Hr}adK5tn_vv9&v!c>dLj^Cr{)wv z=Wg{j**fnwXCOa*mYZ=*nl~GFV9Py$2Dnyxkb(!WuHWyFs3?cE-0}wqlvo6!6)>X` zG!H3s3Mvj#dkkIxn0U6w{nC0S5F8)iah7d(xQX8Z0v^zkW0GTieV~JF3&2^#R{+iN zJ99*KkTe`KcsE*tbbU!l3B`>>P>}@2Id96$Fa$pU7@f7?0zETl*T3<@X60Ze-9Uiw zH9GD4kJmZl@c!8L;ZsocT|@h|VAjh%{3J}S7>S^mFyFA?LX74hl3LY^(`LgJI`xX} zzjJ0EPK5HmG%0L(lY|ns2MJ$Yww1EsvfAro&zVv3q5$|)$du(H-2&J!XmRO#gVN|Z zyyqj8N|iR9spT(OIEefL)KiAuxA=b4aFoZ5LCn>LHWEc0X68KyI|*%bfSaineEdAH zQlgyu`f;KyfK4gv{e0j2P@f^WX%31BnIKgM>hxRb(}rWtpXQcf3GeHBI;fQhp^KJ4 zOjGe#HSpl8-cSzCYPlW&HtK9eii{8VpYyvQ`0w7oXmdte@ehW(=AK>TKz$^ox z9auPfklprUuKfuRucK+_K*#;_RoY!0?q`8=8q*@0t7~d0sr3y z6}%;2Q2e#DcZULIahw9ECPf-nfn@y{iK-z$OwgIYAB!!mq2UfnCLp}xr3nKr1OXBQ z$Vx;j^sdvT65U{C064f0xaea zFjk}sZZMuz_ikd(6$ltOIUX_jKI$u8BLnmgKV;v){i%oD|ojiTEP`d#c|b_ zf#M>>2s!e`02c+*2jD{@5|SEFtor;iC@ie$omu$=s4qiB@z?Z^z-7vP-{CE;SBt!$ z$5%Dw29XVb#{rw-Kv2IGLrYH|DnbRaa==f=!vk0x$b3AWRi;F;U|7R5f_To}&aSzo z<>}L>Z{NJZnEiDV?bAO*Z?s%-ij0OumWBaMp;C8hbgaZqK}AOgcv(|Wsh_5R+y<7( z^|sgci4a0WLc(8!>U5`t40a;`NArLFxw}<91duDRZ2-s8c?eA#Fpo`IC|$VQ{Z^o) zqo=osr=W_GQwAwN*q;Mueeg->Wz@i?Ky@~Nh44uEFYHIaU;=h$4kgwOCUh;ot`_J7 zpiAcSG~pQZuz=Pe87xxbe&xntJG*xh$hX@HbVGj9o_sgR0o0w^%rk}E+%Dnk073K< zP|j7GmBt{632JNiUgQJl4G?%%a5ez!4atrzPdqXRwt6DJvmGd;PakqaBG#yRg^zxN zBQ~IG1=V+frF@8h(5;6>0`w_)Q6y!E-N3N}!s%nnQzW2*L(&ZGp5DR2N@Ud)10oQ# zm{9XhWMt-ZbuzNDV&KcItac%WJ=~fh1B@hS8Q6O|r~qxSWMX3))!%__5ZpMYYWW)v ziETG_T{1Q#1Qbx31xni80OAI6?v?Q53h(RyzBI35@exNcvB*adnM7gNA@2O~;|I(_ zfpicK5y0$FT%m^#2LNUahlCU3unra#ZWjc(3dc-PTph?!t*lrBTX-#IUjjHB(isr% zl~qw$>k=cu^nOVm1)8KF5GQPdb1J-MA2+)f59l)>ngBwH5x)cO9{_X&I$byVwv@G6 zfJZAODS7|iJ=mh-DEml^hKA7k?qdt9o}^v}n8)DmEG0xzK~mCAdQ2i}7u$_^A`wZW zdlyF<5n(B*srLo5_4xPp2eQdrf*7y9e)a#z_O$N$YhwsafpZKJ`xmg+7OX1lxdL0( z4Gt2)d|<$aZceU`xRQQ6VLwSyMs( z96)<+4~@-@;VgrQpqY`8@3(JIk^ntYle(ei+Ti2W_4RWwwo5&UJ)4~md{XlAx`A~5 zSP>dYKn(&qNDHRE`Q9iAXw$*#$4K`uy+0Cp zk4J%zGV1$Xvlbt~i`BPcis761vW6hMvR>+}K(8nTDzSB$+4!I#MQ7F>3ccbJK|ls~ zaZZ&SWas0n+RBMot@)kHW9Ng_6R2}`Z6VYbUJzQ0UJD1d3M>iGv+mruR;OJQ zKj}eI2b{FbOrNe*bP52K!Jp>=mkA|eXXh&O13%6=y~x3>Wc1qH54bQfM!$R_G$iC* zJP%w49-sIco=-mT<-Igr$mW3=GM!R4^J}!txr-m_L$D^W*TGq86^=Szjd5a_<98%r zR~O&I!qT^X5BZ7PxkJ?y>BEOmw1FMnJWclP|6ZLnm0u({IQ6yNg1s?!@@7h#gm*!< zy0~#nyBau;0Ni_-fkA1iySIXrs%7vH|mTpDCAh1l?BKD>WfPRBt41hG+#|IAmQ5QO3>c;4gpel8H+HWy? zi*p>K5r#+=5jdEy++2eb1JTvh)E0EOAJO_cfx_u2{*7XY>)5s(aS*^SCUsg)at99# zc(y?P!%>J32&weSCu(3s5w&qNf_}8Hpx4y2!n*>EJcs+UY>uMwq{!BcgpaKVi5=s&kwX2#^iG3`R zZ|Iy`Q+vJUpZ&**-_J@wAREj)8I%n`(OW^)^5#U<45z>P{ZqAV5R?LzZ6~;_ISX`{ zlU6m*%J{{+#I5CyfJR*h;#y9$I=F+2GNKG!jtAz3T-h@tH~vBU_3M6~;4$UjVFHS5 z8rK9}Vyog>^P8GiI>xasE?J>;|hsVg#d8_ zg=vN@L5!JhPIw(A9F09XMTK>-oLhew5c%PYDDQLs$4JZ^>Voy{hHLBs-3sSG&mU`} znGpE3?8^v0oUUBvck*3#Ma}q?;TeO#dFF_Uz-jG%BQF&-wJv#EJ0wfzhZE-ciiKZV z=1r%oPlDf)YO?vm@kYg|pf3Ps85MN&a=5}|Cz$$l+R4`A51|Yckx<+&FmdwoFsulk zJA^~<98u$fAg_Z=6ZFS{{fW}<4Q&Gft3&WqFss1kc#p?s`8}kh5S)OmRRN7E!+xs6 z*c&j$$8@3$gl<57K$RRD%C}%%V3bbT*%jmLEb31j7xE4q}8V zF27&XG^0i`@ILFV*4(}F^!kuF#S zq;4QUWrE3N*yyA7d-v_m)wcw}xJJW4fdf5e2%r+cSFT*xfO7yM*J!!92ILRGW0~n! zsWX>>`ap>y!}|J{W!?>#JCiUbowrO;8?_CQ!v&9)OgV4+gAU zcd<{S`Bg4b*qFFt$8!jzDZFW}BuogT8N@lyY@D(pdf~jq@MI5U@ZW;^Tujs3iK_-U+m-fl7fngzrs3=%Y}I zY@&WZc(xc?52?Jk4h|q~ia2uKaFlQlqw5Y`>6-nV^Lh;bP<8?zM-P(Ab>>{?pFvp@ zcrl;@SY77@^(c!SipZOvI;J7OpENr{MUL&%P&oVWeE*R#Aw|7$4zpzjs*m7>H7Ssr53GV#|mj6Ghzm`K?7E*|*vs94r2b-J1Kc-mO2hLt?)Xg%WZfcaTiaK7B+CYn!%(_r>7w zY056!rb@^E)??4|RP!)#x|z%2$VX$FuQQgU(0j>DQ^HV1u0pZD*Y-)tN>?j)Y`&M? zAiQwq$&j{e-`$!Bx&8aJ`B>8|OdQK!6^=L?|$tqNiDm95>CXI*k)p14AO3o-ZD4ixtvc}AttDnFAm z2pGPMXw!af@K-D52a+|sd-9B_Mfv-8ZrPC-+97mqS9JEpPxYhwcUK#tWUuH)HCULE zeOI|V{!!N<77h=3tu`7-oLWKWDIsFX_2)DDY}T`n$w^3Q-BljYg%$YH5EIK^Oop`kA-8MJlyOhZQi7v zLsu(8p=E&*ALJQ{)tDzi^ciP|_h}nPRv$ZoEG4#QwFTE+OcB}3!8%K?>_K!U} zV$#U2i~_yv-OhTZQA`hE(-iA2robWca=mOTdH`}t2WNNZ1+C^X1$Ic2vl|cI9R677 zOlLJTChu9lXc=AXqn`Twc+pDUwXE+6p3Rklp#=++Y&Mv>|L(E*O~KnPE)3sK_1K7v zeMD94!t+cIbGobgUZc>Ksjk}R9?TyMZ&?Ie5*FKH7Pi`BQ_JWQ5bpImTu4cx7p};) zUyE%12q8OOv#Mj@S-HBgmxEaGPz8r)-=Y;aot0s-@`ScfC4=zmz}N`1vs=_d%NTmu z(5sDD?58QMOw8BL;VDg%%_^=`#g8u-tSY>2j=B6Nt2a~jmgcL>4~(Q6if(g!9I@ih zLJw;Qzv4YAbr~J`+M)Ohj?KgNp_n;aFC2tuDk8AMv-puJ@#RC~z@ZGeuZA)B^d-XH z_U0wgMd7T4L1~6big|tZ2Ql3KMwzl%{VHpck3d2$yxqDBiH%Uzix*?U>wh8XcV=T2 zW4$2lxJh1{yNiuDNW_WM>qwDyR2Qn@Rsh$XDxI52?;`$Lnhx(CZ6c}YAJ%8I(bCj- zcXeYXP2gDQj_2tN!->F?hV!jeA+==5!r`GzBlGxl>jiF>m928B1Vf4^t8JOsYJnm# z5?diNDeRebDQiqGt7%@lHfupNE2E6@;9bY9iMz2wuXO0bqbQLP*?7|4L-$(+c z|Jn4^#N!3C)UY<&2Zk+;`Y$Wbg=TW6^b_w8OV~fe46SDvGSaEd?%L9`f>owcNZ(a! zL3k=BOSd*%ufoZG_N;*J9){ZOZxVB{ibrZ}Ox}&uav2LRD8dv|LmYGPW2Lm2iUoR> zt-T)_%zRI^avY(c#l2@3nERGK;##Ui8e>fXKjW=rp@{hG2hw4R;pyQ@7&P=N`qs#> zu8asVxzjwg^#%ndf?A91s6m8f8E4^9RH;^BTFDIkAGDsQcw^Fq2wH*xEnT}jWtx=V zVm0B|e^{OwMt4^=s0rh3$jHuW78@0s%Wq^od*AW{bM=syIgCc(Y z^fyY93M}l%_@T=K>PRvlzRMRpRZhxjIl^`;RP#~$plr*kY4!@)5IrH`}4oL*=%(@rYNZ`iQ;S2<~Wi3BOFS8r>!(Fx$}$B?t=pTyw0 zoeDb#e%@RS`BC%;zKNbL)9%dWBeTSOy15OjE4N?&iJ>R^^p%;!Qff}VokG6Uoak^^ z)rP0xd8Za<R!f)vciPMeg=(CJ&sf8WsJ!j1IyWQ&Q zs;Vo@lxNL0wFZ*Wv6@lsak%QrngKNof=}x@)n%fZ#g#zOzz8l)uy|Degnn;8hLv;p zCsDI{L@3?15{qDa(T!?4b^#u_F11wJIu5+7JgkhpHNzrCx3KtE1V_di+p=}_Qys)f61hk znBNh40Q0FuyIN_pHV4E4U1>yE)aa~FH#sgjLTk9#sI`;hGu0Ct)@mNb3$5_=#q5&P zr}7fIjmMnlyzu$NjGd~t80pAaKEtlf+$JX4L2J*7dg5s!f1FvKOGvsY2kPD_GnZXT z_qpLhO7SMBthT>Ae3zZFq2t-^tv^iNvv-QxHJO9n_g{|cRg0vl(J>$ut$81y~oj*3`Hj5Z=1R2viH}wde+hTD4sY;#H zRifO={H<0b)@$o<1FL!Fq)Ccp!T8OWPObD}uFxK-83X%BUC~jz6^3@~l)tieUHaNQ zi2zyj?Ge`q4Q*aZKN@8;x;tJGtIPShW($a%2;%`>wN zb`n+e<1uTW;HBjJ{4J^d?eDFxjDnOIpnId#>F z(TKrRxTud?MP&cs7VoPzx>w3c@r6ecM)cOwH?qZU@f^LffM@Sl?d^Q>2#47ATV+3JOcT@RhDC0`q=#QiJLrMTFe&HSt7c*6ZP&()k_lrvzrB&1vE`%1jfNj45=%bA zVIwA;*k4)wjM|64I;@+K8O)&Hch-EwOwC5G_DgEUAxX*Jl4fRUvHt0G28|~;1!JBA zoc4D-ciBV2;>5f%J4J(YXpd?>TSn$Qu*sEi)>J-XuhYRx#7>}M7b4#dsIhWw_jJbc zqV0HKD^>ZthPN&Yj`2}N=AE1NZCRvjyXC>{BVS#5My|ihxo!?)idMu@I*Q(8u4NOY zv3gHo{v+>f;qfj<#tAE@Gk9BOBusYVEP?fQf+Ci#H3nB9>G1mv0NJ=Y#js z%k#c{{j55Cjg0*j=1{G|+{^lX5w55rhF3k8!2&+ECy)BDzvZkp*!(lMBcybFqw6{$ zt9vRrleZtbr<#V2%yb>PrQC9|gPQMn<-$>OD{r2Rd||FqiT zdndoy=wFd|vJ-$MlyOgp23H6t(3=ZX#s;!e)CPrbFWhl;jp)kwfY)0oT@$hy!z~HA zp{n|}N;X!3Ew7(x2GQLJ_+&tbi4IdO zb*zFT!0jg%-UnQvXS!wb!VeK0CCZ*Hsz!IJ^-P>f#iVu_z!FW|w<;FPEXGFQI-(|> z6^7|`+@N#ygm;P`P`G)RJ<_xuvNTalYsKS^_sRpdHItlQD>Fa6(gaHemYZO z4^M2r`sMdVvJ{N=sko0)(+3q_eQngq2r{fB9o!q0s4%+e`~xo=*l@+1OX)h;@mooF!X-rf7K|=F(OsOEIIoyvMs~eIHf+Yfe}?-YQmTfW zI_y?e!~X152GL;BBPv4Qv?}j`7aJBgs>Yp&F$ow+|L)0?7QfS%!<|s&sIhwg@EXSF zx~3TX{-%Z1@p*oNOIH2tJz^tmPm~@HosF-$3{L;v$AZ6^rTC8j@K(y@6L*Kl$UoCf z(Z^dAdEo0A#@A!Ap=UknzuGH+qs5jH?nu>h^x;{dgoF}f+2*yXyY$rIw;Tz_L@1Zo(1Um9kQ}Fp73cEIh5+ zv#`Bi#VsuReMq3lAUf@rK^YIRe9dG`ylKIS%V3XEOUo?hZ3-l%t8+dAXco#uH9u4?xR0}2uvI5p%k#5EQ1-Ev@bhi5!oW-m#P(m{il%7iGP|Z1+s#(@y>6XyS-Y6cXR{043-a? z?^>6cuwXGuht=(UKr4AKViKWQT`CQSgrQRP`q?$!z}yC%)gv`K9bfw3QSfkWnCUuui&bElN zedoR^O+bU@Adx94q?mY7p6l7HO;$v@&x^!YiwFbo#Tf4O-wie%L|A{$YY^h&@aSIt znC}Tilrw4(g?f)h>=b?Smn@jYeX^RiKlw<#e@DeDh|vz!GT&P(?m5Qt(q&(zcj7N= zU9E}M;mPJa%#+3rY;%4*RO-rCQx(s^<0-r7O5cI@^=;HU$t}3h6oCbJ9XIz{;uXCq9@bC1zxqkFp5qEDGu_c4_N~$ zI*-C%Y%eZ*cZFqlabT>oX!Fu8I5zW%<+pKEp;LrOXIrgUAK$r?+KqV^aFNzMB zPH+&*l*5s+EA!dsa`D)fT`pCgLYoc~L8rJ|8ba6AF|5M0zD648hpuZfliZlXNwS7h zCM%{QPVe%VKrFRnNOg`9=|Jb7>dn+dVqkq^k<~Dz{~x|;LW$lX0ag>e(6L2I5X4#C;8Z!wC!Tz z!6`5!NjFbyi|K*20zs}=xQI09kM=9%_K2-1eO+Pb5RHV8B>0)GBvB&^hBmW$C{1um z3XId$U(69D*v}v&oow_oIZ?gx%u}0OI3c2iP=+cbN9&&2)bDI6n0rAri$kgbV|*YW z-SD^8<`FE8Vl)t+S=IqJ|3M) zsg#fyO*y-F`~`PLDI)j5@waI;%S8re)o_{z+m3v-vk(*8zs5i=OXSx) zPQycy{vsy@jI%NQYd7baIvyN2ngrvSupQ(S+7amPJM<-(XXwA_|kLb+6Nky_N_c7<Jlc{+H)1d6ho5%xP7V^mC$*mG{E5aE5jvs{Avvs18(9vE&O2WO zf9hG<6QVWD<~Ws&lwVBQpH%u%3~_MqXTFl90jEIrc?OllU`kO@Kty&ZhKACvC_Pb? zi3_Kj-ElY%i`(4Om+Z^J4Sq(=&iI60KfI~xzK6-Tm*)c2%iiVzwr=+uWfxP9bG{2? z^Z%@6AJ#RNh9Q$8zn=2dzNC5}+P_z&@bnDbFn=neh~Pe8z%sr*|9#h1d zs{zrp*GL2HlM?uBVjDFM93^*RVCj11?@_JPzO80^pX#Jh9~kq}+h``+;?qZ?T^UD1 zC2pbz|2QwM3*gBwri;QK`_%Kq&Z z3qmiVlXdDIz)Dy~CzazQPBGFVnBeEhRl=rW%MUv$Bnq;;o6+dE@e@a6EW>J)} z8!yJ|Wd0GRhjf;LtixLRX|#T(a8B8RQYS(3_Md*-m?6w$ouA%Wxi6X6^d}@J^2+uX zSTj?{5TW;-2~}|;yRe#COL*@0(R-bQE}~&SV6x7H1fG*siQSUWMp)_!E5R$GC5!nP zo>56-)v*)Z-Me%;kGfupH!`N;Ap+h#Asv=r)=yH}U=b5ucu#UeDpQ^=Vu4$>(qvuJ zA{ZHHhjyJt9xp6Qm=_(5913;DVx}=Th840;WTT%|41Xj{%9$ebenmYHVErrdr}E3)Yiro<#piV|4di+KLq2fJ-u97Rts)z_^;3i?R{CEO@+a{z zU77z-fh=fW|3_lz|2v-X%PSvSp)%PF_COb^i*3byBUDtJ74R*o{0}Rgq31MyQ3l#~ zLCl&j5d@>cy#5-Gtji=A@CR^HU;Gs2jkqE$yT+Z%>Vz1X6&jQH){iPk8Y*Ydk`zX( zsy0qxCrIbYGT?T|-i*LDlSD%xM*nRwJaO!l|DSajdZhmc9fn(0iq8IY%1QPPoyvs_ zBmMln|NH%g>h=E<{e?Puu3s_Fja`@M5Au#*x4e4axb43EdDCzsInmtx>%eaWlaf8QV;uKuw7$HA?X%$D?S{WIHV(~}4 zGE39=8DyG9p5vu@JzU?mLKV})>c$cq8fmC+1c9RW40diSV=tyj?#UDdZR)g9@yY_e z+Gpes-D)2}V=$Wl@`U)Zk@{ujNv_UcKtFuq} zrG)Z$CbC#Y`IxLZ`m$f#no;e}>fvxo`LcOMcOSEP1JEkJqg~we3Mb$#k@qVcmZ+8UUDYo$KdG~$1ovCMRn}N>%Psdpsj5t@4-r_nH?j6;ZzzDCn83T-!_L& zra46OQP%lM5hVsC)k@{dCrI7b)E}?~(AlgQ0@*5Ql5o-w$Bq6f(j(tL62g(c9{_#0 zn4~|w?hbo4x?{oPn^}Z?P3uH)`rPT)FmTYLrLwQtw&N zD-7+EN6pj7N06*_={vF`UQ`w;{NUVE8UAg5`t7Z;X=pFHX2pp7lNP4wd;T?+Jxr=| zlg5vuT6dGgt*&_w^kVt(5*dXI+VmW(sFX36R`I+Y_%dxQR=aQ`P<*xvF+u)@j4WpK zB)H>bJ}^o1Apxk7cw^k0*d@^QFUL(%`#M zuF|cyrh>CUgXd+=7{bso9RDEIzpU!_cQ(cKvL~K&t|oWQ<41_nIOvJ5oZiz8(M(Wv z*!jJSW+WcH?{`aFF8yrdJef^-bA%*VTDXd#BSa`&)vVKAG-7@6esI2|Jysc9P1vZ? z)<|e~i%C_YJndyKSJ6g>bXL#N*pJ^bLxxs6g^ux>MxO1p1f6y%?=hHn`IsZJ<5w1q z=*uTMmqL_YDEcl4B`k@HxfcB7`<`u7NzmEmrmXvWc$YPbzOBT`zed(jLSW>uh+5iH zm^=S@i&?mPSfxSX#AhqIQ3mHp4vy=d`b2jrn&`;Zw8A>@12aHqW=cmsb+lQlF4~S~ zK$11TSk^RxkKyx_6_3hR@r4tInt%~u%a6(-Ub`orv{+?rdeV5m$M=t&iVU{>`<2#1 z7$&+@s5!P~+kVt1dPV4{>tjvLTe6goHwS!-U_>q8nNolzU8q`-!B@vuo9S|8gGywF zY?&-49eX^l<&;T0HR%XyjCrLA3ptdwiW$cI=~@;GNobdLba|fcx_8aMP!X}J|O0WUDv?}3Y z?!igLg>SCzSDS*+C}GjliRRWmtK#% zsV^}<_-4ZUj4cwcFkV)%mPZ*LoVcBzwV*SL*}6Wvyh*2de9S+`hUE{|Hom*O;|o!G zew}MVib;A<#mDvoYxeWRmKg#@Ug`*h#L2vpp7m~cQ%q)e2t%~|9#-dC4(qsXRY!{5 z6m4Nk@NRBMS4Kl((eOeSi|HvsW0D~Ts~Hst7}J% zn+WFb!RJi`-q}`bd^1XQp@*Ayj^j7IrJHqLIEH~6VcvOE{Kz`vU?YWck^6++=b+|e z$bn0ls(Jaufy?`cnGFY>uM@@fs-n6^VmIuH#o4%e&QdQ3=M2c9aCF9Nr*2tG2@wrM#ba#%HG z$N#uQSz+Zo^&$nale=Iit$Q+VQ)RH@DAFS~8w-1!Zs-wSM5aV{tfU@$n#In05yl9{ z;I7ab*XQ9b-n!xpw!=zgn_*4EMGpVShO zIn(@pKJe5`zD{wAu6*M~M3R3t)4fgQ2>vkFI@kH{+e@0Yi;YEp1~KTdmp@mXMEK;5 zX-IQiAK0xg(*LXouIKd)#I>Y9TkLdtMdeWhmRep4PMLG-(t>Yl+H^SW$B-2Rbm8Plbc#j_)mmn^hsywW}GfH$O4e%(c8$u;F4(ehHMPC26E>$GQvu?La; zmdQnnFKsDlJa@E5dtesT+j4ivo!C+auQ_Xl2O;Mq#cxF1o$t}ymZ$zylLgay5{LIQ z%Q|XKgXNWQ?R6>cUg!vmEr%}R>EJM^QW00qxNzbRT4n3Vo?1;xa;Xv&ZmgHoO^<20 zQ)+78dYz#R%8QGb*&Bl9vgQT};5klynWC}^%v0?z45YBoHK<{M0Uq+Jp%I=uvK{`&zdm%}gg?``hZ2s%q&IYMgIs)a zVc9U6xGFy;--~kJvavZ5qKQ=4P%1NV>QvKt;LePk$gGjJFN8JxFFRXtSF%oQv>eUw zJCEd$3h0OOAdbo!H6`lz&Pg#u*k8L5r-Kh|(SIpsl-B-&_(qH~polAE#&98v{^)z~ zWTVc#i%xsbWHeEtgyx51zqH3&Se1HCCyi2J$Q@Ly0-9PopEY5#oMWFd%qzrnIe17$ z2AAB!otVE?n+7F(cmYkIR`5oxNDsy8?3fl>w6#g`YJo}#}9Hlb&ra0M^czWJ^9CERr1 z)*<~~`8G@9hSo{FIv^(7r=v52V)s;Z1`9a3U$0Dj1iJfD)MvDDjuu&i^@4dhb?tqI z3CETEbWx9C%LtTBEJ1jz$&&yYo6sZwU>qNNq+Q0NV7c9s99}Fad&->PMJpporXsKO zI($D62*=X{385cHd&EK4qj1S?xm2@Qku`z1WQdf^^-5!+h20EXfV|gp(nv03YrIVJ zvT)*f)%xnx3Mjs!k!S!>=tf>nSjOHLH{A{B)?tWhI+)U9C*@PzF1GOENoOYU`5iNW zPlCVYT#=Wguep4`0m&$(=}CnS)^3B!L0f+Lmg2}$udmGae&59!%yy zr3)&&PlM=@cAyMj`e!%*YsqG15OE~iZ54S>r+e?1nB`fC@4zQ5ueTSkSAh&uxzNk) zuuCkE<-d4^U&2YwldS#1Asn2PN(Zuhs3KH54#f5IEMI*&RkIj`h72Sx3sbf~OHz=} z6i^_3eOEY9;vGgjsrPu>jV*9S)#=>_abn6nVuAqYz2YuyMmfY>J>!57rY7JO!*{Q2 zPPg^B?>*mSz-R2ys?tLTj6-Z|WLd%<@^DCmA9%VM`Hr1eV%B7$I{D&wdi1af zG+^zvL4WssZ5*`%u?y^hROY&gW|df%$i{ra#CVErz&qQELqP=P0BqA+hMyQ9mW)Rw zYoy;bCn^;Cbj}+jLo0%ip;YCKeExL(#b_ATVGJ@6vGrR#i82{WxNWO3uynww1X31^ zVM^G|#%!QWsF6!YX5dt)XCXGaW|bs5^d)cCE66cE0~2+#L?Q`8{*)WEwKe-|$1LW! z;dUq5vuiwx=}y`U9iMZaeo!biy~!6=Hf+(zzx~93}dofmOFl(KD^#w zTo)B$0Ge=z6{xMgWmc3a=EYFHbTF6SC8Jr(Op`#Zriea2PNcIiJ0DzD&JE3cLT8nv zSbUx6QND5v+rqUOUfuD7e)Y~TU$l?WcG`?=uX`g%0XD~$nGgJEISyXD=>m(+znam~ z*-DOiR-LyM0Fvn3JNA=j754=5zaTCvwngZA`+BS`XKRSmUHD~}yqRPQ%y%CoW|7Zy zS{zLlK6OKv-`VUo{NVa1Uu*|qlOAojm~{BMSTaeIN}f_r{z)hTRba(B=4U8RTMk`8 z8$uUJZ`@$)R8^AK#}=x)yg0Z>-)+c&r;@xHI_VXMV8$Q&4aiP3_IwL9fcS?4fje!R zEmudQ>%<;hNwPXYnHbq=8}z3w(AW7IMtE!B)lZ(j*N>Af4X9TIMT4HUxXDUh%t0Tg zNIhBO$YgT+E_OKa$wn)}yxl;~3E-kg+o#UIL=qZeL`_04KD zsTyf-I%?7^H~Wemi+1}^rg|!xZP<_TyBB}8J`&3#(0B6Cute%Bmd;xQ?G&W}uMHZm zRU8AGmb>i-K&2cmen?QA^z@!Tc-#L0IP8NQ!MevGsZP-H5-q+Cd zlFLmpN$~wnGe%<%=ZeYQAf3Q7&$rY)l{NjN3%{!!@M)Fp zI~fIXJP$o_Tyd0l)BE2!1}z=EacBHNulCz< zZo5Z#&GRcMX*nvU`x3b&MWX<1i5Y~=jCT2nCK`^abELsGF0yED1bYWX zfAjmLt!C5m%Fy{_&`Zd;E@x_}#8{WMO!wM}JL|q6E?!d^h*Z|qtCchDO`7r=X?4IE zbY;5R4ZKaiPGo%kFTsI-rAs;(xH_qFsBYf)l z>43lN8MG_1k0%PtE^D;ZdKC9fh`jepiSA=?k(O9{%bSBtUzPT%NK^_oE5bC^o;#Y4 z&cEezJ+hgJYaN?a+S*f3t}N(U@gvu*XgD4{B1M-{#vRQ+J@&lLKR($s$B`k<`po;p z_R2NZw65^ykhG#sl`+BiRo6v^#FT&dEM(ihu#7vB+fcve!Hor{=VIy(_~Q3qMHZ!b z$r7_kpEkS0mc-^PzEBJLZ0ve9%0ju!;&X@AWC%EaHHNj0R#~t_m#JgC-Mul9P@=~d z4^~`-d=zXkZhOOMmuZhSQCxZ$XQNamB1PZRaqo@Q#IlZc=XyvCGCqco%nP<0DnI1P zgTi$sed@d$^*&b+8UTGgtP=_d_@+Z-+;(y=Xgfvs@+Y9HK8trBd!Jr~E>QE-*3LKr zAtSjn=@{^5?Q@jL@@RZA_g5p%uqb@gnWxWvJjj04GsUmw&~^4XvrpGVC*2vYcb}iW z&DAkcNL`0kZwoXqhHbD|#_O6?h)Vh%=*Li1VhZ!(={>kdYo7orb)JWgbfa=+@7IW# zTCC%tE+P~>>hfUMK&7rwn3r`(fP5&+B@Odw6{*tLCq&!3uZEdf*wb(sJzUVar@mUJ zTWy4Nd|jm#qhwyib?q#IUE_;dN7m_9gb5F>TQwaeI|Fwn+8VE0Cc?L~TnIQbz z9Twt#-HXS7w&#oQbD*4S%@?+N@>Hw)>cL}2lbE_F^dB*y2KA`~I^bFnXsnsz#$}MQ z9#B|JjXabdi%-Pd{7mrH9~=8s^%+=%(WSOlmHY|TH-eGL;Gs~1(JRBytk0oRo_YJ@ zL~rHZdVWq7^dcO%;Ox7cCpiOuQtjYIbwgQw$%}_1y7!|VpW>7=U-WNn35RWcmo?WD z=qcPIJh;z)mA#<1^P6g|&0HKbm^w{aAU4(mj$@2ykl>2Uyt}Zabwp+J$zf5+_9XB6 z2k6HBgWC0I(`KAYoinXTh}2}>FOM99Qeg%v^HJB(J@&ks=-v!F+5B0(mA0p&J9$0L ze&>#-g*JD?1iIAeufl)2-IL!^4(y`fqiUa(BP{%*U1L0^1~|wQIFbM`!y#hAVc#>& z(@>12?xs`xgTFjt!RF3^##j@q2RM^Fx^j-}wwqHPznn>0Ot;q6*kRa>Js!XPyGLz4 zOZ+8`2a|P%Hx@8j&*}cTY2e0NxjMNK{eKz*z{z{x{%3X38^0<3J6#oWO~FN%au*QE zE3rSB9s}`l-v?WzfK3Jl>q- z@#wr<8>dR^)wJkCO8YAGrr52g@7>afZ^l4fzwV*89E;rsZ}u~!oo-EISH(_7$k~1K zlz!h#MhyHqI16$&19WdsC=+mFgxw-6~!jRWWE~eek=LgPCFF_Dn zd7)@HhNjPAQJdo**JoYr-U9*1>(m9DtmW!$MY`*cR2-Pxx#Xw$oAVT$Aowx9;23qY(?}=V51ZyVyt3m)gF!g-(fw*{NNQ?6#jNfP25 z8{q{Bb~ibwM0odo=`EW5@wh*cUpFR{AuuH8swMe4SirIhhG>;*UsN0p)uLZu`krOg zOWHH;cJ)Ktu(w8~-x@T~t$mdt6}Y=S=@Vmhd`=XwS|IkAw>mLG05lXDwh{WyRCox#!AJNYkVNNyL4Ym}|c zkd=IEKK_iz8;F<5)dNl?6g`V)z`|se-1yZ{0e-|{#->>%wkf&9C zhejq@O9z1NA5)+>2+TYX|>XvQbBd(+K*?mgegeZ7ko`n&oH;zmTt{b_r{;(FENt_Y{?+P-H z1!NdXB65#PMB#Q4jLg5;R=t!1!Uf{WnQ!8?0*g?6cil3BWO!!xhrjw7aQV{dVXB?+ zn8zdUz~;rD?C*N>?HYXV;emK3&U{GOw3){`vdqCqi}C5${ujIKXx^~SD&h!Y)z)VK zTc6cdrH!QONdOID5^7YP`YJk_9!X4*vZTMzi8N5eP%Gp+d=@`uT97t3@%z-&#`{88 zFot&9fc3boN-lvnT)++B5=~S|<3%VVp)=~+R znoRK+-1bv^?L?!1wb2j}^J+>XZY7Vk=BoI;Q^w?}Ux2aDPuGA$~QvZ|Q1a+|WenCXGP&`+q@_2FN+j*|+4@FXKeMPQk*T{`}oWn;*=o|Ldut!HI}{!Qwi02l+hiz>ur zaO;JAfwfQZ>(pYa&G)Euh(drRld$#XK^iKZ9edCyu0Y&E#97JdmCZ0;qbV?2ek}9s z^l@H`R6AQbku9(aCB}+MixhnmB4z=>*KaCAMtF_J z`=6&*yEp>{Vx5baQEJJ7YU=9k!iX00o6XH3ZPRnuN*sLCL10N6W?xzX2XeVp<%-<& z%6Vv5t%nNmUD95$2j4fJZ)?U@jPZ-s=OuH-kH`X4_Ibsjt6P)YwU>n>^~L5b95$=^o?gz* zGYbvTqfMJUdo&%wn$;yt)6r1=?8e?ms!5fdyASa#yN>q2n4&N0PJ=* zo!h=)o{y-Y+oqY3M}N~+@6C4mD6oPoolQrmRfx_4EY{3t&~@o=cVl7WO38VTb*6#| z@2=hV=>YjO$plNTdfRrY*V&1AybpG34f>J+(Br<*z^+0cSqC(sLG2)>KgCTYLpP*z z>;Ye4rDj@u^2j#1-c$Y44lBSZuz3SSQnjzJ8e&FfE%OetS;Kz1PYsB+Lo%_`5u|44 z#`Fup^|_h@{xwN|Tmtwfa?x3L-D0(ZlM$`CRIu6d`dX`NtbVc1sLODznZ1cnweC;l z_<727y>5qDOjGScZs{RyVirTZF@3!2>@tl(L19zga3w9;ct;GS>Da2e=9^hLl6oUM@S7`WsFJW1`(^6zOt4FuTNyix$VBz>#4PGjs zv0CEqrb5a##R-g(BTpxa&TMF9|FGh*``uLqwy$#Tb3QI}FC9b-rTf1Y>F0Pa5T&l# z30v-^g4LVqTa7_Wb=VW*Y^vm#ucAz4!Qa}97;)heFLa7OoK?8YeTD@j(mam06Vv5x zl3m;@7cqQ@-FD+LEmsm;9kt1_ZwpYg(;UHl!AV|7^aHm@CwSEsuzP^!(euSe z(=arR0{rt$H8tiWdJ6uzV=lcpg(l{;kbu?&xU%Zlq{%K#iyDi;-#B9oMw4yX>A6XhEz&lO&HyCfk^_- zn(2s~0HS`-DGU27?U!$P-_$x{mq7M!?ET_j**kY_Be?zIf2Z%i?2ZI_0uq5KLuelb z8mY&NPacFyRAwAj3zP-_Z1Vsn%WCq7!^bbdww*&_>Y{GoRx8Z{5`Z8UE>&G=;D2}j0Mg9 zpWNLa-5<2`g4Cc=gcq!rlP{Jx?5wf0T>Rl5&&*i!9O*A?b`L3sGL5&Y{%9${(>u7y znKM1Bn6vw0@E~6f@tj!4rlqeAIWx_~QTd^r@6qK!Y1*J**RSC8>>lM2DfXjtWRknV zk2)m%z;@RC?Tg6+$|FTqfS9i)Lo%zS0%YcRPGff2r^>S)P-J#7i0^Ss72W#^=*Rq^ z$r3M_gpkAglLy{5gx8Z^z+F{QE9U=0%ze(=bZ+A2_C%;!w|qtB$<|nxzCEBgT`uhL zwdrs@kejF%{db-&M)kJH&xQ9T2>BjEnU=eO(jrE}z4X%FGZTk1`*sM2Tz&zcV4I$; zdvHO-l(iPZV&-tAPVRk#tKOVCx%d~y0jVSq6gNbN_60X+d*$yhY?2|@msR7UCoH>d zwiHZ$NjkYOZ@Kq`&U_e8Nz2_dOI<{@NXYCg2jDq1q6!@f9qh%4MyIa}j6R~WHBsqP zRRV{(?1{EYC}D+Kx2=wEK7a#-eZ}TfIf5d`06<-x1d2cV`ry9;)Su5z?`=juO^9G0 zx)(N_C_>2K569~>ZdRgCe=e2B@@XM0jGl*#c;zN%p*{O&M8~y(_}))%o>{nGSiyPh zC}a^g-_*B-$pCP=$HO^Hle}%xefEy|mFU2Wi7Jvu!1(pLeM-hfZ_}0&+n$H|woh2T zD#{dJ^wt_9lnSV^l?UwDnaX|AdBhg^VNO_L%-e>xEt4x7cD$f1kVq}5`J`mRnxWL- zNT8du!Oc=s>$NPm{YK4P?W2YfRC)~e`|+g|pqjYw{P7n$O%LZ{H#{*ulMxELn%b;s zaCWY6K~TqmTsU%K?gT(Ld?-YiobJrW6;cd~%>!1>P~MbRUx(3-iIQG9`Esn}+&Y80nu+|Bs8xyml zi6snVmajZA{+)@tSe`TAkXtgeNt8%fJ{w;~9cfvhH{w?;Gw~MVB&w=u_7hOPIsy`=%6Oy|K zKm|p#-0S2{wlz(G>CiQ2&Qro$RBr2sv08WMhIQ$@D1URtl)bxQ_~h%OF@U6>9dun0 zx~|swuW@0hG0x$B;MtLx^uFK+XDl~#VpO~y-L;@sDP~q@V2NzGmD`{Hw->;-&rh0Y zWOmpa{(1?z9pfJv%5Xn+-12i$k*KUrq{c6);^bmw{5cf>OqUO z(l(u^Q8yM<{;%*nr}_U4o~MxgD?C5EQPVoXGaX-g4E4R##l;cCymVy#pz&GCKWLoC z5|I>KWR!Et52plsa>peN0Gn%ivL0^wKi)8E-HNdK!5yb5hs^G!S}u{G99SwnQ4&*< zXHY-)pZ@FSey&+;spI9dCNp+ZiAf^Nj#RCv@V+Nj1y)+@1 z<7|h+3Md~`${mZ(r_(5egC{x*n4ml8CM~ib5!KAI!r~q?mPl@j>Q2Vhbp>Bg!IN+h zEL>?SLh6=(c&s$q~0EXAWa=vnncBtKaj3W%P_Guc_Z`NY&{)YzuI+1}AU7_>A% zVYjGrEdr%K_3D4{nUtkVTr`T+Hp*Gjs^vkKo5Gq%^?|%qWc39Up zr=r(N>wgq9(X?Q!Eo{6tDB3V@)9jWmE8xr=s1KLci;2{6b5}E28U=HRBrb(=w5u7y zxBil|Y_2}&c*ZpdaD=9E1EqJ9jPSY0Z~g_Sn|$2@s|JfZ2+hsG=YVo>Pu0-#4201+ zk8Deg7&9fEe0DrFa z;OqqKT1zIpzLyIVT>f;qV7rn~&}AM8A*P%&@WOyt#P@&hx;H(Xr&(xM5Y(QSjQaIb~0td8Q8 zcII@QojEE&U#ATa@J$_ou-bD?AVJGmF>C5LrZ?GDG8ZxgvNB9Nyz|*JU12A6+?lk>6+h)34X!E;1JIVnBy$z7>ylE=R-efl zS5{Y|?_6LQ)sZcD*@%qC3%3l#zNTUyl5gy*1CPa@1S9Q);PKL9N8l*#==A`LDu~}~ zs4fu01S^=?*Np-GwA}C^8o@=OYzL%{8|ze1WR8{l$h@L6YS?|BmEkE_NAT8uT1$@n zQnvhz-nZ%O6q8U7Kue=HnZ*FyHZZNnrs2KY0?GlnjND&64|s9vexUR8h+I*S+_ENg zxQH)Bbt)||$B{dZ4$c(6?cXIdaIPuP2JINGr;VaU#;IYB5|$qSk*n-^?T5fQ*Ufqf zYn8cxf66npEiqLzea8XFxxr@ym#Y>PHHG~r9Q!va#o}&`{jA@V_M7Mu1|8_gXq0E0 zn{d7sAVy7@XUui9i`t8^TA;%w9k zZ0i>^w>b*=Gcue@_2{*H&pt}-wg8qv^fG9>TNFrz(k*^l6Gy1sUJ9A#DS-1>>SSHd z@E%By)svSnWCChONSyZQ$~ng}bG73md*+~hnJFS}Y|Yp)#yqS-5=fFUwBd=99ODYJ z^nJx|Fo0z4_J zdStSN4GhtAPYaM_T`^RoI-)bhIdVS;U7I6&k!~4@r zU4E9Qa6`8e6~f=4d*D?r-2v*>{G*Yu8XA*F58-gsWd+xT52Twos1s+V(SBwds8t)W z_}#zFSv;Ks!6@lb=w?DIMFf4VNz6xn$$2Gw&HTdo6e4Wch36mn#|;mfAotI{L0z2i z7b%m?dL0!6*!31GMZaR!^SnhVJPf|%$&o|lcuI@kjeCB92-Z87`;4QNIxDz*W`07Z z+pK!Kf_{@A+90t17+=09^)`#-e0(x&j~O`N0VveC8NJ3oTj%24syGB0I#)Ki;7ch} zhfu*~;DkhEYPWVq(7TTmSh$Fb|M%YCT-T0xxwrq(c)XKa@T(e%zdcs||6 - - - - `) - defer ctx.Writef("") - - ctx.Writef("") - defer ctx.Writef("") - - ctx.Writef(` - - - - - - - `) - defer ctx.Writef(`
MethodPathHandler
`) - - registeredRoutes := ctx.Application().GetRoutesReadOnly() - for _, r := range registeredRoutes { - if r.Path() == "/" { // don't list the root, current one. - continue - } - - ctx.Writef(` - - %s - %s%s - %s - - `, r.Method(), ctx.Host(), r.Path(), r.MainHandlerName()) - } -} - -type httpError struct { - Code int `json:"code"` - Reason string `json:"reason"` -} - -func (h httpError) Error() string { - return fmt.Sprintf("Status Code: %d\nReason: %s", h.Code, h.Reason) -} - -func fail(ctx iris.Context, statusCode int, format string, a ...interface{}) { - reason := "unspecified" - if format != "" { - reason = fmt.Sprintf(format, a...) - } - - err := httpError{ - Code: statusCode, - Reason: reason, - } - - ctx.StopWithJSON(statusCode, err) -} - -func handleNotFound(ctx iris.Context) { - suggestPaths := ctx.FindClosest(3) - if len(suggestPaths) == 0 { - ctx.WriteString("not found") - return - } - - ctx.HTML("Did you mean?
    ") - for _, s := range suggestPaths { - ctx.HTML(`
  • %s
  • `, s, s) - } - ctx.HTML("
") -} - -// Topic the payload for a kafka topic creation. -type Topic struct { - Topic string `json:"topic"` - Partitions int32 `json:"partitions"` - ReplicationFactor int16 `json:"replication"` - Configs []kv `json:"configs,omitempty"` -} - -type kv struct { - Key string `json:"key"` - Value string `json:"value"` -} - -func createKafkaTopic(t Topic) error { - cluster, err := sarama.NewClusterAdmin(brokers, config) - if err != nil { - return err - } - defer cluster.Close() - - topicName := t.Topic - topicDetail := sarama.TopicDetail{ - NumPartitions: t.Partitions, - ReplicationFactor: t.ReplicationFactor, - } - - if len(t.Configs) > 0 { - topicDetail.ConfigEntries = make(map[string]*string, len(t.Configs)) - for _, c := range t.Configs { - topicDetail.ConfigEntries[c.Key] = &c.Value // generate a ptr, or fill a new(string) with it and use that. - } - } - - return cluster.CreateTopic(topicName, &topicDetail, false) -} - -func postTopicsHandler(ctx iris.Context) { - var t Topic - err := ctx.ReadJSON(&t) - if err != nil { - fail(ctx, iris.StatusBadRequest, - "received invalid topic payload: %v", err) - return - } - - // try to create the topic inside kafka. - err = createKafkaTopic(t) - if err != nil { - fail(ctx, iris.StatusInternalServerError, - "unable to create topic: %v", err) - return - } - - // unnecessary statement but it's here to show you that topic is created, - // depending on your API expectations and how you used to work - // you may want to change the status code to something like `iris.StatusCreated`. - ctx.StatusCode(iris.StatusOK) -} - -func getKafkaTopics() ([]string, error) { - client, err := sarama.NewClient(brokers, config) - if err != nil { - return nil, err - } - defer client.Close() - - return client.Topics() -} - -func getTopicsHandler(ctx iris.Context) { - topics, err := getKafkaTopics() - if err != nil { - fail(ctx, iris.StatusInternalServerError, - "unable to retrieve topics: %v", err) - return - } - - ctx.JSON(topics) -} - -func produceKafkaMessage(toTopic string, key string, value []byte) (partition int32, offset int64, err error) { - // On the broker side, you may want to change the following settings to get - // stronger consistency guarantees: - // - For your broker, set `unclean.leader.election.enable` to false - // - For the topic, you could increase `min.insync.replicas`. - - producer, err := sarama.NewSyncProducer(brokers, config) - if err != nil { - return -1, -1, err - } - defer producer.Close() - - // We are not setting a message key, which means that all messages will - // be distributed randomly over the different partitions. - return producer.SendMessage(&sarama.ProducerMessage{ - Topic: toTopic, - Key: sarama.StringEncoder(key), - Value: sarama.ByteEncoder(value), - }) -} - -func postTopicProduceHandler(ctx iris.Context) { - topicName := ctx.Params().Get("topic") - key := ctx.URLParamDefault("key", "default") - - // read the request data and store them as they are (not recommended in production ofcourse, do your own checks here). - body, err := ioutil.ReadAll(ctx.Request().Body) - if err != nil { - fail(ctx, iris.StatusUnprocessableEntity, "unable to read your data: %v", err) - return - } - - partition, offset, err := produceKafkaMessage(topicName, key, body) - if err != nil { - fail(ctx, iris.StatusInternalServerError, "failed to store your data: %v", err) - return - } - - // The tuple (topic, partition, offset) can be used as a unique identifier - // for a message in a Kafka cluster. - ctx.Writef("Your data is stored with unique identifier: %s/%d/%d", topicName, partition, offset) -} - -type message struct { - Time time.Time `json:"time"` - Key string `json:"key"` - // Value []byte/json.RawMessage(if you are sure that you are sending only JSON) `json:"value"` - // or: - Value string `json:"value"` // for simple key-value storage. -} - -func getTopicConsumeSSEHandler(ctx iris.Context) { - flusher, ok := ctx.ResponseWriter().Flusher() - if !ok { - ctx.StopWithText(iris.StatusHTTPVersionNotSupported, "streaming unsupported") - return - } - - ctx.ContentType("application/json, text/event-stream") - ctx.Header("Cache-Control", "no-cache") - ctx.Header("Connection", "keep-alive") - - master, err := sarama.NewConsumer(brokers, config) - if err != nil { - fail(ctx, iris.StatusInternalServerError, "unable to start master consumer: %v", err) - return - } - - fromTopic := ctx.Params().Get("topic") - // take the partition, defaults to the first found if not url query parameter "partition" passed. - var partition int32 - partitions, err := master.Partitions(fromTopic) - if err != nil { - master.Close() - fail(ctx, iris.StatusInternalServerError, "unable to get partitions for topic: '%s': %v", fromTopic, err) - return - } - - if len(partitions) > 0 { - partition = partitions[0] - } - - partition = ctx.URLParamInt32Default("partition", partition) - offset := ctx.URLParamInt64Default("offset", sarama.OffsetOldest) - - consumer, err := master.ConsumePartition(fromTopic, partition, offset) - if err != nil { - ctx.Application().Logger().Error(err) - master.Close() // close the master here to avoid any leaks, we will exit. - fail(ctx, iris.StatusInternalServerError, "unable to start partition consumer: %v", err) - return - } - - // `OnClose` fires when the request is finally done (all data read and handler exits) or interrupted by the user. - ctx.OnClose(func() { - ctx.Application().Logger().Warnf("a client left") - - // Close shuts down the consumer. It must be called after all child - // PartitionConsumers have already been closed. <-- That is what - // godocs says but it doesn't work like this. - // if err = consumer.Close(); err != nil { - // ctx.Application().Logger().Errorf("[%s] unable to close partition consumer: %v", ctx.RemoteAddr(), err) - // } - // so close the master only and omit the first ^ consumer.Close: - if err = master.Close(); err != nil { - ctx.Application().Logger().Errorf("[%s] unable to close master consumer: %v", ctx.RemoteAddr(), err) - } - }) - - for { - select { - case consumerErr, ok := <-consumer.Errors(): - if !ok { - return - } - ctx.Writef("data: error: {\"reason\": \"%s\"}\n\n", consumerErr.Error()) - flusher.Flush() - case incoming, ok := <-consumer.Messages(): - if !ok { - return - } - - msg := message{ - Time: incoming.Timestamp, - Key: string(incoming.Key), - Value: string(incoming.Value), - } - - b, err := json.Marshal(msg) - if err != nil { - ctx.Application().Logger().Error(err) - continue - } - - ctx.Writef("data: %s\n\n", b) - flusher.Flush() - } - } -} diff --git a/_examples/logging/file-logger/main.go b/_examples/logging/file-logger/main.go deleted file mode 100644 index a9cca07d..00000000 --- a/_examples/logging/file-logger/main.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import ( - "os" - "time" - - "github.com/kataras/iris/v12" -) - -func main() { - f := newLogFile() - defer f.Close() - - app := iris.New() - // Attach the file as logger, remember, iris' app logger is just an io.Writer. - // Use the following code if you need to write the logs to file and console at the same time. - // app.Logger().SetOutput(io.MultiWriter(f, os.Stdout)) - app.Logger().SetOutput(f) - - app.Get("/ping", func(ctx iris.Context) { - // for the sake of simplicity, in order see the logs at the ./_today_.txt - ctx.Application().Logger().Infof("Request path: %s", ctx.Path()) - ctx.WriteString("pong") - }) - - // Navigate to http://localhost:8080/ping - // and open the ./logs{TODAY}.txt file. - if err := app.Listen(":8080", iris.WithoutBanner); err != nil { - app.Logger().Warn("Shutdown with error: " + err.Error()) - } -} - -// Get a filename based on the date, just for the sugar. -func todayFilename() string { - today := time.Now().Format("Jan 02 2006") - return today + ".txt" -} - -func newLogFile() *os.File { - filename := todayFilename() - // Open the file, this will append to the today's file if server restarted. - f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) - if err != nil { - panic(err) - } - - return f -} diff --git a/_examples/logging/json-logger/main.go b/_examples/logging/json-logger/main.go deleted file mode 100644 index 71470664..00000000 --- a/_examples/logging/json-logger/main.go +++ /dev/null @@ -1,87 +0,0 @@ -package main - -import ( - "encoding/json" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/requestid" - - "github.com/kataras/golog" -) - -func main() { - app := iris.New() - app.Logger().SetLevel("debug") - app.Logger().Handle(jsonOutput) - - app.Use(requestid.New()) - - /* Example Output: - { - "timestamp": 1591422944, - "level": "debug", - "message": "This is a message with data", - "fields": { - "username": "kataras" - }, - "stacktrace": [ - { - "function": "main.main", - "source": "C:/mygopath/src/github.com/kataras/iris/_examples/logging/json-logger/main.go:16" - } - ] - } - */ - app.Logger().Debugf("This is a %s with data (debug prints the stacktrace too)", "message", golog.Fields{ - "username": "kataras", - }) - - /* Example Output: - { - "timestamp": 1591422944, - "level": "info", - "message": "An info message", - "fields": { - "home": "https://iris-go.com" - } - } - */ - app.Logger().Infof("An info message", golog.Fields{"home": "https://iris-go.com"}) - - app.Get("/ping", ping) - - // Navigate to http://localhost:8080/ping. - app.Listen(":8080" /*, iris.WithoutBanner*/) -} - -func jsonOutput(l *golog.Log) bool { - enc := json.NewEncoder(l.Logger.Printer) // you can change the output to a file as well. - enc.SetIndent("", " ") - err := enc.Encode(l) - return err == nil -} - -func ping(ctx iris.Context) { - /* Example Output: - { - "timestamp": 1591423046, - "level": "debug", - "message": "Request path: /ping", - "fields": { - "request_id": "fc12d88a-a338-4bb9-aa5e-126f2104365c" - }, - "stacktrace": [ - { - "function": "main.ping", - "source": "C:/mygopath/src/github.com/kataras/iris/_examples/logging/json-logger/main.go:82" - }, - ... - ] - } - */ - ctx.Application().Logger().Debugf("Request path: %s", ctx.Path(), golog.Fields{ - "request_id": ctx.GetID(), - }) - - ctx.WriteString("pong") -} diff --git a/_examples/logging/json-logger/main_test.go b/_examples/logging/json-logger/main_test.go deleted file mode 100644 index 70f02d85..00000000 --- a/_examples/logging/json-logger/main_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package main - -import ( - "bytes" - "encoding/json" - "strings" - "sync" - "testing" - - "github.com/kataras/golog" - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/httptest" -) - -func TestJSONLogger(t *testing.T) { - iters := 500 - - out := new(bytes.Buffer) - - app := iris.New() - app.Logger().SetTimeFormat("") // disable timestamps. - app.Logger().SetStacktraceLimit(1) // limit debug stacktrace to 1, show only the first caller. - app.Logger().SetOutput(out) - - app.Logger().Handle(func(l *golog.Log) bool { - enc := json.NewEncoder(l.Logger.Printer) // you can change the output to a file as well. - err := enc.Encode(l) - return err == nil - }) - - app.Get("/ping", ping) - - const expectedLogStr = `{"level":"debug","message":"Request path: /ping","fields":{"request_id":null},"stacktrace":[{"function":"json-logger/ping","source":"C:/mygopath/src/github.com/kataras/iris/_examples/logging/json-logger/main.go:82"}]}` - e := httptest.New(t, app, httptest.LogLevel("debug")) - wg := new(sync.WaitGroup) - wg.Add(iters) - for i := 0; i < iters; i++ { - go func() { - e.GET("/ping").Expect().Status(httptest.StatusOK).Body().Equal("pong") - wg.Done() - }() - } - - wg.Wait() - expected := "" - for i := 0; i < iters; i++ { - expected += expectedLogStr + "\n" - } - - got := out.String() - got = got[strings.Index(got, "{"):] // take only the json we care and after. - if expected != got { - if !strings.HasSuffix(got, expected) { - // C:/mygopath vs /home/travis vs any file system, - // pure check but it does the job. - t.Fatalf("expected:\n%s\nbut got:\n%s", expected, got) - } - } -} diff --git a/_examples/logging/request-logger/main.go b/_examples/logging/request-logger/main.go deleted file mode 100644 index 1e89d833..00000000 --- a/_examples/logging/request-logger/main.go +++ /dev/null @@ -1,65 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/logger" -) - -func main() { - app := iris.New() - - customLogger := logger.New(logger.Config{ - // Status displays status code - Status: true, - // IP displays request's remote address - IP: true, - // Method displays the http method - Method: true, - // Path displays the request path - Path: true, - // Query appends the url query to the Path. - Query: true, - - // Columns: true, - - // if !empty then its contents derives from `ctx.Values().Get("logger_message") - // will be added to the logs. - MessageContextKeys: []string{"logger_message"}, - - // if !empty then its contents derives from `ctx.GetHeader("User-Agent") - MessageHeaderKeys: []string{"User-Agent"}, - }) - - app.Use(customLogger) - - h := func(ctx iris.Context) { - ctx.Writef("Hello from %s", ctx.Path()) - } - app.Get("/", h) - - app.Get("/1", h) - - app.Get("/2", h) - - // http errors have their own handlers, therefore - // registering a middleare should be done manually. - /* - app.OnErrorCode(404 ,customLogger, func(ctx iris.Context) { - ctx.Writef("My Custom 404 error page ") - }) - */ - // or catch all http errors: - app.OnAnyErrorCode(customLogger, func(ctx iris.Context) { - // this should be added to the logs, at the end because of the `logger.Config#MessageContextKey` - ctx.Values().Set("logger_message", - "a dynamic message passed to the logs") - ctx.Writef("My Custom error page") - }) - - // http://localhost:8080 - // http://localhost:8080/1 - // http://localhost:8080/2 - // http://lcoalhost:8080/notfoundhere - // see the output on the console. - app.Listen(":8080") -} diff --git a/_examples/logging/request-logger/request-logger-file-json/main.go b/_examples/logging/request-logger/request-logger-file-json/main.go deleted file mode 100644 index 67480502..00000000 --- a/_examples/logging/request-logger/request-logger-file-json/main.go +++ /dev/null @@ -1,110 +0,0 @@ -package main - -import ( - "fmt" - "io" - "os" - "strings" - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/logger" -) - -const deleteFileOnExit = false - -func newRequestLogger(newWriter io.Writer) iris.Handler { - c := logger.Config{} - c.AddSkipper(func(ctx iris.Context) bool { - path := ctx.Path() - for _, ext := range excludeExtensions { - if strings.HasSuffix(path, ext) { - return true - } - } - return false - }) - - c.LogFuncCtx = func(ctx iris.Context, latency time.Duration) { - datetime := time.Now().Format(ctx.Application().ConfigurationReadOnly().GetTimeFormat()) - customHandlerMessage := ctx.Values().GetString("log_message") - - file, line := ctx.HandlerFileLine() - source := fmt.Sprintf("%s:%d", file, line) - - // this will just append a line without an array of javascript objects, readers of this file should read one line per log javascript object, - // however, you can improve it even more, this is just a simple example on how to use the `LogFuncCtx`. - jsonStr := fmt.Sprintf(`{"datetime":"%s","level":"%s","source":"%s","latency": "%s","status": %d,"method":"%s","path":"%s","message":"%s"}`, - datetime, "INFO", source, latency.String(), ctx.GetStatusCode(), ctx.Method(), ctx.Path(), customHandlerMessage) - - fmt.Fprintln(newWriter, jsonStr) - } - - return logger.New(c) -} - -func h(ctx iris.Context) { - ctx.Values().Set("log_message", "something to give more info to the request logger") - - ctx.Writef("Hello from %s", ctx.Path()) -} - -func main() { - app := iris.New() - - logFile := newLogFile() - defer func() { - logFile.Close() - if deleteFileOnExit { - os.Remove(logFile.Name()) - } - }() - - r := newRequestLogger(logFile) - app.Use(r) - - app.OnAnyErrorCode(r, func(ctx iris.Context) { - ctx.HTML("

Error: Please try this instead.

") - }) - - app.Get("/", h) - - app.Get("/1", h) - - app.Get("/2", h) - - app.Get("/", h) - - // http://localhost:8080 - // http://localhost:8080/1 - // http://localhost:8080/2 - // http://lcoalhost:8080/notfoundhere - app.Listen(":8080") -} - -var excludeExtensions = [...]string{ - ".js", - ".css", - ".jpg", - ".png", - ".ico", - ".svg", -} - -// get a filename based on the date, file logs works that way the most times -// but these are just a sugar. -func todayFilename() string { - today := time.Now().Format("Jan 02 2006") - return today + ".json" -} - -func newLogFile() *os.File { - filename := todayFilename() - // open an output file, this will append to the today's file if server restarted. - f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) - if err != nil { - panic(err) - } - - return f -} diff --git a/_examples/logging/request-logger/request-logger-file/main.go b/_examples/logging/request-logger/request-logger-file/main.go deleted file mode 100644 index ac387963..00000000 --- a/_examples/logging/request-logger/request-logger-file/main.go +++ /dev/null @@ -1,107 +0,0 @@ -package main - -import ( - "os" - "strings" - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/logger" -) - -const deleteFileOnExit = false - -func main() { - app := iris.New() - r, close := newRequestLogger() - defer close() - - app.Use(r) - app.OnAnyErrorCode(r, func(ctx iris.Context) { - ctx.HTML("

Error: Please try this instead.

") - }) - - h := func(ctx iris.Context) { - ctx.Writef("Hello from %s", ctx.Path()) - } - - app.Get("/", h) - - app.Get("/1", h) - - app.Get("/2", h) - - // http://localhost:8080 - // http://localhost:8080/1 - // http://localhost:8080/2 - // http://lcoalhost:8080/notfoundhere - app.Listen(":8080") -} - -// get a filename based on the date, file logs works that way the most times -// but these are just a sugar. -func todayFilename() string { - today := time.Now().Format("Jan 02 2006") - return today + ".txt" -} - -func newLogFile() *os.File { - filename := todayFilename() - // open an output file, this will append to the today's file if server restarted. - f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) - if err != nil { - panic(err) - } - - return f -} - -var excludeExtensions = [...]string{ - ".js", - ".css", - ".jpg", - ".png", - ".ico", - ".svg", -} - -func newRequestLogger() (h iris.Handler, close func() error) { - close = func() error { return nil } - - c := logger.Config{ - Status: true, - IP: true, - Method: true, - Path: true, - Columns: true, - } - - logFile := newLogFile() - close = func() error { - err := logFile.Close() - if deleteFileOnExit { - err = os.Remove(logFile.Name()) - } - return err - } - - c.LogFunc = func(endTime time.Time, latency time.Duration, status, ip, method, path string, message interface{}, headerMessage interface{}) { - output := logger.Columnize(endTime.Format("2006/01/02 - 15:04:05"), latency, status, ip, method, path, message, headerMessage) - logFile.Write([]byte(output)) - } // or make use of the `LogFuncCtx`, see the '../request-logger-file-json' example for more. - - // when we don't want to use to log requests to assets and etc. - c.AddSkipper(func(ctx iris.Context) bool { - path := ctx.Path() - for _, ext := range excludeExtensions { - if strings.HasSuffix(path, ext) { - return true - } - } - return false - }) - - h = logger.New(c) - - return -} diff --git a/_examples/logging/rollbar/go.mod b/_examples/logging/rollbar/go.mod deleted file mode 100644 index 6a3e5ca1..00000000 --- a/_examples/logging/rollbar/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/kataras/iris/examples/logging/rollbar - -go 1.15 - -require ( - github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd - github.com/rollbar/rollbar-go v1.2.0 -) diff --git a/_examples/logging/rollbar/main.go b/_examples/logging/rollbar/main.go deleted file mode 100644 index 0903f886..00000000 --- a/_examples/logging/rollbar/main.go +++ /dev/null @@ -1,107 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "os" - "runtime/debug" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/requestid" - - "github.com/rollbar/rollbar-go" -) - -// * https://rollbar.com/signup -// * https://docs.rollbar.com/docs/go -func init() { - token := os.Getenv("ROLLBAR_TOKEN") // replace that with your token. - if token == "" { - panic("ROLLBAR_TOKEN is missing") - } - - // rb := rollbar.NewAsync(token, "production", "", hostname, "github.com/kataras/iris") - // Or use the package-level instance: - rollbar.SetToken(token) - // defaults to "development" - rollbar.SetEnvironment("production") - // optional Git hash/branch/tag (required for GitHub integration) - // rollbar.SetCodeVersion("v2") - // optional override; defaults to hostname - // rollbar.SetServerHost("web.1") - // path of project (required for GitHub integration and non-project stacktrace collapsing) - rollbar.SetServerRoot("github.com/kataras/iris") - -} - -func main() { - app := iris.New() - // A middleware which sets the ctx.GetID (or requestid.Get(ctx)). - app.Use(requestid.New()) - // A recover middleware which sends the error trace to the rollbar. - app.Use(func(ctx iris.Context) { - defer func() { - if r := recover(); r != nil { - debug.PrintStack() - - file, line := ctx.HandlerFileLine() // the failed handler's source code position. - - // cause other info - rollbar.Critical(errors.New(fmt.Sprint(r)), iris.Map{ - "request_id": ctx.GetID(), - "request_ip": ctx.RemoteAddr(), - "request_uri": ctx.FullRequestURI(), - "handler": iris.Map{ - "name": ctx.HandlerName(), // the handler which failed. - "file": fmt.Sprintf("%s:%d", file, line), - }, - }) - - ctx.StopWithStatus(iris.StatusInternalServerError) - } - }() - - ctx.Next() - }) - - app.Get("/", index) - app.Get("/panic", panicMe) - - // http://localhost:8080 should add an info message to the rollbar's "Items" dashboard. - // http://localhost:8080/panic should add a critical message to the rollbar's "Items" dashboard, - // with the corresponding information appending on its "Occurrences" tab item, e.g: - // Timestamp (PDT) - // * 2020-06-08 04:47 pm - // - // server.host - // * DESKTOP-HOSTNAME - // - // trace_chain.0.exception.message - // * a critical error message here - // - // custom.handler.file - // * C:/mygopath/src/github.com/kataras/iris/_examples/logging/rollbar/main.go:76 - // - // custom.handler.name - // * main.panicMe - // - // custom.request_id - // * cce61665-0c1b-4fb5-8547-06a3537e477c - // - // custom.request_ip - // * ::1 - // - // custom.request_uri - // * http://localhost:8080/panic - app.Listen(":8080") -} - -func index(ctx iris.Context) { - rollbar.Info(fmt.Sprintf("Index page requested by %s", ctx.RemoteAddr())) - - ctx.HTML("

Index Page

") -} - -func panicMe(ctx iris.Context) { - panic("a critical error message here") -} diff --git a/_examples/mvc/authenticated-controller/main.go b/_examples/mvc/authenticated-controller/main.go deleted file mode 100644 index 25a27955..00000000 --- a/_examples/mvc/authenticated-controller/main.go +++ /dev/null @@ -1,110 +0,0 @@ -// Package main shows how to use a dependency to check if a user is logged in -// using a special custom Go type `Authenticated`, which when, -// present on a controller's method or a field then -// it limits the visibility to "authenticated" users only. -// -// The same result could be done through a middleware as well, however using a static type -// any person reads your code can see that an "X" controller or method -// should only be used by "authenticated" users. -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" - "github.com/kataras/iris/v12/sessions" -) - -func main() { - app := newApp() - app.Logger().SetLevel("debug") - - // Open a client, e.g. Postman and visit the below endpoints. - // GET: http://localhost:8080/user (UnauthenticatedUserController.Get) - // POST: http://localhost:8080/user/login (UnauthenticatedUserController.PostLogin) - // GET: http://localhost:8080/user (UserController.Get) - // POST: http://localhost:8080/user/logout (UserController.PostLogout) - app.Listen(":8080") -} - -func newApp() *iris.Application { - app := iris.New() - sess := sessions.New(sessions.Config{ - Cookie: "myapp_session_id", - AllowReclaim: true, - }) - app.Use(sess.Handler()) - - userRouter := app.Party("/user") - { - // Use that in order to be able to register a route twice, - // last one will be executed if the previous route's handler(s) stopped and the response can be reset-ed. - // See core/router/route_register_rule_test.go#TestRegisterRuleOverlap. - userRouter.SetRegisterRule(iris.RouteOverlap) - - // Initialize a new MVC application on top of the "userRouter". - userApp := mvc.New(userRouter) - // Register Dependencies. - userApp.Register(authDependency) - - // Register Controllers. - userApp.Handle(new(UserController)) - userApp.Handle(new(UnauthenticatedUserController)) - } - - return app -} - -// Authenticated is a custom type used as "annotation" for resources that requires authentication, -// its value should be the logged user ID. -type Authenticated uint64 - -func authDependency(ctx iris.Context, session *sessions.Session) Authenticated { - userID := session.GetUint64Default("user_id", 0) - if userID == 0 { - // If execution was stopped - // any controller's method will not be executed at all. - ctx.StopWithStatus(iris.StatusUnauthorized) - return 0 - } - - return Authenticated(userID) -} - -// UnauthenticatedUserController serves the "public" Unauthorized User API. -type UnauthenticatedUserController struct{} - -// Get registers a route that will be executed when authentication is not passed -// (see UserController.Get) too. -func (c *UnauthenticatedUserController) Get() string { - return "custom action to redirect on authentication page" -} - -// PostLogin serves -// POST: /user/login -func (c *UnauthenticatedUserController) PostLogin(session *sessions.Session) mvc.Response { - session.Set("user_id", 1) - - // Redirect (you can still use the Context.Redirect if you want so). - return mvc.Response{ - Path: "/user", - Code: iris.StatusFound, - } -} - -// UserController serves the "public" User API. -type UserController struct { - CurrentUserID Authenticated -} - -// Get returns a message for the sake of the example. -// GET: /user -func (c *UserController) Get() string { - return `UserController.Get: The Authenticated type -can be used to secure a controller's method too.` -} - -// PostLogout serves -// POST: /user/logout -func (c *UserController) PostLogout(ctx iris.Context) { - sessions.Get(ctx).Man.Destroy(ctx) -} diff --git a/_examples/mvc/authenticated-controller/main_test.go b/_examples/mvc/authenticated-controller/main_test.go deleted file mode 100644 index df47e18e..00000000 --- a/_examples/mvc/authenticated-controller/main_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestMVCOverlapping(t *testing.T) { - app := newApp() - - e := httptest.New(t, app, httptest.URL("http://example.com")) - // unauthenticated. - e.GET("/user").Expect().Status(httptest.StatusOK).Body().Equal("custom action to redirect on authentication page") - // login. - e.POST("/user/login").Expect().Status(httptest.StatusOK) - // authenticated. - e.GET("/user").Expect().Status(httptest.StatusOK).Body().Equal(`UserController.Get: The Authenticated type -can be used to secure a controller's method too.`) - // logout. - e.POST("/user/logout").Expect().Status(httptest.StatusOK) - // unauthenticated. - e.GET("/user").Expect().Status(httptest.StatusOK).Body().Equal("custom action to redirect on authentication page") -} diff --git a/_examples/mvc/basic/main.go b/_examples/mvc/basic/main.go deleted file mode 100644 index ebdfcde9..00000000 --- a/_examples/mvc/basic/main.go +++ /dev/null @@ -1,105 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/recover" - "github.com/kataras/iris/v12/sessions" - - "github.com/kataras/iris/v12/mvc" -) - -func main() { - app := iris.New() - app.Use(recover.New()) - app.Logger().SetLevel("debug") - mvc.Configure(app.Party("/basic"), basicMVC) - - app.Listen(":8080") -} - -func basicMVC(app *mvc.Application) { - // You can use normal middlewares at MVC apps of course. - app.Router.Use(func(ctx iris.Context) { - ctx.Application().Logger().Infof("Path: %s", ctx.Path()) - ctx.Next() - }) - - // Register dependencies which will be binding to the controller(s), - // can be either a function which accepts an iris.Context and returns a single value (dynamic binding) - // or a static struct value (service). - app.Register( - sessions.New(sessions.Config{}).Start, - &prefixedLogger{prefix: "DEV"}, - ) - - // GET: http://localhost:8080/basic - // GET: http://localhost:8080/basic/custom - // GET: http://localhost:8080/basic/custom2 - app.Handle(new(basicController)) - - // All dependencies of the parent *mvc.Application - // are cloned to this new child, - // thefore it has access to the same session as well. - // GET: http://localhost:8080/basic/sub - app.Party("/sub"). - Handle(new(basicSubController)) -} - -// If controller's fields (or even its functions) expecting an interface -// but a struct value is binded then it will check -// if that struct value implements -// the interface and if true then it will add this to the -// available bindings, as expected, before the server ran of course, -// remember? Iris always uses the best possible way to reduce load -// on serving web resources. - -type LoggerService interface { - Log(string) -} - -type prefixedLogger struct { - prefix string -} - -func (s *prefixedLogger) Log(msg string) { - fmt.Printf("%s: %s\n", s.prefix, msg) -} - -type basicController struct { - Logger LoggerService - - Session *sessions.Session -} - -func (c *basicController) BeforeActivation(b mvc.BeforeActivation) { - b.HandleMany("GET", "/custom /custom2", "Custom") -} - -func (c *basicController) AfterActivation(a mvc.AfterActivation) { - if a.Singleton() { - panic("basicController should be stateless, a request-scoped, we have a 'Session' which depends on the context.") - } -} - -func (c *basicController) Get() string { - count := c.Session.Increment("count", 1) - - body := fmt.Sprintf("Hello from basicController\nTotal visits from you: %d", count) - c.Logger.Log(body) - return body -} - -func (c *basicController) Custom() string { - return "custom" -} - -type basicSubController struct { - Session *sessions.Session -} - -func (c *basicSubController) Get() string { - count := c.Session.GetIntDefault("count", 1) - return fmt.Sprintf("Hello from basicSubController.\nRead-only visits count: %d", count) -} diff --git a/_examples/mvc/basic/wildcard/main.go b/_examples/mvc/basic/wildcard/main.go deleted file mode 100644 index 915d3e3d..00000000 --- a/_examples/mvc/basic/wildcard/main.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" -) - -func main() { - app := iris.New() - usersRouter := app.Party("/users") - mvc.New(usersRouter).Handle(new(myController)) - // Same as: - // usersRouter.Get("/{p:path}", func(ctx iris.Context) { - // wildcardPathParameter := ctx.Params().Get("p") - // ctx.JSON(response{ - // Message: "The path parameter is: " + wildcardPathParameter, - // }) - // }) - - /* - curl --location --request GET 'http://localhost:8080/users/path_segment_1/path_segment_2' - - Expected Output: - { - "message": "The wildcard is: path_segment_1/path_segment_2" - } - */ - app.Listen(":8080") -} - -type myController struct{} - -type response struct { - Message string `json:"message"` -} - -func (c *myController) GetByWildcard(wildcardPathParameter string) response { - return response{ - Message: "The path parameter is: " + wildcardPathParameter, - } -} diff --git a/_examples/mvc/error-handler/main.go b/_examples/mvc/error-handler/main.go deleted file mode 100644 index f22015d9..00000000 --- a/_examples/mvc/error-handler/main.go +++ /dev/null @@ -1,39 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/kataras/iris/v12" - - "github.com/kataras/iris/v12/mvc" -) - -func main() { - app := iris.New() - app.Logger().SetLevel("debug") - - mvcApp := mvc.New(app) - // To all controllers, it can optionally be overridden per-controller - // if the controller contains the `HandleError(ctx iris.Context, err error)` function. - // - mvcApp.HandleError(func(ctx iris.Context, err error) { - ctx.HTML(fmt.Sprintf("%s", err.Error())) - }) - // - mvcApp.Handle(new(myController)) - - // http://localhost:8080 - app.Listen(":8080") -} - -type myController struct { -} - -// overriddes the mvcApp.HandleError function. -func (c *myController) HandleError(ctx iris.Context, err error) { - ctx.HTML(fmt.Sprintf("%s", err.Error())) -} - -func (c *myController) Get() error { - return fmt.Errorf("error here") -} diff --git a/_examples/mvc/grpc-compatible/README.md b/_examples/mvc/grpc-compatible/README.md deleted file mode 100644 index 94a84d4e..00000000 --- a/_examples/mvc/grpc-compatible/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# gRPC Iris Example - -## Generate TLS Keys - -```sh -$ openssl genrsa -out server.key 2048 -$ openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650 -``` - -## Install the protoc Go plugin - -```sh -$ go get -u github.com/golang/protobuf/protoc-gen-go -``` - -## Generate proto - -```sh -$ protoc -I helloworld/ helloworld/helloworld.proto --go_out=plugins=grpc:helloworld -``` diff --git a/_examples/mvc/grpc-compatible/grpc-client/main.go b/_examples/mvc/grpc-compatible/grpc-client/main.go deleted file mode 100644 index 253b3799..00000000 --- a/_examples/mvc/grpc-compatible/grpc-client/main.go +++ /dev/null @@ -1,47 +0,0 @@ -// Package main implements a client for Greeter service. -package main - -import ( - "context" - "log" - "os" - "time" - - pb "github.com/kataras/iris/v12/_examples/mvc/grpc-compatible/helloworld" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" -) - -const ( - address = "localhost:443" - defaultName = "world" -) - -func main() { - // Set up a connection to the server. - cred, err := credentials.NewClientTLSFromFile("../server.crt", "localhost") - if err != nil { - log.Fatal(err) - } - - conn, err := grpc.Dial(address, grpc.WithTransportCredentials(cred), grpc.WithBlock()) - if err != nil { - log.Fatalf("did not connect: %v", err) - } - defer conn.Close() - c := pb.NewGreeterClient(conn) - - // Contact the server and print out its response. - name := defaultName - if len(os.Args) > 1 { - name = os.Args[1] - } - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name}) - if err != nil { - log.Fatalf("could not greet: %v", err) - } - log.Printf("Greeting: %s", r.GetMessage()) -} diff --git a/_examples/mvc/grpc-compatible/helloworld/README.md b/_examples/mvc/grpc-compatible/helloworld/README.md deleted file mode 100644 index 61b3729c..00000000 --- a/_examples/mvc/grpc-compatible/helloworld/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Helloworld gRPC Example - -https://github.com/grpc/grpc-go/tree/master/examples/helloworld \ No newline at end of file diff --git a/_examples/mvc/grpc-compatible/helloworld/helloworld.pb.go b/_examples/mvc/grpc-compatible/helloworld/helloworld.pb.go deleted file mode 100644 index 6be07b7c..00000000 --- a/_examples/mvc/grpc-compatible/helloworld/helloworld.pb.go +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright 2015 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.21.0 -// protoc v3.11.1 -// source: helloworld.proto - -package helloworld - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// The request message containing the user's name. -type HelloRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` -} - -func (x *HelloRequest) Reset() { - *x = HelloRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_helloworld_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *HelloRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HelloRequest) ProtoMessage() {} - -func (x *HelloRequest) ProtoReflect() protoreflect.Message { - mi := &file_helloworld_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead. -func (*HelloRequest) Descriptor() ([]byte, []int) { - return file_helloworld_proto_rawDescGZIP(), []int{0} -} - -func (x *HelloRequest) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -// The response message containing the greetings -type HelloReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` -} - -func (x *HelloReply) Reset() { - *x = HelloReply{} - if protoimpl.UnsafeEnabled { - mi := &file_helloworld_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *HelloReply) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HelloReply) ProtoMessage() {} - -func (x *HelloReply) ProtoReflect() protoreflect.Message { - mi := &file_helloworld_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead. -func (*HelloReply) Descriptor() ([]byte, []int) { - return file_helloworld_proto_rawDescGZIP(), []int{1} -} - -func (x *HelloReply) GetMessage() string { - if x != nil { - return x.Message - } - return "" -} - -var File_helloworld_proto protoreflect.FileDescriptor - -var file_helloworld_proto_rawDesc = []byte{ - 0x0a, 0x10, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x12, 0x0a, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x22, 0x22, - 0x0a, 0x0c, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x22, 0x26, 0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x49, 0x0a, 0x07, 0x47, 0x72, - 0x65, 0x65, 0x74, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x08, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, - 0x6f, 0x12, 0x18, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x48, - 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x68, 0x65, - 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x30, 0x0a, 0x1b, 0x69, 0x6f, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, - 0x6f, 0x72, 0x6c, 0x64, 0x42, 0x0f, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x57, 0x6f, 0x72, 0x6c, 0x64, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_helloworld_proto_rawDescOnce sync.Once - file_helloworld_proto_rawDescData = file_helloworld_proto_rawDesc -) - -func file_helloworld_proto_rawDescGZIP() []byte { - file_helloworld_proto_rawDescOnce.Do(func() { - file_helloworld_proto_rawDescData = protoimpl.X.CompressGZIP(file_helloworld_proto_rawDescData) - }) - return file_helloworld_proto_rawDescData -} - -var file_helloworld_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_helloworld_proto_goTypes = []interface{}{ - (*HelloRequest)(nil), // 0: helloworld.HelloRequest - (*HelloReply)(nil), // 1: helloworld.HelloReply -} -var file_helloworld_proto_depIdxs = []int32{ - 0, // 0: helloworld.Greeter.SayHello:input_type -> helloworld.HelloRequest - 1, // 1: helloworld.Greeter.SayHello:output_type -> helloworld.HelloReply - 1, // [1:2] is the sub-list for method output_type - 0, // [0:1] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_helloworld_proto_init() } -func file_helloworld_proto_init() { - if File_helloworld_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_helloworld_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HelloRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_helloworld_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HelloReply); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_helloworld_proto_rawDesc, - NumEnums: 0, - NumMessages: 2, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_helloworld_proto_goTypes, - DependencyIndexes: file_helloworld_proto_depIdxs, - MessageInfos: file_helloworld_proto_msgTypes, - }.Build() - File_helloworld_proto = out.File - file_helloworld_proto_rawDesc = nil - file_helloworld_proto_goTypes = nil - file_helloworld_proto_depIdxs = nil -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConnInterface - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 - -// GreeterClient is the client API for Greeter service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type GreeterClient interface { - // Sends a greeting - SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) -} - -type greeterClient struct { - cc grpc.ClientConnInterface -} - -func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient { - return &greeterClient{cc} -} - -func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) { - out := new(HelloReply) - err := c.cc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// GreeterServer is the server API for Greeter service. -type GreeterServer interface { - // Sends a greeting - SayHello(context.Context, *HelloRequest) (*HelloReply, error) -} - -// UnimplementedGreeterServer can be embedded to have forward compatible implementations. -type UnimplementedGreeterServer struct { -} - -func (*UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented") -} - -func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) { - s.RegisterService(&_Greeter_serviceDesc, srv) -} - -func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(HelloRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(GreeterServer).SayHello(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/helloworld.Greeter/SayHello", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _Greeter_serviceDesc = grpc.ServiceDesc{ - ServiceName: "helloworld.Greeter", - HandlerType: (*GreeterServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "SayHello", - Handler: _Greeter_SayHello_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "helloworld.proto", -} diff --git a/_examples/mvc/grpc-compatible/helloworld/helloworld.proto b/_examples/mvc/grpc-compatible/helloworld/helloworld.proto deleted file mode 100644 index abb62783..00000000 --- a/_examples/mvc/grpc-compatible/helloworld/helloworld.proto +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2015 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package helloworld; - -// The greeting service definition. -service Greeter { - // Sends a greeting - rpc SayHello (HelloRequest) returns (HelloReply) {} -} - -// The request message containing the user's name. -message HelloRequest { - string name = 1; -} - -// The response message containing the greetings -message HelloReply { - string message = 1; -} \ No newline at end of file diff --git a/_examples/mvc/grpc-compatible/http-client/main.go b/_examples/mvc/grpc-compatible/http-client/main.go deleted file mode 100644 index f198d398..00000000 --- a/_examples/mvc/grpc-compatible/http-client/main.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "bytes" - "crypto/tls" - "crypto/x509" - "encoding/json" - "io/ioutil" - "log" - "net/http" - - pb "github.com/kataras/iris/v12/_examples/mvc/grpc-compatible/helloworld" -) - -func main() { - b, err := ioutil.ReadFile("../server.crt") - if err != nil { - log.Fatal(err) - } - cp := x509.NewCertPool() - if !cp.AppendCertsFromPEM(b) { - log.Fatal("credentials: failed to append certificates") - } - - transport := &http.Transport{ - TLSClientConfig: &tls.Config{ - RootCAs: cp, - }, - } - - client := http.Client{Transport: transport} - buf := new(bytes.Buffer) - err = json.NewEncoder(buf).Encode(pb.HelloRequest{Name: "world"}) - if err != nil { - log.Fatal(err) - } - - resp, err := client.Post("https://localhost/helloworld.Greeter/SayHello", "application/json", buf) - if err != nil { - log.Fatal(err) - } - defer resp.Body.Close() - - var reply pb.HelloReply - err = json.NewDecoder(resp.Body).Decode(&reply) - if err != nil { - log.Fatal(err) - } - log.Printf("Greeting: %s", reply.GetMessage()) -} diff --git a/_examples/mvc/grpc-compatible/main.go b/_examples/mvc/grpc-compatible/main.go deleted file mode 100644 index f93bf7a1..00000000 --- a/_examples/mvc/grpc-compatible/main.go +++ /dev/null @@ -1,74 +0,0 @@ -package main - -import ( - "context" - - pb "github.com/kataras/iris/v12/_examples/mvc/grpc-compatible/helloworld" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" - - "google.golang.org/grpc" -) - -// See https://github.com/kataras/iris/issues/1449 -// Iris automatically binds the standard "context" context.Context to `iris.Context.Request().Context()` -// and any other structure that is not mapping to a registered dependency -// as a payload depends on the request, e.g XML, YAML, Query, Form, JSON. -// -// Useful to use gRPC services as Iris controllers fast and without wrappers. - -func main() { - app := newApp() - app.Logger().SetLevel("debug") - - // The Iris server should ran under TLS (it's a gRPC requirement). - // POST: https://localhost:443/helloworld.Greeter/SayHello - // with request data: {"name": "John"} - // and expected output: {"message": "Hello John"} - app.Run(iris.TLS(":443", "server.crt", "server.key")) -} - -func newApp() *iris.Application { - app := iris.New() - // app.Configure(iris.WithLowercaseRouting) // OPTIONAL. - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

Index Page

") - }) - - ctrl := &myController{} - // Register gRPC server. - grpcServer := grpc.NewServer() - pb.RegisterGreeterServer(grpcServer, ctrl) - - // serviceName := pb.File_helloworld_proto.Services().Get(0).FullName() - - // Register MVC application controller for gRPC services. - // You can bind as many mvc gRpc services in the same Party or app, - // as the ServiceName differs. - mvc.New(app).Handle(ctrl, mvc.GRPC{ - Server: grpcServer, // Required. - ServiceName: "helloworld.Greeter", // Required. - Strict: false, - }) - - return app -} - -type myController struct { - // Ctx iris.Context -} - -// SayHello implements helloworld.GreeterServer. -// See https://github.com/kataras/iris/issues/1449#issuecomment-625570442 -// for the comments below (https://github.com/iris-contrib/swagger). -// -// @Description greet service -// @Accept json -// @Produce json -// @Success 200 {string} string "Hello {name}" -// @Router /helloworld.Greeter/SayHello [post] -func (c *myController) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { - return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil -} diff --git a/_examples/mvc/grpc-compatible/main_test.go b/_examples/mvc/grpc-compatible/main_test.go deleted file mode 100644 index f937b9d9..00000000 --- a/_examples/mvc/grpc-compatible/main_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestGRPCCompatible(t *testing.T) { - app := newApp() - - e := httptest.New(t, app) - e.POST("/helloworld.Greeter/SayHello").WithJSON(map[string]string{"name": "makis"}).Expect(). - Status(httptest.StatusOK). - JSON().Equal(map[string]string{"message": "Hello makis"}) -} diff --git a/_examples/mvc/grpc-compatible/server.crt b/_examples/mvc/grpc-compatible/server.crt deleted file mode 100644 index c554e9b1..00000000 --- a/_examples/mvc/grpc-compatible/server.crt +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDkzCCAnugAwIBAgIUZLvkZXRRB1CP8FEjpRslVNRW4HwwDQYJKoZIhvcNAQEL -BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM -GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MB4X -DTIwMDMwNzEwNDk0N1oXDTMwMDMwNTEwNDk0N1owWTELMAkGA1UEBhMCQVUxEzAR -BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 -IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEA1M0frpMcALlH2BGNNXdUlH3wmJSe9IUkfu/Il5/8SWuMWed39gL0 -Ps70TLi2cklyu5ZDuos6VRQecrkhtPWqcvM67YGM1unIJDVJJJZaiEMTLCv+1srE -+6DZBPZ3vrtA1Z3GH0xzDGyGyTNeQ+yRjdZkjYlalFkswi83qQzbwMx9bba76Tmg -ojfwMbYeoXMmQsIeKuCtpHNYo1uY1fIKnBa9CjOaJfshI+ch9YcFuntRYYS/UrXe -6XTnweFFN4MsSjkxlu7AImT2xW56y9Z64CYLwmT4MDB80FcKS/eRpCyG+KILoZXb -Jj8weneyG0An6gsAkZuN0I6M+XlXxYCzgQIDAQABo1MwUTAdBgNVHQ4EFgQUZLMV -958+SxbRbS3Yjy/9Yyo+FYAwHwYDVR0jBBgwFoAUZLMV958+SxbRbS3Yjy/9Yyo+ -FYAwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEANNSkFO6bxt8f -b7ZoNXYdBBopwx6o9e8uMLlWP1Wv3l0AWdn5WBlTj5ZoS90lKPEvLKO+BI096fwc -lC1P073k3mbXz0fQ/zyyz+7xn6h5FCe66LXU8AhpewolkIogSGwx4NT7lwIYpJ8T -BQXRtNtP3dH9w8iOpFECQIcLCMBamM1UGithrZRNmzYomFMnQYUz7A41eyXyTZ80 -IE5NbwVmd2XYpwrfqror6wkE5Psp3Fb7flKgMT1bU1ugmojIQEmFAYSUTSI7aNmT -W1XenU5tvCmSUnUgUW/vxj8u6W5SP5Lr0jirKT6WUON8lo5C/uWjzkX5Ij6J63JI -w0xukwlSLg== ------END CERTIFICATE----- diff --git a/_examples/mvc/grpc-compatible/server.key b/_examples/mvc/grpc-compatible/server.key deleted file mode 100644 index af79c0d1..00000000 --- a/_examples/mvc/grpc-compatible/server.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEA1M0frpMcALlH2BGNNXdUlH3wmJSe9IUkfu/Il5/8SWuMWed3 -9gL0Ps70TLi2cklyu5ZDuos6VRQecrkhtPWqcvM67YGM1unIJDVJJJZaiEMTLCv+ -1srE+6DZBPZ3vrtA1Z3GH0xzDGyGyTNeQ+yRjdZkjYlalFkswi83qQzbwMx9bba7 -6TmgojfwMbYeoXMmQsIeKuCtpHNYo1uY1fIKnBa9CjOaJfshI+ch9YcFuntRYYS/ -UrXe6XTnweFFN4MsSjkxlu7AImT2xW56y9Z64CYLwmT4MDB80FcKS/eRpCyG+KIL -oZXbJj8weneyG0An6gsAkZuN0I6M+XlXxYCzgQIDAQABAoIBAQCY12d8/L4tKuaW -Iy0YDMhcCwSmooB0wbhPz6t0c/1BQpTA8gZwVPjWr9A51qV7+pMEds3Yiy1vdA7W -eW/jSFuPSnG1qsnchncwwnDxbWhC3GJF5KeZ4HORA5s7/EZPYLEVfMeTLVaowr4g -ftuiz6RPioAYRGIhkNcb9cv1iH3BwA7B5D1T+qnOcxgrc4pK5Ecle9NyImU5q002 -vMh3zGuHz+H4zY66oOTplQ5gDONXkEGXCKIKczeFUMUiTVhQwEn/MYHmc+Gm2UVE -S29Is4/DdxCt3x2CRdC/2tsUK20azT51vzKs6qZ/Zvu4smOeov7KJ3Yedye62Dvx -SMrnVwJRAoGBAOovi0Mq1JYPUFBztSza9IiaKXgf9KVE34fPa41aSiLsqQIoiXel -My/LXmrjAKtUiusqUscC+KD+PvR926ceEyObE0lqYuE5MH3XYn25KF35RibD3qhv -Fd57GrgXVuTuB7Rqi8bvmgq/aTSSeFjNF1grojGvSHOb/i1LW8+9jiO1AoGBAOif -o+ndgkkpGloQv34Lko8YZyySaLoQDSrtyCmcE3DGTRVTtuVxZbU8ZRp726km6dQg -w+XbnlF07j7S3S2jvkIx1a/q3DhOe50uMlgEMUtvLtcgTKeqxBL0WWg1wZDWZI5R -Km1JzNl9QxN5MOMkD7XHdTZLO8wDwhr7ggp9xQgdAoGAXMOIfoqwuuBGCBhNY/83 -bgTi+FpwJicqBDn9eHiTdVIZgGleSq59oCkGtYBF+5f5jz2snHho1BziAyb3ozMe -kbQT57jkgiKNOsvej76QZukfCKv9vuqB1yccZl+YZAaFtsmdpKe0dR1tJw397e8P -mDVwgg3UvTbFcFuxepCzhSECgYBl/rEA9nWMnHAIc3Vyz6IoCbwbJ+qxQh5z5yQv -UlaXyOq9YiI8QdcleuCdlxb9+KjnsKIUI5IsBwf7FbuSqkvefDlEU8bRDWBXz4yV -WOlAOPShsHDLxy0HXonhDkjbt5UJbX8bwhMGfUyuuiF8RjB5NIYpEx2Z2z/9Uq92 -6CQ+5QKBgFZemvsuHfuAmEeHS0YfEs47IJIC1GtzfmJXT6w05wPKhMQbB+89HBlJ -Qbn1fG8B3hye6VCRAXk7B7w/FIPCeGUu4TQpoBzmtkH9LC8q09CPCxDISY64MQ1a -fJ2xUWbJbEQv799eTyxIXMG7+L+WYbKrZaiQzB2G/36ID1h7wCXi ------END RSA PRIVATE KEY----- diff --git a/_examples/mvc/hello-world/main.go b/_examples/mvc/hello-world/main.go deleted file mode 100644 index 10a4797c..00000000 --- a/_examples/mvc/hello-world/main.go +++ /dev/null @@ -1,154 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" - - "github.com/kataras/iris/v12/middleware/logger" - "github.com/kataras/iris/v12/middleware/recover" -) - -// This example is equivalent to the -// https://github.com/kataras/iris/blob/master/_examples/hello-world/main.go -// -// It seems that additional code you -// have to write doesn't worth it -// but remember that, this example -// does not make use of iris mvc features like -// the Model, Persistence or the View engine neither the Session, -// it's very simple for learning purposes, -// probably you'll never use such -// as simple controller anywhere in your app. -// -// The cost we have on this example for using MVC -// on the "/hello" path which serves JSON -// is ~2MB per 20MB throughput on my personal laptop, -// it's tolerated for the majority of the applications -// but you can choose -// what suits you best with Iris, low-level handlers: performance -// or high-level controllers: easier to maintain and smaller codebase on large applications. - -// Of course you can put all these to main func, it's just a separate function -// for the main_test.go. -func newApp() *iris.Application { - app := iris.New() - // Optionally, add two builtin handlers - // that can recover from any http-relative panics - // and log the requests to the terminal. - app.Use(recover.New()) - app.Use(logger.New()) - - // Serve a controller based on the root Router, "/". - mvc.New(app).Handle(new(ExampleController)) - return app -} - -func main() { - app := newApp() - - // http://localhost:8080 - // http://localhost:8080/ping - // http://localhost:8080/hello - // http://localhost:8080/custom_path - app.Listen(":8080") -} - -// ExampleController serves the "/", "/ping" and "/hello". -type ExampleController struct{} - -// Get serves -// Method: GET -// Resource: http://localhost:8080 -func (c *ExampleController) Get() mvc.Result { - return mvc.Response{ - ContentType: "text/html", - Text: "

Welcome

", - } -} - -// GetPing serves -// Method: GET -// Resource: http://localhost:8080/ping -func (c *ExampleController) GetPing() string { - return "pong" -} - -// GetHello serves -// Method: GET -// Resource: http://localhost:8080/hello -func (c *ExampleController) GetHello() interface{} { - return map[string]string{"message": "Hello Iris!"} -} - -// BeforeActivation called once, before the controller adapted to the main application -// and of course before the server ran. -// After version 9 you can also add custom routes for a specific controller's methods. -// Here you can register custom method's handlers -// use the standard router with `ca.Router` to do something that you can do without mvc as well, -// and add dependencies that will be binded to a controller's fields or method function's input arguments. -func (c *ExampleController) BeforeActivation(b mvc.BeforeActivation) { - anyMiddlewareHere := func(ctx iris.Context) { - ctx.Application().Logger().Warnf("Inside /custom_path") - ctx.Next() - } - b.Handle("GET", "/custom_path", "CustomHandlerWithoutFollowingTheNamingGuide", anyMiddlewareHere) - - // or even add a global middleware based on this controller's router, - // which in this example is the root "/": - // b.Router().Use(myMiddleware) -} - -// CustomHandlerWithoutFollowingTheNamingGuide serves -// Method: GET -// Resource: http://localhost:8080/custom_path -func (c *ExampleController) CustomHandlerWithoutFollowingTheNamingGuide() string { - return "hello from the custom handler without following the naming guide" -} - -// GetUserBy serves -// Method: GET -// Resource: http://localhost:8080/user/{username:string} -// By is a reserved "keyword" to tell the framework that you're going to -// bind path parameters in the function's input arguments, and it also -// helps to have "Get" and "GetBy" in the same controller. -// -// func (c *ExampleController) GetUserBy(username string) mvc.Result { -// return mvc.View{ -// Name: "user/username.html", -// Data: username, -// } -// } - -/* Can use more than one, the factory will make sure -that the correct http methods are being registered for each route -for this controller, uncomment these if you want: - -func (c *ExampleController) Post() {} -func (c *ExampleController) Put() {} -func (c *ExampleController) Delete() {} -func (c *ExampleController) Connect() {} -func (c *ExampleController) Head() {} -func (c *ExampleController) Patch() {} -func (c *ExampleController) Options() {} -func (c *ExampleController) Trace() {} -*/ - -/* -func (c *ExampleController) All() {} -// OR -func (c *ExampleController) Any() {} - - - -func (c *ExampleController) BeforeActivation(b mvc.BeforeActivation) { - // 1 -> the HTTP Method - // 2 -> the route's path - // 3 -> this controller's method name that should be handler for that route. - b.Handle("GET", "/mypath/{param}", "DoIt", optionalMiddlewareHere...) -} - -// After activation, all dependencies are set-ed - so read only access on them -// but still possible to add custom controller or simple standard handlers. -func (c *ExampleController) AfterActivation(a mvc.AfterActivation) {} - -*/ diff --git a/_examples/mvc/hello-world/main_test.go b/_examples/mvc/hello-world/main_test.go deleted file mode 100644 index 5fe2d368..00000000 --- a/_examples/mvc/hello-world/main_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestMVCHelloWorld(t *testing.T) { - e := httptest.New(t, newApp()) - - e.GET("/").Expect().Status(httptest.StatusOK). - ContentType("text/html", "utf-8").Body().Equal("

Welcome

") - - e.GET("/ping").Expect().Status(httptest.StatusOK). - Body().Equal("pong") - - e.GET("/hello").Expect().Status(httptest.StatusOK). - JSON().Object().Value("message").Equal("Hello Iris!") - - e.GET("/custom_path").Expect().Status(httptest.StatusOK). - Body().Equal("hello from the custom handler without following the naming guide") -} diff --git a/_examples/mvc/login-mvc-single-responsibility/folder_structure.png b/_examples/mvc/login-mvc-single-responsibility/folder_structure.png deleted file mode 100644 index 955e436e834d2494950d59fda49d6be3d8135518..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28423 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 diff --git a/_examples/mvc/login-mvc-single-responsibility/main.go b/_examples/mvc/login-mvc-single-responsibility/main.go deleted file mode 100644 index c64a120f..00000000 --- a/_examples/mvc/login-mvc-single-responsibility/main.go +++ /dev/null @@ -1,56 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12/_examples/mvc/login-mvc-single-responsibility/user" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" - "github.com/kataras/iris/v12/sessions" -) - -func main() { - app := iris.New() - // You got full debug messages, useful when using MVC and you want to make - // sure that your code is aligned with the Iris' MVC Architecture. - app.Logger().SetLevel("debug") - - app.RegisterView(iris.HTML("./views", ".html").Layout("shared/layout.html")) - - app.HandleDir("/public", iris.Dir("./public")) - - userRouter := app.Party("/user") - { - manager := sessions.New(sessions.Config{ - Cookie: "sessioncookiename", - Expires: 24 * time.Hour, - }) - userRouter.Use(manager.Handler()) - mvc.Configure(userRouter, configureUserMVC) - } - - // http://localhost:8080/user/register - // http://localhost:8080/user/login - // http://localhost:8080/user/me - // http://localhost:8080/user/logout - // http://localhost:8080/user/1 - app.Listen(":8080", configure) -} - -func configureUserMVC(userApp *mvc.Application) { - userApp.Register( - user.NewDataSource(), - ) - userApp.Handle(new(user.Controller)) -} - -func configure(app *iris.Application) { - app.Configure( - iris.WithOptimizations, - iris.WithFireMethodNotAllowed, - iris.WithLowercaseRouting, - iris.WithPathIntelligence, - iris.WithTunneling, - ) -} diff --git a/_examples/mvc/login-mvc-single-responsibility/public/css/site.css b/_examples/mvc/login-mvc-single-responsibility/public/css/site.css deleted file mode 100644 index 163af622..00000000 --- a/_examples/mvc/login-mvc-single-responsibility/public/css/site.css +++ /dev/null @@ -1,61 +0,0 @@ -/* Bordered form */ -form { - border: 3px solid #f1f1f1; -} - -/* Full-width inputs */ -input[type=text], input[type=password] { - width: 100%; - padding: 12px 20px; - margin: 8px 0; - display: inline-block; - border: 1px solid #ccc; - box-sizing: border-box; -} - -/* Set a style for all buttons */ -button { - background-color: #4CAF50; - color: white; - padding: 14px 20px; - margin: 8px 0; - border: none; - cursor: pointer; - width: 100%; -} - -/* Add a hover effect for buttons */ -button:hover { - opacity: 0.8; -} - -/* Extra style for the cancel button (red) */ -.cancelbtn { - width: auto; - padding: 10px 18px; - background-color: #f44336; -} - -/* Center the container */ - -/* Add padding to containers */ -.container { - padding: 16px; -} - -/* The "Forgot password" text */ -span.psw { - float: right; - padding-top: 16px; -} - -/* Change styles for span and cancel button on extra small screens */ -@media screen and (max-width: 300px) { - span.psw { - display: block; - float: none; - } - .cancelbtn { - width: 100%; - } -} \ No newline at end of file diff --git a/_examples/mvc/login-mvc-single-responsibility/user/auth.go b/_examples/mvc/login-mvc-single-responsibility/user/auth.go deleted file mode 100644 index 64ded5df..00000000 --- a/_examples/mvc/login-mvc-single-responsibility/user/auth.go +++ /dev/null @@ -1,110 +0,0 @@ -package user - -import ( - "errors" - "strconv" - "strings" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" - "github.com/kataras/iris/v12/sessions" -) - -const sessionIDKey = "UserID" - -// paths -var ( - PathLogin = mvc.Response{Path: "/user/login"} - PathLogout = mvc.Response{Path: "/user/logout"} -) - -// AuthController is the user authentication controller, a custom shared controller. -type AuthController struct { - // context is auto-binded if struct depends on this, - // in this controller we don't we do everything with mvc-style, - // and that's neither the 30% of its features. - // Ctx iris.Context - - Source *DataSource - Session *sessions.Session - - // the whole controller is request-scoped because we already depend on Session, so - // this will be new for each new incoming request, BeginRequest sets that based on the session. - UserID int64 -} - -// BeginRequest saves login state to the context, the user id. -func (c *AuthController) BeginRequest(ctx iris.Context) { - c.UserID, _ = c.Session.GetInt64(sessionIDKey) -} - -// EndRequest is here just to complete the BaseController -// in order to be tell iris to call the `BeginRequest` before the main method. -func (c *AuthController) EndRequest(ctx iris.Context) {} - -func (c *AuthController) fireError(err error) mvc.View { - return mvc.View{ - Code: iris.StatusBadRequest, - Name: "shared/error.html", - Data: iris.Map{"Title": "User Error", "Message": strings.ToUpper(err.Error())}, - } -} - -func (c *AuthController) redirectTo(id int64) mvc.Response { - return mvc.Response{Path: "/user/" + strconv.Itoa(int(id))} -} - -func (c *AuthController) createOrUpdate(firstname, username, password string) (user Model, err error) { - username = strings.Trim(username, " ") - if username == "" || password == "" || firstname == "" { - return user, errors.New("empty firstname, username or/and password") - } - - userToInsert := Model{ - Firstname: firstname, - Username: username, - password: password, - } // password is hashed by the Source. - - newUser, err := c.Source.InsertOrUpdate(userToInsert) - if err != nil { - return user, err - } - - return newUser, nil -} - -func (c *AuthController) isLoggedIn() bool { - // we don't search by session, we have the user id - // already by the `BeginRequest` middleware. - return c.UserID > 0 -} - -func (c *AuthController) verify(username, password string) (user Model, err error) { - if username == "" || password == "" { - return user, errors.New("please fill both username and password fields") - } - - u, found := c.Source.GetByUsername(username) - if !found { - // if user found with that username not found at all. - return user, errors.New("user with that username does not exist") - } - - if ok, err := ValidatePassword(password, u.HashedPassword); err != nil || !ok { - // if user found but an error occurred or the password is not valid. - return user, errors.New("please try to login with valid credentials") - } - - return u, nil -} - -// if logged in then destroy the session -// and redirect to the login page -// otherwise redirect to the registration page. -func (c *AuthController) logout() mvc.Response { - if c.isLoggedIn() { - c.Session.Destroy() - } - return PathLogin -} diff --git a/_examples/mvc/login-mvc-single-responsibility/user/controller.go b/_examples/mvc/login-mvc-single-responsibility/user/controller.go deleted file mode 100644 index b4777e4b..00000000 --- a/_examples/mvc/login-mvc-single-responsibility/user/controller.go +++ /dev/null @@ -1,189 +0,0 @@ -package user - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" -) - -var ( - // About Code: iris.StatusSeeOther -> - // When redirecting from POST to GET request you -should- use this HTTP status code, - // however there're some (complicated) alternatives if you - // search online or even the HTTP RFC. - // "See Other" RFC 7231 - pathMyProfile = mvc.Response{Path: "/user/me", Code: iris.StatusSeeOther} - pathRegister = mvc.Response{Path: "/user/register"} -) - -// Controller is responsible to handle the following requests: -// GET /user/register -// POST /user/register -// GET /user/login -// POST /user/login -// GET /user/me -// GET /user/{id:int64} -// All HTTP Methods /user/logout -type Controller struct { - AuthController -} - -type formValue func(string) string - -// BeforeActivation called once before the server start -// and before the controller's registration, here you can add -// dependencies, to this controller and only, that the main caller may skip. -func (c *Controller) BeforeActivation(b mvc.BeforeActivation) { - // bind the context's `FormValue` as well in order to be - // acceptable on the controller or its methods' input arguments (NEW feature as well). - b.Dependencies().Register(func(ctx iris.Context) formValue { return ctx.FormValue }) -} - -type page struct { - Title string -} - -// GetRegister handles GET:/user/register. -// mvc.Result can accept any struct which contains a `Dispatch(ctx iris.Context)` method. -// Both mvc.Response and mvc.View are mvc.Result. -func (c *Controller) GetRegister() mvc.Result { - if c.isLoggedIn() { - return c.logout() - } - - // You could just use it as a variable to win some time in serve-time, - // this is an exersise for you :) - return mvc.View{ - Name: pathRegister.Path + ".html", - Data: page{"User Registration"}, - } -} - -// PostRegister handles POST:/user/register. -func (c *Controller) PostRegister(form formValue) mvc.Result { - // we can either use the `c.Ctx.ReadForm` or read values one by one. - var ( - firstname = form("firstname") - username = form("username") - password = form("password") - ) - - user, err := c.createOrUpdate(firstname, username, password) - if err != nil { - return c.fireError(err) - } - - // setting a session value was never easier. - c.Session.Set(sessionIDKey, user.ID) - // succeed, nothing more to do here, just redirect to the /user/me. - return pathMyProfile -} - -// with these static views, -// you can use variables-- that are initialized before server start -// so you can win some time on serving. -// You can do it else where as well but I let them as pracise for you, -// essentially you can understand by just looking below. -var userLoginView = mvc.View{ - Name: PathLogin.Path + ".html", - Data: page{"User Login"}, -} - -// GetLogin handles GET:/user/login. -func (c *Controller) GetLogin() mvc.Result { - if c.isLoggedIn() { - return c.logout() - } - return userLoginView -} - -// PostLogin handles POST:/user/login. -func (c *Controller) PostLogin(form formValue) mvc.Result { - var ( - username = form("username") - password = form("password") - ) - - user, err := c.verify(username, password) - if err != nil { - return c.fireError(err) - } - - c.Session.Set(sessionIDKey, user.ID) - return pathMyProfile -} - -// AnyLogout handles any method on path /user/logout. -func (c *Controller) AnyLogout() { - c.logout() -} - -// GetMe handles GET:/user/me. -func (c *Controller) GetMe() mvc.Result { - id, err := c.Session.GetInt64(sessionIDKey) - if err != nil || id <= 0 { - // when not already logged in, redirect to login. - return PathLogin - } - - u, found := c.Source.GetByID(id) - if !found { - // if the session exists but for some reason the user doesn't exist in the "database" - // then logout him and redirect to the register page. - return c.logout() - } - - // set the model and render the view template. - return mvc.View{ - Name: pathMyProfile.Path + ".html", - Data: iris.Map{ - "Title": "Profile of " + u.Username, - "User": u, - }, - } -} - -func (c *Controller) renderNotFound(id int64) mvc.View { - return mvc.View{ - Code: iris.StatusNotFound, - Name: "user/notfound.html", - Data: iris.Map{ - "Title": "User Not Found", - "ID": id, - }, - } -} - -// Dispatch completes the `mvc.Result` interface -// in order to be able to return a type of `Model` -// as mvc.Result. -// If this function didn't exist then -// we should explicit set the output result to that Model or to an interface{}. -func (u Model) Dispatch(ctx iris.Context) { - ctx.JSON(u) -} - -// GetBy handles GET:/user/{id:int64}, -// i.e http://localhost:8080/user/1 -func (c *Controller) GetBy(userID int64) mvc.Result { - // we have /user/{id} - // fetch and render user json. - user, found := c.Source.GetByID(userID) - if !found { - // not user found with that ID. - return c.renderNotFound(userID) - } - - // Q: how the hell Model can be return as mvc.Result? - // A: I told you before on some comments and the docs, - // any struct that has a `Dispatch(ctx iris.Context)` - // can be returned as an mvc.Result(see ~20 lines above), - // therefore we are able to combine many type of results in the same method. - // For example, here, we return either an mvc.View to render a not found custom template - // either a user which returns the Model as JSON via its Dispatch. - // - // We could also return just a struct value that is not an mvc.Result, - // if the output result of the `GetBy` was that struct's type or an interface{} - // and iris would render that with JSON as well, but here we can't do that without complete the `Dispatch` - // function, because we may return an mvc.View which is an mvc.Result. - return user -} diff --git a/_examples/mvc/login-mvc-single-responsibility/user/datasource.go b/_examples/mvc/login-mvc-single-responsibility/user/datasource.go deleted file mode 100644 index ad596e21..00000000 --- a/_examples/mvc/login-mvc-single-responsibility/user/datasource.go +++ /dev/null @@ -1,114 +0,0 @@ -package user - -import ( - "errors" - "sync" - "time" -) - -// IDGenerator would be our user ID generator -// but here we keep the order of users by their IDs -// so we will use numbers that can be easly written -// to the browser to get results back from the REST API. -// var IDGenerator = func() string { -// return uuid.NewV4().String() -// } - -// DataSource is our data store example. -type DataSource struct { - Users map[int64]Model - mu sync.RWMutex -} - -// NewDataSource returns a new user data source. -func NewDataSource() *DataSource { - return &DataSource{ - Users: make(map[int64]Model), - } -} - -// GetBy receives a query function -// which is fired for every single user model inside -// our imaginary database. -// When that function returns true then it stops the iteration. -// -// It returns the query's return last known boolean value -// and the last known user model -// to help callers to reduce the loc. -// -// But be carefully, the caller should always check for the "found" -// because it may be false but the user model has actually real data inside it. -// -// It's actually a simple but very clever prototype function -// I'm think of and using everywhere since then, -// hope you find it very useful too. -func (d *DataSource) GetBy(query func(Model) bool) (user Model, found bool) { - d.mu.RLock() - for _, user = range d.Users { - found = query(user) - if found { - break - } - } - d.mu.RUnlock() - return -} - -// GetByID returns a user model based on its ID. -func (d *DataSource) GetByID(id int64) (Model, bool) { - return d.GetBy(func(u Model) bool { - return u.ID == id - }) -} - -// GetByUsername returns a user model based on the Username. -func (d *DataSource) GetByUsername(username string) (Model, bool) { - return d.GetBy(func(u Model) bool { - return u.Username == username - }) -} - -func (d *DataSource) getLastID() (lastID int64) { - d.mu.RLock() - for id := range d.Users { - if id > lastID { - lastID = id - } - } - d.mu.RUnlock() - - return lastID -} - -// InsertOrUpdate adds or updates a user to the (memory) storage. -func (d *DataSource) InsertOrUpdate(user Model) (Model, error) { - // no matter what we will update the password hash - // for both update and insert actions. - hashedPassword, err := GeneratePassword(user.password) - if err != nil { - return user, err - } - user.HashedPassword = hashedPassword - - // update - if id := user.ID; id > 0 { - _, found := d.GetByID(id) - if !found { - return user, errors.New("ID should be zero or a valid one that maps to an existing User") - } - d.mu.Lock() - d.Users[id] = user - d.mu.Unlock() - return user, nil - } - - // insert - id := d.getLastID() + 1 - user.ID = id - d.mu.Lock() - user.CreatedAt = time.Now() - d.Users[id] = user - d.mu.Unlock() - - return user, nil -} diff --git a/_examples/mvc/login-mvc-single-responsibility/user/model.go b/_examples/mvc/login-mvc-single-responsibility/user/model.go deleted file mode 100644 index c49c462a..00000000 --- a/_examples/mvc/login-mvc-single-responsibility/user/model.go +++ /dev/null @@ -1,36 +0,0 @@ -package user - -import ( - "time" - - "golang.org/x/crypto/bcrypt" -) - -// Model is our User example model. -type Model struct { - ID int64 `json:"id"` - Firstname string `json:"firstname"` - Username string `json:"username"` - // password is the client-given password - // which will not be stored anywhere in the server. - // It's here only for actions like registration and update password, - // because we caccept a Model instance - // inside the `DataSource#InsertOrUpdate` function. - password string - HashedPassword []byte `json:"-"` - CreatedAt time.Time `json:"created_at"` -} - -// GeneratePassword will generate a hashed password for us based on the -// user's input. -func GeneratePassword(userPassword string) ([]byte, error) { - return bcrypt.GenerateFromPassword([]byte(userPassword), bcrypt.DefaultCost) -} - -// ValidatePassword will check if passwords are matched. -func ValidatePassword(userPassword string, hashed []byte) (bool, error) { - if err := bcrypt.CompareHashAndPassword(hashed, []byte(userPassword)); err != nil { - return false, err - } - return true, nil -} diff --git a/_examples/mvc/login-mvc-single-responsibility/views/shared/error.html b/_examples/mvc/login-mvc-single-responsibility/views/shared/error.html deleted file mode 100644 index aca44bcc..00000000 --- a/_examples/mvc/login-mvc-single-responsibility/views/shared/error.html +++ /dev/null @@ -1,4 +0,0 @@ -

Error.

-

An error occurred while processing your request.

- -

{{.Message}}

\ No newline at end of file diff --git a/_examples/mvc/login-mvc-single-responsibility/views/shared/layout.html b/_examples/mvc/login-mvc-single-responsibility/views/shared/layout.html deleted file mode 100644 index 1e02677b..00000000 --- a/_examples/mvc/login-mvc-single-responsibility/views/shared/layout.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - {{.Title}} - - - - - {{ yield }} - - - \ No newline at end of file diff --git a/_examples/mvc/login-mvc-single-responsibility/views/user/login.html b/_examples/mvc/login-mvc-single-responsibility/views/user/login.html deleted file mode 100644 index 132c739e..00000000 --- a/_examples/mvc/login-mvc-single-responsibility/views/user/login.html +++ /dev/null @@ -1,11 +0,0 @@ -
-
- - - - - - - -
-
\ No newline at end of file diff --git a/_examples/mvc/login-mvc-single-responsibility/views/user/me.html b/_examples/mvc/login-mvc-single-responsibility/views/user/me.html deleted file mode 100644 index 17e2f0b3..00000000 --- a/_examples/mvc/login-mvc-single-responsibility/views/user/me.html +++ /dev/null @@ -1,3 +0,0 @@ -

- Welcome back {{.User.Firstname}}! -

\ No newline at end of file diff --git a/_examples/mvc/login-mvc-single-responsibility/views/user/notfound.html b/_examples/mvc/login-mvc-single-responsibility/views/user/notfound.html deleted file mode 100644 index c0000bda..00000000 --- a/_examples/mvc/login-mvc-single-responsibility/views/user/notfound.html +++ /dev/null @@ -1,3 +0,0 @@ -

- User with ID {{.ID}} does not exist. -

\ No newline at end of file diff --git a/_examples/mvc/login-mvc-single-responsibility/views/user/register.html b/_examples/mvc/login-mvc-single-responsibility/views/user/register.html deleted file mode 100644 index 79684d99..00000000 --- a/_examples/mvc/login-mvc-single-responsibility/views/user/register.html +++ /dev/null @@ -1,14 +0,0 @@ -
-
- - - - - - - - - - -
-
\ No newline at end of file diff --git a/_examples/mvc/login/datamodels/user.go b/_examples/mvc/login/datamodels/user.go deleted file mode 100644 index fdcb63f9..00000000 --- a/_examples/mvc/login/datamodels/user.go +++ /dev/null @@ -1,41 +0,0 @@ -package datamodels - -import ( - "time" - - "golang.org/x/crypto/bcrypt" -) - -// User is our User example model. -// Keep note that the tags for public-use (for our web app) -// should be kept in other file like "web/viewmodels/user.go" -// which could wrap by embedding the datamodels.User or -// define completely new fields instead but for the sake -// of the example, we will use this datamodel -// as the only one User model in our application. -type User struct { - ID int64 `json:"id" form:"id"` - Firstname string `json:"firstname" form:"firstname"` - Username string `json:"username" form:"username"` - HashedPassword []byte `json:"-" form:"-"` - CreatedAt time.Time `json:"created_at" form:"created_at"` -} - -// IsValid can do some very very simple "low-level" data validations. -func (u User) IsValid() bool { - return u.ID > 0 -} - -// GeneratePassword will generate a hashed password for us based on the -// user's input. -func GeneratePassword(userPassword string) ([]byte, error) { - return bcrypt.GenerateFromPassword([]byte(userPassword), bcrypt.DefaultCost) -} - -// ValidatePassword will check if passwords are matched. -func ValidatePassword(userPassword string, hashed []byte) (bool, error) { - if err := bcrypt.CompareHashAndPassword(hashed, []byte(userPassword)); err != nil { - return false, err - } - return true, nil -} diff --git a/_examples/mvc/login/datasource/users.go b/_examples/mvc/login/datasource/users.go deleted file mode 100644 index 1c3fb74a..00000000 --- a/_examples/mvc/login/datasource/users.go +++ /dev/null @@ -1,31 +0,0 @@ -// file: datasource/users.go - -package datasource - -import ( - "errors" - - "github.com/kataras/iris/v12/_examples/mvc/login/datamodels" -) - -// Engine is from where to fetch the data, in this case the users. -type Engine uint32 - -const ( - // Memory stands for simple memory location; - // map[int64] datamodels.User ready to use, it's our source in this example. - Memory Engine = iota - // Bolt for boltdb source location. - Bolt - // MySQL for mysql-compatible source location. - MySQL -) - -// LoadUsers returns all users(empty map) from the memory, for the sake of simplicty. -func LoadUsers(engine Engine) (map[int64]datamodels.User, error) { - if engine != Memory { - return nil, errors.New("for the sake of simplicity we're using a simple map as the data source") - } - - return make(map[int64]datamodels.User), nil -} diff --git a/_examples/mvc/login/folder_structure.png b/_examples/mvc/login/folder_structure.png deleted file mode 100644 index c89b273dd080646f4912ec0177b4058c1e9afd9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33014 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 loops { - break // break - } - } - } - } - - return -} - -// Select receives a query function -// which is fired for every single user model inside -// our imaginary data source. -// When that function returns true then it stops the iteration. -// -// It returns the query's return last known boolean value -// and the last known user model -// to help callers to reduce the LOC. -// -// It's actually a simple but very clever prototype function -// I'm using everywhere since I firstly think of it, -// hope you'll find it very useful as well. -func (r *userMemoryRepository) Select(query Query) (user datamodels.User, found bool) { - found = r.Exec(query, func(m datamodels.User) bool { - user = m - return true - }, 1, ReadOnlyMode) - - // set an empty datamodels.User if not found at all. - if !found { - user = datamodels.User{} - } - - return -} - -// SelectMany same as Select but returns one or more datamodels.User as a slice. -// If limit <=0 then it returns everything. -func (r *userMemoryRepository) SelectMany(query Query, limit int) (results []datamodels.User) { - r.Exec(query, func(m datamodels.User) bool { - results = append(results, m) - return true - }, limit, ReadOnlyMode) - - return -} - -// InsertOrUpdate adds or updates a user to the (memory) storage. -// -// Returns the new user and an error if any. -func (r *userMemoryRepository) InsertOrUpdate(user datamodels.User) (datamodels.User, error) { - id := user.ID - - if id == 0 { // Create new action - var lastID int64 - // find the biggest ID in order to not have duplications - // in productions apps you can use a third-party - // library to generate a UUID as string. - r.mu.RLock() - for _, item := range r.source { - if item.ID > lastID { - lastID = item.ID - } - } - r.mu.RUnlock() - - id = lastID + 1 - user.ID = id - - // map-specific thing - r.mu.Lock() - r.source[id] = user - r.mu.Unlock() - - return user, nil - } - - // Update action based on the user.ID, - // here we will allow updating the poster and genre if not empty. - // Alternatively we could do pure replace instead: - // r.source[id] = user - // and comment the code below; - current, exists := r.Select(func(m datamodels.User) bool { - return m.ID == id - }) - - if !exists { // ID is not a real one, return an error. - return datamodels.User{}, errors.New("failed to update a nonexistent user") - } - - // or comment these and r.source[id] = user for pure replace - if user.Username != "" { - current.Username = user.Username - } - - if user.Firstname != "" { - current.Firstname = user.Firstname - } - - // map-specific thing - r.mu.Lock() - r.source[id] = current - r.mu.Unlock() - - return user, nil -} - -func (r *userMemoryRepository) Delete(query Query, limit int) bool { - return r.Exec(query, func(m datamodels.User) bool { - delete(r.source, m.ID) - return true - }, limit, ReadWriteMode) -} diff --git a/_examples/mvc/login/services/user_service.go b/_examples/mvc/login/services/user_service.go deleted file mode 100644 index 4921c4f9..00000000 --- a/_examples/mvc/login/services/user_service.go +++ /dev/null @@ -1,125 +0,0 @@ -package services - -import ( - "errors" - - "github.com/kataras/iris/v12/_examples/mvc/login/datamodels" - "github.com/kataras/iris/v12/_examples/mvc/login/repositories" -) - -// UserService handles CRUID operations of a user datamodel, -// it depends on a user repository for its actions. -// It's here to decouple the data source from the higher level compoments. -// As a result a different repository type can be used with the same logic without any aditional changes. -// It's an interface and it's used as interface everywhere -// because we may need to change or try an experimental different domain logic at the future. -type UserService interface { - GetAll() []datamodels.User - GetByID(id int64) (datamodels.User, bool) - GetByUsernameAndPassword(username, userPassword string) (datamodels.User, bool) - DeleteByID(id int64) bool - - Update(id int64, user datamodels.User) (datamodels.User, error) - UpdatePassword(id int64, newPassword string) (datamodels.User, error) - UpdateUsername(id int64, newUsername string) (datamodels.User, error) - - Create(userPassword string, user datamodels.User) (datamodels.User, error) -} - -// NewUserService returns the default user service. -func NewUserService(repo repositories.UserRepository) UserService { - return &userService{ - repo: repo, - } -} - -type userService struct { - repo repositories.UserRepository -} - -// GetAll returns all users. -func (s *userService) GetAll() []datamodels.User { - return s.repo.SelectMany(func(_ datamodels.User) bool { - return true - }, -1) -} - -// GetByID returns a user based on its id. -func (s *userService) GetByID(id int64) (datamodels.User, bool) { - return s.repo.Select(func(m datamodels.User) bool { - return m.ID == id - }) -} - -// GetByUsernameAndPassword returns a user based on its username and passowrd, -// used for authentication. -func (s *userService) GetByUsernameAndPassword(username, userPassword string) (datamodels.User, bool) { - if username == "" || userPassword == "" { - return datamodels.User{}, false - } - - return s.repo.Select(func(m datamodels.User) bool { - if m.Username == username { - hashed := m.HashedPassword - if ok, _ := datamodels.ValidatePassword(userPassword, hashed); ok { - return true - } - } - return false - }) -} - -// Update updates every field from an existing User, -// it's not safe to be used via public API, -// however we will use it on the web/controllers/user_controller.go#PutBy -// in order to show you how it works. -func (s *userService) Update(id int64, user datamodels.User) (datamodels.User, error) { - user.ID = id - return s.repo.InsertOrUpdate(user) -} - -// UpdatePassword updates a user's password. -func (s *userService) UpdatePassword(id int64, newPassword string) (datamodels.User, error) { - // update the user and return it. - hashed, err := datamodels.GeneratePassword(newPassword) - if err != nil { - return datamodels.User{}, err - } - - return s.Update(id, datamodels.User{ - HashedPassword: hashed, - }) -} - -// UpdateUsername updates a user's username. -func (s *userService) UpdateUsername(id int64, newUsername string) (datamodels.User, error) { - return s.Update(id, datamodels.User{ - Username: newUsername, - }) -} - -// Create inserts a new User, -// the userPassword is the client-typed password -// it will be hashed before the insertion to our repository. -func (s *userService) Create(userPassword string, user datamodels.User) (datamodels.User, error) { - if user.ID > 0 || userPassword == "" || user.Firstname == "" || user.Username == "" { - return datamodels.User{}, errors.New("unable to create this user") - } - - hashed, err := datamodels.GeneratePassword(userPassword) - if err != nil { - return datamodels.User{}, err - } - user.HashedPassword = hashed - - return s.repo.InsertOrUpdate(user) -} - -// DeleteByID deletes a user by its id. -// -// Returns true if deleted otherwise false. -func (s *userService) DeleteByID(id int64) bool { - return s.repo.Delete(func(m datamodels.User) bool { - return m.ID == id - }, 1) -} diff --git a/_examples/mvc/login/web/controllers/user_controller.go b/_examples/mvc/login/web/controllers/user_controller.go deleted file mode 100644 index 56686619..00000000 --- a/_examples/mvc/login/web/controllers/user_controller.go +++ /dev/null @@ -1,170 +0,0 @@ -// file: controllers/user_controller.go - -package controllers - -import ( - "github.com/kataras/iris/v12/_examples/mvc/login/datamodels" - "github.com/kataras/iris/v12/_examples/mvc/login/services" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" - "github.com/kataras/iris/v12/sessions" -) - -// UserController is our /user controller. -// UserController is responsible to handle the following requests: -// GET /user/register -// POST /user/register -// GET /user/login -// POST /user/login -// GET /user/me -// All HTTP Methods /user/logout -type UserController struct { - // context is auto-binded by Iris on each request, - // remember that on each incoming request iris creates a new UserController each time, - // so all fields are request-scoped by-default, only dependency injection is able to set - // custom fields like the Service which is the same for all requests (static binding) - // and the Session which depends on the current context (dynamic binding). - Ctx iris.Context - - // Our UserService, it's an interface which - // is binded from the main application. - Service services.UserService - - // Session, binded using dependency injection from the main.go. - Session *sessions.Session -} - -const userIDKey = "UserID" - -func (c *UserController) getCurrentUserID() int64 { - userID := c.Session.GetInt64Default(userIDKey, 0) - return userID -} - -func (c *UserController) isLoggedIn() bool { - return c.getCurrentUserID() > 0 -} - -func (c *UserController) logout() { - c.Session.Destroy() -} - -var registerStaticView = mvc.View{ - Name: "user/register.html", - Data: iris.Map{"Title": "User Registration"}, -} - -// GetRegister handles GET: http://localhost:8080/user/register. -func (c *UserController) GetRegister() mvc.Result { - if c.isLoggedIn() { - c.logout() - } - - return registerStaticView -} - -// PostRegister handles POST: http://localhost:8080/user/register. -func (c *UserController) PostRegister() mvc.Result { - // get firstname, username and password from the form. - var ( - firstname = c.Ctx.FormValue("firstname") - username = c.Ctx.FormValue("username") - password = c.Ctx.FormValue("password") - ) - - // create the new user, the password will be hashed by the service. - u, err := c.Service.Create(password, datamodels.User{ - Username: username, - Firstname: firstname, - }) - - // set the user's id to this session even if err != nil, - // the zero id doesn't matters because .getCurrentUserID() checks for that. - // If err != nil then it will be shown, see below on mvc.Response.Err: err. - c.Session.Set(userIDKey, u.ID) - - return mvc.Response{ - // if not nil then this error will be shown instead. - Err: err, - // redirect to /user/me. - Path: "/user/me", - // When redirecting from POST to GET request you -should- use this HTTP status code, - // however there're some (complicated) alternatives if you - // search online or even the HTTP RFC. - // Status "See Other" RFC 7231, however iris can automatically fix that - // but it's good to know you can set a custom code; - // Code: 303, - } -} - -var loginStaticView = mvc.View{ - Name: "user/login.html", - Data: iris.Map{"Title": "User Login"}, -} - -// GetLogin handles GET: http://localhost:8080/user/login. -func (c *UserController) GetLogin() mvc.Result { - if c.isLoggedIn() { - // if it's already logged in then destroy the previous session. - c.logout() - } - - return loginStaticView -} - -// PostLogin handles POST: http://localhost:8080/user/register. -func (c *UserController) PostLogin() mvc.Result { - var ( - username = c.Ctx.FormValue("username") - password = c.Ctx.FormValue("password") - ) - - u, found := c.Service.GetByUsernameAndPassword(username, password) - - if !found { - return mvc.Response{ - Path: "/user/register", - } - } - - c.Session.Set(userIDKey, u.ID) - - return mvc.Response{ - Path: "/user/me", - } -} - -// GetMe handles GET: http://localhost:8080/user/me. -func (c *UserController) GetMe() mvc.Result { - if !c.isLoggedIn() { - // if it's not logged in then redirect user to the login page. - return mvc.Response{Path: "/user/login"} - } - - u, found := c.Service.GetByID(c.getCurrentUserID()) - if !found { - // if the session exists but for some reason the user doesn't exist in the "database" - // then logout and re-execute the function, it will redirect the client to the - // /user/login page. - c.logout() - return c.GetMe() - } - - return mvc.View{ - Name: "user/me.html", - Data: iris.Map{ - "Title": "Profile of " + u.Username, - "User": u, - }, - } -} - -// AnyLogout handles All/Any HTTP Methods for: http://localhost:8080/user/logout. -func (c *UserController) AnyLogout() { - if c.isLoggedIn() { - c.logout() - } - - c.Ctx.Redirect("/user/login") -} diff --git a/_examples/mvc/login/web/controllers/users_controller.go b/_examples/mvc/login/web/controllers/users_controller.go deleted file mode 100644 index 02715c48..00000000 --- a/_examples/mvc/login/web/controllers/users_controller.go +++ /dev/null @@ -1,88 +0,0 @@ -package controllers - -import ( - "github.com/kataras/iris/v12/_examples/mvc/login/datamodels" - "github.com/kataras/iris/v12/_examples/mvc/login/services" - - "github.com/kataras/iris/v12" -) - -// UsersController is our /users API controller. -// GET /users | get all -// GET /users/{id:int64} | get by id -// PUT /users/{id:int64} | update by id -// DELETE /users/{id:int64} | delete by id -// Requires basic authentication. -type UsersController struct { - // Optionally: context is auto-binded by Iris on each request, - // remember that on each incoming request iris creates a new UserController each time, - // so all fields are request-scoped by-default, only dependency injection is able to set - // custom fields like the Service which is the same for all requests (static binding). - Ctx iris.Context - - // Our UserService, it's an interface which - // is binded from the main application. - Service services.UserService -} - -// Get returns list of the users. -// Demo: -// curl -i -u admin:password http://localhost:8080/users -// -// The correct way if you have sensitive data: -// func (c *UsersController) Get() (results []viewmodels.User) { -// data := c.Service.GetAll() -// -// for _, user := range data { -// results = append(results, viewmodels.User{user}) -// } -// return -// } -// otherwise just return the datamodels. -func (c *UsersController) Get() (results []datamodels.User) { - return c.Service.GetAll() -} - -// GetBy returns a user. -// Demo: -// curl -i -u admin:password http://localhost:8080/users/1 -func (c *UsersController) GetBy(id int64) (user datamodels.User, found bool) { - u, found := c.Service.GetByID(id) - if !found { - // this message will be binded to the - // main.go -> app.OnAnyErrorCode -> NotFound -> shared/error.html -> .Message text. - c.Ctx.Values().Set("message", "User couldn't be found!") - } - return u, found // it will throw/emit 404 if found == false. -} - -// PutBy updates a user. -// Demo: -// curl -i -X PUT -u admin:password -F "username=kataras" -// -F "password=rawPasswordIsNotSafeIfOrNotHTTPs_You_Should_Use_A_client_side_lib_for_hash_as_well" -// http://localhost:8080/users/1 -func (c *UsersController) PutBy(id int64) (datamodels.User, error) { - // username := c.Ctx.FormValue("username") - // password := c.Ctx.FormValue("password") - u := datamodels.User{} - if err := c.Ctx.ReadForm(&u); err != nil { - return u, err - } - - return c.Service.Update(id, u) -} - -// DeleteBy deletes a user. -// Demo: -// curl -i -X DELETE -u admin:password http://localhost:8080/users/1 -func (c *UsersController) DeleteBy(id int64) interface{} { - wasDel := c.Service.DeleteByID(id) - if wasDel { - // return the deleted user's ID - return map[string]interface{}{"deleted": id} - } - // right here we can see that a method function - // can return any of those two types(map or int), - // we don't have to specify the return type to a specific type. - return iris.StatusBadRequest // same as 400. -} diff --git a/_examples/mvc/login/web/middleware/basicauth.go b/_examples/mvc/login/web/middleware/basicauth.go deleted file mode 100644 index eaf085ba..00000000 --- a/_examples/mvc/login/web/middleware/basicauth.go +++ /dev/null @@ -1,12 +0,0 @@ -// file: middleware/basicauth.go - -package middleware - -import "github.com/kataras/iris/v12/middleware/basicauth" - -// BasicAuth middleware sample. -var BasicAuth = basicauth.New(basicauth.Config{ - Users: map[string]string{ - "admin": "password", - }, -}) diff --git a/_examples/mvc/login/web/public/css/site.css b/_examples/mvc/login/web/public/css/site.css deleted file mode 100644 index d6dc3b10..00000000 --- a/_examples/mvc/login/web/public/css/site.css +++ /dev/null @@ -1,61 +0,0 @@ -/* Bordered form */ -form { - border: 3px solid #f1f1f1; -} - -/* Full-width inputs */ -input[type=text], input[type=password] { - width: 100%; - padding: 12px 20px; - margin: 8px 0; - display: inline-block; - border: 1px solid #ccc; - box-sizing: border-box; -} - -/* Set a style for all buttons */ -button { - background-color: #4CAF50; - color: white; - padding: 14px 20px; - margin: 8px 0; - border: none; - cursor: pointer; - width: 100%; -} - -/* Add a hover effect for buttons */ -button:hover { - opacity: 0.8; -} - -/* Extra style for the cancel button (red) */ -.cancelbtn { - width: auto; - padding: 10px 18px; - background-color: #f44336; -} - -/* Center the container */ - -/* Add padding to containers */ -.container { - padding: 16px; -} - -/* The "Forgot password" text */ -span.psw { - float: right; - padding-top: 16px; -} - -/* Change styles for span and cancel button on extra small screens */ -@media screen and (max-width: 300px) { - span.psw { - display: block; - float: none; - } - .cancelbtn { - width: 100%; - } -} \ No newline at end of file diff --git a/_examples/mvc/login/web/viewmodels/README.md b/_examples/mvc/login/web/viewmodels/README.md deleted file mode 100644 index 4cd55577..00000000 --- a/_examples/mvc/login/web/viewmodels/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# View Models - -There should be the view models, the structure that the client will be able to see. - -Example: - -```go -import ( - "github.com/kataras/iris/v12/_examples/mvc/login/datamodels" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" -) - -type User struct { - datamodels.User -} - -func (m User) IsValid() bool { - /* do some checks and return true if it's valid... */ - return m.ID > 0 -} -``` - -Iris is able to convert any custom data Structure into an HTTP Response Dispatcher, -so theoretically, something like the following is permitted if it's really necessary; - -```go -// Dispatch completes the `kataras/iris/mvc#Result` interface. -// Sends a `User` as a controlled http response. -// If its ID is zero or less then it returns a 404 not found error -// else it returns its json representation, -// (just like the controller's functions do for custom types by default). -// -// Don't overdo it, the application's logic should not be here. -// It's just one more step of validation before the response, -// simple checks can be added here. -// -// It's just a showcase, -// imagine the potentials this feature gives when designing a bigger application. -// -// This is called where the return value from a controller's method functions -// is type of `User`. -// For example the `controllers/user_controller.go#GetBy`. -func (m User) Dispatch(ctx iris.Context) { - if !m.IsValid() { - ctx.NotFound() - return - } - ctx.JSON(m, context.JSON{Indent: " "}) -} -``` - -However, we will use the "datamodels" as the only one models package because -User structure doesn't contain any sensitive data, clients are able to see all of its fields -and we don't need any extra functionality or validation inside it. \ No newline at end of file diff --git a/_examples/mvc/login/web/views/shared/error.html b/_examples/mvc/login/web/views/shared/error.html deleted file mode 100644 index 3847119d..00000000 --- a/_examples/mvc/login/web/views/shared/error.html +++ /dev/null @@ -1,15 +0,0 @@ -

Error.

-

An error occurred while processing your request.

- -

{{.Message}}

- - \ No newline at end of file diff --git a/_examples/mvc/login/web/views/shared/layout.html b/_examples/mvc/login/web/views/shared/layout.html deleted file mode 100644 index 75e14fb0..00000000 --- a/_examples/mvc/login/web/views/shared/layout.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - {{.Title}} - - - - - {{ yield }} - - - \ No newline at end of file diff --git a/_examples/mvc/login/web/views/user/login.html b/_examples/mvc/login/web/views/user/login.html deleted file mode 100644 index e84528a6..00000000 --- a/_examples/mvc/login/web/views/user/login.html +++ /dev/null @@ -1,11 +0,0 @@ -
-
- - - - - - - -
-
\ No newline at end of file diff --git a/_examples/mvc/login/web/views/user/me.html b/_examples/mvc/login/web/views/user/me.html deleted file mode 100644 index d15da930..00000000 --- a/_examples/mvc/login/web/views/user/me.html +++ /dev/null @@ -1,3 +0,0 @@ -

- Welcome back {{.User.Firstname}}! -

\ No newline at end of file diff --git a/_examples/mvc/login/web/views/user/register.html b/_examples/mvc/login/web/views/user/register.html deleted file mode 100644 index e46cc54d..00000000 --- a/_examples/mvc/login/web/views/user/register.html +++ /dev/null @@ -1,14 +0,0 @@ -
-
- - - - - - - - - - -
-
\ No newline at end of file diff --git a/_examples/mvc/middleware/main.go b/_examples/mvc/middleware/main.go deleted file mode 100644 index 6cd4e53c..00000000 --- a/_examples/mvc/middleware/main.go +++ /dev/null @@ -1,47 +0,0 @@ -// Package main shows how you can add middleware to an mvc Application, simply -// by using its `Router` which is a sub router(an iris.Party) of the main iris app. -package main - -import ( - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/cache" - "github.com/kataras/iris/v12/mvc" -) - -var cacheHandler = cache.Handler(10 * time.Second) - -func main() { - app := iris.New() - app.Logger().SetLevel("debug") - - mvc.Configure(app, configure) - - // http://localhost:8080 - // http://localhost:8080/other - // - // refresh every 10 seconds and you'll see different time output. - app.Listen(":8080") -} - -func configure(m *mvc.Application) { - m.Router.Use(cacheHandler) - m.Handle(&exampleController{ - timeFormat: "Mon, Jan 02 2006 15:04:05", - }) -} - -type exampleController struct { - timeFormat string -} - -func (c *exampleController) Get() string { - now := time.Now().Format(c.timeFormat) - return "last time executed without cache: " + now -} - -func (c *exampleController) GetOther() string { - now := time.Now().Format(c.timeFormat) - return "/other: " + now -} diff --git a/_examples/mvc/middleware/per-method/main.go b/_examples/mvc/middleware/per-method/main.go deleted file mode 100644 index f4e13560..00000000 --- a/_examples/mvc/middleware/per-method/main.go +++ /dev/null @@ -1,105 +0,0 @@ -/* -If you want to use it as middleware for the entire controller -you can use its router which is just a sub router to add it as you normally do with standard API: - -I'll show you 4 different methods for adding a middleware into an mvc application, -all of those 4 do exactly the same thing, select what you prefer, -I prefer the last code-snippet when I need the middleware to be registered somewhere -else as well, otherwise I am going with the first one: - -```go -// 1 -mvc.Configure(app.Party("/user"), func(m *mvc.Application) { - m.Router.Use(cache.Handler(10*time.Second)) -}) -``` - -```go -// 2 -// same: -userRouter := app.Party("/user") -userRouter.Use(cache.Handler(10*time.Second)) -mvc.Configure(userRouter, ...) -``` - -```go -// 3 -// same: -userRouter := app.Party("/user", cache.Handler(10*time.Second)) -mvc.Configure(userRouter, ...) -``` - -```go -// 4 -// same: -app.PartyFunc("/user", func(r iris.Party){ - r.Use(cache.Handler(10*time.Second)) - mvc.Configure(r, ...) -}) -``` - -If you want to use a middleware for a single route, -for a single controller's method that is already registered by the engine -and not by custom `Handle` (which you can add -the middleware there on the last parameter) and it's not depend on the `Next Handler` to do its job -then you just call it on the method: - -```go -var myMiddleware := myMiddleware.New(...) // this should return an iris/context.Handler - -type UserController struct{} -func (c *UserController) GetSomething(ctx iris.Context) { - // ctx.Proceed checks if myMiddleware called `ctx.Next()` - // inside it and returns true if so, otherwise false. - nextCalled := ctx.Proceed(myMiddleware) - if !nextCalled { - return - } - - // else do the job here, it's allowed -} -``` - -And last, if you want to add a middleware on a specific method -and it depends on the next and the whole chain then you have to do it -using the `AfterActivation` like the example below: -*/ -package main - -import ( - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/cache" - "github.com/kataras/iris/v12/mvc" -) - -var cacheHandler = cache.Handler(10 * time.Second) - -func main() { - app := iris.New() - // You don't have to use .Configure if you do it all in the main func - // mvc.Configure and mvc.New(...).Configure() are just helpers to split - // your code better, here we use the simplest form: - m := mvc.New(app) - m.Handle(&exampleController{}) - - app.Listen(":8080") -} - -type exampleController struct{} - -func (c *exampleController) AfterActivation(a mvc.AfterActivation) { - // select the route based on the method name you want to - // modify. - index := a.GetRoute("Get") - // just prepend the handler(s) as middleware(s) you want to use. - // or append for "done" handlers. - index.Handlers = append([]iris.Handler{cacheHandler}, index.Handlers...) -} - -func (c *exampleController) Get() string { - // refresh every 10 seconds and you will see different time output. - now := time.Now().Format("Mon, Jan 02 2006 15:04:05") - return "last time executed without cache: " + now -} diff --git a/_examples/mvc/middleware/without-ctx-next/main.go b/_examples/mvc/middleware/without-ctx-next/main.go deleted file mode 100644 index 1473880e..00000000 --- a/_examples/mvc/middleware/without-ctx-next/main.go +++ /dev/null @@ -1,48 +0,0 @@ -/*Package main shows how to add done handlers in an MVC application without -the necessity of `ctx.Next()` inside the controller's methods. - -When we want the `Done` handlers of that specific mvc app's `Party` -to be executed but we don't want to add `ctx.Next()` on the `exampleController#EndRequest`*/ -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" -) - -func main() { - app := iris.New() - app.Get("/", func(ctx iris.Context) { ctx.Redirect("/example") }) - - exampleRouter := app.Party("/example") - { - exampleRouter.SetExecutionRules(iris.ExecutionRules{ - Done: iris.ExecutionOptions{Force: true}, - }) - - exampleRouter.Done(doneHandler) - - m := mvc.New(exampleRouter) - m.Handle(&exampleController{}) - } - - app.Listen(":8080") -} - -func doneHandler(ctx iris.Context) { - ctx.WriteString("\nFrom Done Handler") -} - -type exampleController struct{} - -func (c *exampleController) Get() string { - return "From Main Handler" - // Note that here we don't binding the `Context`, and we don't call its `Next()` - // function in order to call the `doneHandler`, - // this is done automatically for us because we changed the execution rules with the - // `SetExecutionRules`. - // - // Therefore the final output is: - // From Main Handler - // From Done Handler -} diff --git a/_examples/mvc/overview/Dockerfile b/_examples/mvc/overview/Dockerfile deleted file mode 100644 index 16c9113d..00000000 --- a/_examples/mvc/overview/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -# docker build -t app . -# docker run --rm -it -p 8080:8080 app:latest -FROM golang:latest AS builder -RUN apt-get update -ENV GO111MODULE=on \ - CGO_ENABLED=0 \ - GOOS=linux \ - GOARCH=amd64 -WORKDIR /go/src/app -COPY go.mod . -RUN go mod download -COPY . . -RUN go install - -FROM scratch -COPY --from=builder /go/bin/app . -ENTRYPOINT ["./app"] \ No newline at end of file diff --git a/_examples/mvc/overview/README.md b/_examples/mvc/overview/README.md deleted file mode 100644 index e58e6ff7..00000000 --- a/_examples/mvc/overview/README.md +++ /dev/null @@ -1,378 +0,0 @@ -# Quick start - -The following guide is just a simple example of usage of some of the **Iris MVC** features. You are not limited to that data structure or code flow. - -Create a folder, let's assume its path is `app`. The structure should look like that: - -``` -│ main.go -│ go.mod -│ go.sum -└───environment -│ environment.go -└───model -│ request.go -│ response.go -└───database -│ database.go -│ mysql.go -│ sqlite.go -└───service -│ greet_service.go -└───controller - greet_controller.go -``` - -Navigate to that `app` folder and execute the following command: - -```sh -$ go init app -$ go get -u github.com/kataras/iris/v12@master -# or @latest for the latest official release. -``` - -## Environment - -Let's start by defining the available environments that our web-application can behave on. - -We'll just work on two available environments, the "development" and the "production", as they define the two most common scenarios. The `ReadEnv` will read from the `Env` type of a system's environment variable (see `main.go` in the end of the page). - -Create a `environment/environment.go` file and put the following contents: - -```go -package environment - -import ( - "os" - "strings" -) - -const ( - PROD Env = "production" - DEV Env = "development" -) - -type Env string - -func (e Env) String() string { - return string(e) -} - -func ReadEnv(key string, def Env) Env { - v := Getenv(key, def.String()) - if v == "" { - return def - } - - env := Env(strings.ToLower(v)) - switch env { - case PROD, DEV: // allowed. - default: - panic("unexpected environment " + v) - } - - return env -} - -func Getenv(key string, def string) string { - if v := os.Getenv(key); v != "" { - return v - } - - return def -} -``` - -## Database - -We will use two database management systems, the `MySQL` and the `SQLite`. The first one for "production" use and the other for "development". - -Create a `database/database.go` file and copy-paste the following: - -```go -package database - -import "app/environment" - -type DB interface { - Exec(q string) error -} - -func NewDB(env environment.Env) DB { - switch env { - case environment.PROD: - return &mysql{} - case environment.DEV: - return &sqlite{} - default: - panic("unknown environment") - } -} -``` - -Let's simulate our MySQL and SQLite `DB` instances. Create a `database/mysql.go` file which looks like the following one: - -```go -package database - -import "fmt" - -type mysql struct{} - -func (db *mysql) Exec(q string) error { - return fmt.Errorf("mysql: not implemented <%s>", q) -} -``` - -And a `database/sqlite.go` file. - -```go -package database - -type sqlite struct{} - -func (db *sqlite) Exec(q string) error { return nil } -``` - -The `DB` depends on the `Environment. - -> A practical and operational database example, including Docker images, can be found at the following guide: https://github.com/kataras/iris/tree/master/_examples/database/mysql - -## Service - -We'll need a service that will communicate with a database instance in behalf of our Controller(s). - -In our case we will only need a single service, the Greet Service. - -For the sake of the example, let's use two implementations of a greet service based on the `Environment`. The `GreetService` interface contains a single method of `Say(input string) (output string, err error)`. Create a `./service/greet_service.go` file and write the following code: - -```go -package service - -import ( - "fmt" - - "app/database" - "app/environment" -) - -// GreetService example service. -type GreetService interface { - Say(input string) (string, error) -} - -// NewGreetService returns a service backed with a "db" based on "env". -func NewGreetService(env environment.Env, db database.DB) GreetService { - service := &greeter{db: db, prefix: "Hello"} - - switch env { - case environment.PROD: - return service - case environment.DEV: - return &greeterWithLogging{service} - default: - panic("unknown environment") - } -} - -type greeter struct { - prefix string - db database.DB -} - -func (s *greeter) Say(input string) (string, error) { - if err := s.db.Exec("simulate a query..."); err != nil { - return "", err - } - - result := s.prefix + " " + input - return result, nil -} - -type greeterWithLogging struct { - *greeter -} - -func (s *greeterWithLogging) Say(input string) (string, error) { - result, err := s.greeter.Say(input) - fmt.Printf("result: %s\nerror: %v\n", result, err) - return result, err -} - -``` - -The `greeter` will be used on "production" and the `greeterWithLogging` on "development". The `GreetService` depends on the `Environment` and the `DB`. - -## Models - -Continue by creating our HTTP request and response models. - -Create a `model/request.go` file and copy-paste the following code: - -```go -package model - -type Request struct { - Name string `url:"name"` -} -``` - -Same for the `model/response.go` file. - -```go -package model - -type Response struct { - Message string `json:"msg"` -} -``` - -The server will accept a URL Query Parameter of `name` (e.g. `/greet?name=kataras`) and will reply back with a JSON message. - -## Controller - -MVC Controllers are responsible for controlling the flow of the application execution. When you make a request (means request a page) to MVC Application, a controller is responsible for returning the response to that request. - -We will only need the `GreetController` for our mini web-application. Create a file at `controller/greet_controller.go` which looks like that: - -```go -package controller - -import ( - "app/model" - "app/service" -) - -type GreetController struct { - Service service.GreetService - // Ctx iris.Context -} - -func (c *GreetController) Get(req model.Request) (model.Response, error) { - message, err := c.Service.Say(req.Name) - if err != nil { - return model.Response{}, err - } - - return model.Response{Message: message}, nil -} -``` - -The `GreetController` depends on the `GreetService`. It serves the `GET: /greet` index path through its `Get` method. The `Get` method accepts a `model.Request` which contains a single field name of `Name` which will be extracted from the `URL Query Parameter 'name'` (because it's a `GET` requst and its `url:"name"` struct field). - -## Wrap up - -```sh - +-------------------+ - | Env (DEV, PROD) | - +---------+---------+ - | | | - | | | - | | | - DEV | | | PROD --------------------+---------------------+ | +----------------------+------------------- - | | | - | | | - +---+-----+ +----------------v------------------+ +----+----+ - | sqlite | | NewDB(Env) DB | | mysql | - +---+-----+ +----------------+---+--------------+ +----+----+ - | | | | - | | | | - | | | | - +--------------+-----+ +-------------------v---v-----------------+ +----+------+ - | greeterWithLogging | | NewGreetService(Env, DB) GreetService | | greeter | - +--------------+-----+ +---------------------------+-------------+ +----+------+ - | | | - | | | - | +-----------------------------------------+ | - | | GreetController | | | - | | | | | - | | - Service GreetService <-- | | - | | | | - | +-------------------+---------------------+ | - | | | - | | | - | | | - | +-----------+-----------+ | - | | HTTP Request | | - | +-----------------------+ | - | | /greet?name=kataras | | - | +-----------+-----------+ | - | | | -+------------------+--------+ +------------+------------+ +-------+------------------+ -| model.Response (JSON) | | Response (JSON, error) | | Bad Request | -+---------------------------+ +-------------------------+ +--------------------------+ -| { | | mysql: not implemented | -| "msg": "Hello kataras" | +--------------------------+ -| } | -+---------------------------+ -``` - -Now it's the time to wrap all the above into our `main.go` file. Copy-paste the following code: - -```go -package main - -import ( - "app/controller" - "app/database" - "app/environment" - "app/service" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" -) - -func main() { - app := iris.New() - app.Get("/ping", pong).Describe("healthcheck") - - mvc.Configure(app.Party("/greet"), setup) - - // http://localhost:8080/greet?name=kataras - app.Listen(":8080", iris.WithLogLevel("debug")) -} - -func pong(ctx iris.Context) { - ctx.WriteString("pong") -} - -func setup(app *mvc.Application) { - // Register Dependencies. - app.Register( - environment.DEV, // DEV, PROD - database.NewDB, // sqlite, mysql - service.NewGreetService, // greeterWithLogging, greeter - ) - - // Register Controllers. - app.Handle(new(controller.GreetController)) -} -``` - -The `mvc.Application.Register` method registers one more dependencies, dependencies can depend on previously registered dependencies too. Thats the reason we pass, first, the `Environment(DEV)`, then the `NewDB` which depends on that `Environment`, following by the `NewGreetService` function which depends on both the `Environment(DEV)` and the `DB`. - -The `mvc.Application.Handle` registers a new controller, which depends on the `GreetService`, for the targeted sub-router of `Party("/greet")`. - -## Run - -Install [Go](https://golang.org/dl) and run the application with: - -```sh -go run main.go -``` - -
Docker - -Download the [Dockerfile](https://raw.githubusercontent.com/kataras/iris/9b93c0dbb491dcedf49c91e89ca13bab884d116f/_examples/mvc/overview/Dockerfile) and [docker-compose.yml](https://raw.githubusercontent.com/kataras/iris/9b93c0dbb491dcedf49c91e89ca13bab884d116f/_examples/mvc/overview/docker-compose.yml) files to the `app` folder. - -Install [Docker](https://www.docker.com/) and execute the following command: - -```sh -$ docker-compose up -``` -
- -Visit http://localhost:8080?name=kataras. - -Optionally, replace the `main.go`'s `app.Register(environment.DEV` with `environment.PROD`, restart the application and refresh. You will see that a new database (`sqlite`) and another service of (`greeterWithLogging`) will be binded to the `GreetController`. With **a single change** you achieve to completety change the result. diff --git a/_examples/mvc/overview/controller/greet_controller.go b/_examples/mvc/overview/controller/greet_controller.go deleted file mode 100644 index 737bd537..00000000 --- a/_examples/mvc/overview/controller/greet_controller.go +++ /dev/null @@ -1,23 +0,0 @@ -package controller - -import ( - "app/model" - "app/service" -) - -// GreetController handles the index. -type GreetController struct { - Service service.GreetService - // Ctx iris.Context -} - -// Get serves [GET] /. -// Query: name -func (c *GreetController) Get(req model.Request) (model.Response, error) { - message, err := c.Service.Say(req.Name) - if err != nil { - return model.Response{}, err - } - - return model.Response{Message: message}, nil -} diff --git a/_examples/mvc/overview/database/database.go b/_examples/mvc/overview/database/database.go deleted file mode 100644 index c99e96c6..00000000 --- a/_examples/mvc/overview/database/database.go +++ /dev/null @@ -1,20 +0,0 @@ -package database - -import "app/environment" - -// DB example database interface. -type DB interface { - Exec(q string) error -} - -// NewDB returns a database based on "env". -func NewDB(env environment.Env) DB { - switch env { - case environment.PROD: - return &mysql{} - case environment.DEV: - return &sqlite{} - default: - panic("unknown environment") - } -} diff --git a/_examples/mvc/overview/database/mysql.go b/_examples/mvc/overview/database/mysql.go deleted file mode 100644 index 5d14da05..00000000 --- a/_examples/mvc/overview/database/mysql.go +++ /dev/null @@ -1,10 +0,0 @@ -package database - -import "fmt" - -type mysql struct{} - -func (db *mysql) Exec(q string) error { - // simulate an error response. - return fmt.Errorf("mysql: not implemented <%s>", q) -} diff --git a/_examples/mvc/overview/database/sqlite.go b/_examples/mvc/overview/database/sqlite.go deleted file mode 100644 index 956a82fd..00000000 --- a/_examples/mvc/overview/database/sqlite.go +++ /dev/null @@ -1,5 +0,0 @@ -package database - -type sqlite struct{} - -func (db *sqlite) Exec(q string) error { return nil } diff --git a/_examples/mvc/overview/docker-compose.yml b/_examples/mvc/overview/docker-compose.yml deleted file mode 100644 index db906506..00000000 --- a/_examples/mvc/overview/docker-compose.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: '3.1' - -services: - app: - build: . - ports: - - 8080:8080 - environment: - PORT: 8080 - ENVIRONMENT: development - restart: on-failure - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8080/ping"] - interval: 30s - timeout: 10s - retries: 5 diff --git a/_examples/mvc/overview/environment/environment.go b/_examples/mvc/overview/environment/environment.go deleted file mode 100644 index 519a7cc9..00000000 --- a/_examples/mvc/overview/environment/environment.go +++ /dev/null @@ -1,50 +0,0 @@ -package environment - -import ( - "os" - "strings" -) - -// Available environments example. -const ( - PROD Env = "production" - DEV Env = "development" -) - -// Env is the environment type. -type Env string - -// String just returns the string representation of the Env. -func (e Env) String() string { - return string(e) -} - -// ReadEnv returns the environment of the system environment variable of "key". -// Returns the "def" if not found. -// Reports a panic message if the environment variable found -// but the Env is unknown. -func ReadEnv(key string, def Env) Env { - v := Getenv(key, def.String()) - if v == "" { - return def - } - - env := Env(strings.ToLower(v)) - switch env { - case PROD, DEV: // allowed. - default: - panic("unexpected environment " + v) - } - - return env -} - -// Getenv returns the value of a system environment variable "key". -// Defaults to "def" if not found. -func Getenv(key string, def string) string { - if v := os.Getenv(key); v != "" { - return v - } - - return def -} diff --git a/_examples/mvc/overview/go.mod b/_examples/mvc/overview/go.mod deleted file mode 100644 index cb0cb9cd..00000000 --- a/_examples/mvc/overview/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module app - -go 1.15 - -require github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd diff --git a/_examples/mvc/overview/main.go b/_examples/mvc/overview/main.go deleted file mode 100644 index 7476d9b7..00000000 --- a/_examples/mvc/overview/main.go +++ /dev/null @@ -1,85 +0,0 @@ -package main - -import ( - "app/controller" - "app/database" - "app/environment" - "app/service" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" -) - -func main() { - app := iris.New() - app.Get("/ping", pong).Describe("healthcheck") - - mvc.Configure(app.Party("/greet"), setup) - - // http://localhost:8080/greet?name=kataras - addr := ":" + environment.Getenv("PORT", "8080") - app.Listen(addr, iris.WithLogLevel("debug")) -} - -func pong(ctx iris.Context) { - ctx.WriteString("pong") -} - -/* - +-------------------+ - | Env (DEV, PROD) | - +---------+---------+ - | | | - | | | - | | | - DEV | | | PROD --------------------+---------------------+ | +----------------------+------------------- - | | | - | | | - +---+-----+ +----------------v------------------+ +----+----+ - | sqlite | | NewDB(Env) DB | | mysql | - +---+-----+ +----------------+---+--------------+ +----+----+ - | | | | - | | | | - | | | | - +--------------+-----+ +-------------------v---v-----------------+ +----+------+ - | greeterWithLogging | | NewGreetService(Env, DB) GreetService | | greeter | - +--------------+-----+ +---------------------------+-------------+ +----+------+ - | | | - | | | - | +-----------------------------------------+ | - | | GreetController | | | - | | | | | - | | - Service GreetService <-- | | - | | | | - | +-------------------+---------------------+ | - | | | - | | | - | | | - | +-----------+-----------+ | - | | HTTP Request | | - | +-----------------------+ | - | | /greet?name=kataras | | - | +-----------+-----------+ | - | | | -+------------------+--------+ +------------+------------+ +-------+------------------+ -| model.Response (JSON) | | Response (JSON, error) | | Bad Request | -+---------------------------+ +-------------------------+ +--------------------------+ -| { | | mysql: not implemented | -| "msg": "Hello kataras" | +--------------------------+ -| } | -+---------------------------+ -*/ -func setup(app *mvc.Application) { - // Register Dependencies. - // Tip: A dependency can depend on other dependencies too. - env := environment.ReadEnv("ENVIRONMENT", environment.DEV) - app.Register( - env, // DEV, PROD - database.NewDB, // sqlite, mysql - service.NewGreetService, // greeterWithLogging, greeter - ) - - // Register Controllers. - app.Handle(new(controller.GreetController)) -} diff --git a/_examples/mvc/overview/model/request.go b/_examples/mvc/overview/model/request.go deleted file mode 100644 index 03a826ed..00000000 --- a/_examples/mvc/overview/model/request.go +++ /dev/null @@ -1,6 +0,0 @@ -package model - -// Request example incoming request. -type Request struct { - Name string `json:"name" url:"name"` -} diff --git a/_examples/mvc/overview/model/response.go b/_examples/mvc/overview/model/response.go deleted file mode 100644 index 18e7855f..00000000 --- a/_examples/mvc/overview/model/response.go +++ /dev/null @@ -1,6 +0,0 @@ -package model - -// Response example server's response. -type Response struct { - Message string `json:"msg"` -} diff --git a/_examples/mvc/overview/service/greet_service.go b/_examples/mvc/overview/service/greet_service.go deleted file mode 100644 index c0d493d8..00000000 --- a/_examples/mvc/overview/service/greet_service.go +++ /dev/null @@ -1,51 +0,0 @@ -package service - -import ( - "fmt" - - "app/database" - "app/environment" -) - -// GreetService example service. -type GreetService interface { - Say(input string) (string, error) -} - -// NewGreetService returns a service backed with a "db" based on "env". -func NewGreetService(env environment.Env, db database.DB) GreetService { - service := &greeter{db: db, prefix: "Hello"} - - switch env { - case environment.PROD: - return service - case environment.DEV: - return &greeterWithLogging{service} - default: - panic("unknown environment") - } -} - -type greeter struct { - prefix string - db database.DB -} - -func (s *greeter) Say(input string) (string, error) { - if err := s.db.Exec("simulate a query..."); err != nil { - return "", err - } - - result := s.prefix + " " + input - return result, nil -} - -type greeterWithLogging struct { - *greeter -} - -func (s *greeterWithLogging) Say(input string) (string, error) { - result, err := s.greeter.Say(input) - fmt.Printf("result: %s\nerror: %v\n", result, err) - return result, err -} diff --git a/_examples/mvc/regexp/main.go b/_examples/mvc/regexp/main.go deleted file mode 100644 index a68fdf26..00000000 --- a/_examples/mvc/regexp/main.go +++ /dev/null @@ -1,49 +0,0 @@ -// Package main shows how to match "/xxx.json" in MVC handler. -package main - -/* -There is no MVC naming pattern for such these things,you can imagine the limitations of that. -Instead you can use the `BeforeActivation` on your controller to add more advanced routing features -(https://github.com/kataras/iris/tree/master/_examples/routing). - -You can also create your own macro, -i.e: /{file:json} or macro function of a specific parameter type i.e: (/{file:string json()}). -Read the routing examples and you will gain a deeper view, there are all covered. -*/ - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" -) - -func main() { - app := iris.New() - - mvcApp := mvc.New(app.Party("/module")) - mvcApp.Handle(new(myController)) - - // http://localhost:8080/module/xxx.json (OK) - // http://localhost:8080/module/xxx.xml (Not Found) - app.Listen(":8080") -} - -type myController struct{} - -func (m *myController) BeforeActivation(b mvc.BeforeActivation) { - // b.Dependencies().Register - // b.Router().Use/UseGlobal/Done // and any standard API call you already know - - // 1-> Method - // 2-> Path - // 3-> The controller's function name to be parsed as handler - // 4-> Any handlers that should run before the HandleJSON - - // "^[a-zA-Z0-9_.-]+.json$)" to validate file-name pattern and json - // or just: ".json$" to validate suffix. - - b.Handle("GET", "/{file:string regexp(^[a-zA-Z0-9_.-]+.json$))}", "HandleJSON" /*optionalMiddleware*/) -} - -func (m *myController) HandleJSON(file string) string { - return "custom serving of json: " + file -} diff --git a/_examples/mvc/repository/datamodels/README.md b/_examples/mvc/repository/datamodels/README.md deleted file mode 100644 index 75a1b75c..00000000 --- a/_examples/mvc/repository/datamodels/README.md +++ /dev/null @@ -1 +0,0 @@ -# Data Model Layer \ No newline at end of file diff --git a/_examples/mvc/repository/datamodels/movie.go b/_examples/mvc/repository/datamodels/movie.go deleted file mode 100644 index 4499ad47..00000000 --- a/_examples/mvc/repository/datamodels/movie.go +++ /dev/null @@ -1,18 +0,0 @@ -// file: datamodels/movie.go - -package datamodels - -// Movie is our sample data structure. -// Keep note that the tags for public-use (for our web app) -// should be kept in other file like "web/viewmodels/movie.go" -// which could wrap by embedding the datamodels.Movie or -// declare new fields instead butwe will use this datamodel -// as the only one Movie model in our application, -// for the sake of simplicty. -type Movie struct { - ID int64 `json:"id"` - Name string `json:"name"` - Year int `json:"year"` - Genre string `json:"genre"` - Poster string `json:"poster"` -} diff --git a/_examples/mvc/repository/datasource/README.md b/_examples/mvc/repository/datasource/README.md deleted file mode 100644 index b5633a54..00000000 --- a/_examples/mvc/repository/datasource/README.md +++ /dev/null @@ -1 +0,0 @@ -# Data Source / Data Store Layer \ No newline at end of file diff --git a/_examples/mvc/repository/datasource/movies.go b/_examples/mvc/repository/datasource/movies.go deleted file mode 100644 index 518245df..00000000 --- a/_examples/mvc/repository/datasource/movies.go +++ /dev/null @@ -1,44 +0,0 @@ -// file: datasource/movies.go - -package datasource - -import "github.com/kataras/iris/v12/_examples/mvc/repository/datamodels" - -// Movies is our imaginary data source. -var Movies = map[int64]datamodels.Movie{ - 1: { - ID: 1, - Name: "Casablanca", - Year: 1942, - Genre: "Romance", - Poster: "https://iris-go.com/images/examples/mvc-movies/1.jpg", - }, - 2: { - ID: 2, - Name: "Gone with the Wind", - Year: 1939, - Genre: "Romance", - Poster: "https://iris-go.com/images/examples/mvc-movies/2.jpg", - }, - 3: { - ID: 3, - Name: "Citizen Kane", - Year: 1941, - Genre: "Mystery", - Poster: "https://iris-go.com/images/examples/mvc-movies/3.jpg", - }, - 4: { - ID: 4, - Name: "The Wizard of Oz", - Year: 1939, - Genre: "Fantasy", - Poster: "https://iris-go.com/images/examples/mvc-movies/4.jpg", - }, - 5: { - ID: 5, - Name: "North by Northwest", - Year: 1959, - Genre: "Thriller", - Poster: "https://iris-go.com/images/examples/mvc-movies/5.jpg", - }, -} diff --git a/_examples/mvc/repository/folder_structure.png b/_examples/mvc/repository/folder_structure.png deleted file mode 100644 index 0029e8f74cb290572df90924dcabc8939fd39ccf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30336 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 AasU7T diff --git a/_examples/mvc/repository/main.go b/_examples/mvc/repository/main.go deleted file mode 100644 index 1cd430b7..00000000 --- a/_examples/mvc/repository/main.go +++ /dev/null @@ -1,53 +0,0 @@ -// file: main.go - -package main - -import ( - "github.com/kataras/iris/v12/_examples/mvc/repository/datasource" - "github.com/kataras/iris/v12/_examples/mvc/repository/repositories" - "github.com/kataras/iris/v12/_examples/mvc/repository/services" - "github.com/kataras/iris/v12/_examples/mvc/repository/web/controllers" - "github.com/kataras/iris/v12/_examples/mvc/repository/web/middleware" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" -) - -func main() { - app := iris.New() - app.Logger().SetLevel("debug") - - // Load the template files. - app.RegisterView(iris.HTML("./web/views", ".html")) - - // Serve our controllers. - mvc.New(app.Party("/hello")).Handle(new(controllers.HelloController)) - // You can also split the code you write to configure an mvc.Application - // using the `mvc.Configure` method, as shown below. - mvc.Configure(app.Party("/movies"), movies) - - // http://localhost:8080/hello - // http://localhost:8080/hello/iris - // http://localhost:8080/movies - // http://localhost:8080/movies/1 - app.Listen(":8080", iris.WithOptimizations) -} - -// note the mvc.Application, it's not iris.Application. -func movies(app *mvc.Application) { - // Add the basic authentication(admin:password) middleware - // for the /movies based requests. - app.Router.Use(middleware.BasicAuth) - - // Create our movie repository with some (memory) data from the datasource. - repo := repositories.NewMovieRepository(datasource.Movies) - // Create our movie service, we will bind it to the movie app's dependencies. - movieService := services.NewMovieService(repo) - app.Register(movieService) - - // serve our movies controller. - // Note that you can serve more than one controller - // you can also create child mvc apps using the `movies.Party(relativePath)` or `movies.Clone(app.Party(...))` - // if you want. - app.Handle(new(controllers.MovieController)) -} diff --git a/_examples/mvc/repository/models/README.md b/_examples/mvc/repository/models/README.md deleted file mode 100644 index 280664ee..00000000 --- a/_examples/mvc/repository/models/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Domain Models - -There should be the domain/business-level models. - -Example: - -```go -import "github.com/kataras/iris/v12/_examples/mvc/repository/datamodels" - -type Movie struct { - datamodels.Movie -} - -func (m Movie) Validate() (Movie, error) { - /* do some checks and return an error if that Movie is not valid */ -} -``` - -However, we will use the "datamodels" as the only one models package because -Movie structure we don't need any extra functionality or validation inside it. \ No newline at end of file diff --git a/_examples/mvc/repository/repositories/README.md b/_examples/mvc/repository/repositories/README.md deleted file mode 100644 index 6de39915..00000000 --- a/_examples/mvc/repository/repositories/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Repositories - -The package which has direct access to the "datasource" and can manipulate data directly. \ No newline at end of file diff --git a/_examples/mvc/repository/repositories/movie_repository.go b/_examples/mvc/repository/repositories/movie_repository.go deleted file mode 100644 index 6a79aeee..00000000 --- a/_examples/mvc/repository/repositories/movie_repository.go +++ /dev/null @@ -1,176 +0,0 @@ -// file: repositories/movie_repository.go - -package repositories - -import ( - "errors" - "sync" - - "github.com/kataras/iris/v12/_examples/mvc/repository/datamodels" -) - -// Query represents the visitor and action queries. -type Query func(datamodels.Movie) bool - -// MovieRepository handles the basic operations of a movie entity/model. -// It's an interface in order to be testable, i.e a memory movie repository or -// a connected to an sql database. -type MovieRepository interface { - Exec(query Query, action Query, limit int, mode int) (ok bool) - - Select(query Query) (movie datamodels.Movie, found bool) - SelectMany(query Query, limit int) (results []datamodels.Movie) - - InsertOrUpdate(movie datamodels.Movie) (updatedMovie datamodels.Movie, err error) - Delete(query Query, limit int) (deleted bool) -} - -// NewMovieRepository returns a new movie memory-based repository, -// the one and only repository type in our example. -func NewMovieRepository(source map[int64]datamodels.Movie) MovieRepository { - return &movieMemoryRepository{source: source} -} - -// movieMemoryRepository is a "MovieRepository" -// which manages the movies using the memory data source (map). -type movieMemoryRepository struct { - source map[int64]datamodels.Movie - mu sync.RWMutex -} - -const ( - // ReadOnlyMode will RLock(read) the data . - ReadOnlyMode = iota - // ReadWriteMode will Lock(read/write) the data. - ReadWriteMode -) - -func (r *movieMemoryRepository) Exec(query Query, action Query, actionLimit int, mode int) (ok bool) { - loops := 0 - - if mode == ReadOnlyMode { - r.mu.RLock() - defer r.mu.RUnlock() - } else { - r.mu.Lock() - defer r.mu.Unlock() - } - - for _, movie := range r.source { - ok = query(movie) - if ok { - if action(movie) { - loops++ - if actionLimit >= loops { - break // break - } - } - } - } - - return -} - -// Select receives a query function -// which is fired for every single movie model inside -// our imaginary data source. -// When that function returns true then it stops the iteration. -// -// It returns the query's return last known "found" value -// and the last known movie model -// to help callers to reduce the LOC. -// -// It's actually a simple but very clever prototype function -// I'm using everywhere since I firstly think of it, -// hope you'll find it very useful as well. -func (r *movieMemoryRepository) Select(query Query) (movie datamodels.Movie, found bool) { - found = r.Exec(query, func(m datamodels.Movie) bool { - movie = m - return true - }, 1, ReadOnlyMode) - - // set an empty datamodels.Movie if not found at all. - if !found { - movie = datamodels.Movie{} - } - - return -} - -// SelectMany same as Select but returns one or more datamodels.Movie as a slice. -// If limit <=0 then it returns everything. -func (r *movieMemoryRepository) SelectMany(query Query, limit int) (results []datamodels.Movie) { - r.Exec(query, func(m datamodels.Movie) bool { - results = append(results, m) - return true - }, limit, ReadOnlyMode) - - return -} - -// InsertOrUpdate adds or updates a movie to the (memory) storage. -// -// Returns the new movie and an error if any. -func (r *movieMemoryRepository) InsertOrUpdate(movie datamodels.Movie) (datamodels.Movie, error) { - id := movie.ID - - if id == 0 { // Create new action - var lastID int64 - // find the biggest ID in order to not have duplications - // in productions apps you can use a third-party - // library to generate a UUID as string. - r.mu.RLock() - for _, item := range r.source { - if item.ID > lastID { - lastID = item.ID - } - } - r.mu.RUnlock() - - id = lastID + 1 - movie.ID = id - - // map-specific thing - r.mu.Lock() - r.source[id] = movie - r.mu.Unlock() - - return movie, nil - } - - // Update action based on the movie.ID, - // here we will allow updating the poster and genre if not empty. - // Alternatively we could do pure replace instead: - // r.source[id] = movie - // and comment the code below; - current, exists := r.Select(func(m datamodels.Movie) bool { - return m.ID == id - }) - - if !exists { // ID is not a real one, return an error. - return datamodels.Movie{}, errors.New("failed to update a nonexistent movie") - } - - // or comment these and r.source[id] = m for pure replace - if movie.Poster != "" { - current.Poster = movie.Poster - } - - if movie.Genre != "" { - current.Genre = movie.Genre - } - - // map-specific thing - r.mu.Lock() - r.source[id] = current - r.mu.Unlock() - - return movie, nil -} - -func (r *movieMemoryRepository) Delete(query Query, limit int) bool { - return r.Exec(query, func(m datamodels.Movie) bool { - delete(r.source, m.ID) - return true - }, limit, ReadWriteMode) -} diff --git a/_examples/mvc/repository/services/README.md b/_examples/mvc/repository/services/README.md deleted file mode 100644 index 520875c9..00000000 --- a/_examples/mvc/repository/services/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Service Layer - -The package which has access to call functions from the "repositories" and "models" ("datamodels" only in that simple example). It should contain the domain logic. \ No newline at end of file diff --git a/_examples/mvc/repository/services/movie_service.go b/_examples/mvc/repository/services/movie_service.go deleted file mode 100644 index 5e1b0280..00000000 --- a/_examples/mvc/repository/services/movie_service.go +++ /dev/null @@ -1,65 +0,0 @@ -// file: services/movie_service.go - -package services - -import ( - "github.com/kataras/iris/v12/_examples/mvc/repository/datamodels" - "github.com/kataras/iris/v12/_examples/mvc/repository/repositories" -) - -// MovieService handles some of the CRUID operations of the movie datamodel. -// It depends on a movie repository for its actions. -// It's here to decouple the data source from the higher level compoments. -// As a result a different repository type can be used with the same logic without any aditional changes. -// It's an interface and it's used as interface everywhere -// because we may need to change or try an experimental different domain logic at the future. -type MovieService interface { - GetAll() []datamodels.Movie - GetByID(id int64) (datamodels.Movie, bool) - DeleteByID(id int64) bool - UpdatePosterAndGenreByID(id int64, poster string, genre string) (datamodels.Movie, error) -} - -// NewMovieService returns the default movie service. -func NewMovieService(repo repositories.MovieRepository) MovieService { - return &movieService{ - repo: repo, - } -} - -type movieService struct { - repo repositories.MovieRepository -} - -// GetAll returns all movies. -func (s *movieService) GetAll() []datamodels.Movie { - return s.repo.SelectMany(func(_ datamodels.Movie) bool { - return true - }, -1) -} - -// GetByID returns a movie based on its id. -func (s *movieService) GetByID(id int64) (datamodels.Movie, bool) { - return s.repo.Select(func(m datamodels.Movie) bool { - return m.ID == id - }) -} - -// UpdatePosterAndGenreByID updates a movie's poster and genre. -func (s *movieService) UpdatePosterAndGenreByID(id int64, poster string, genre string) (datamodels.Movie, error) { - // update the movie and return it. - return s.repo.InsertOrUpdate(datamodels.Movie{ - ID: id, - Poster: poster, - Genre: genre, - }) -} - -// DeleteByID deletes a movie by its id. -// -// Returns true if deleted otherwise false. -func (s *movieService) DeleteByID(id int64) bool { - return s.repo.Delete(func(m datamodels.Movie) bool { - return m.ID == id - }, 1) -} diff --git a/_examples/mvc/repository/web/controllers/hello_controller.go b/_examples/mvc/repository/web/controllers/hello_controller.go deleted file mode 100644 index 21bbc99e..00000000 --- a/_examples/mvc/repository/web/controllers/hello_controller.go +++ /dev/null @@ -1,58 +0,0 @@ -// file: web/controllers/hello_controller.go - -package controllers - -import ( - "errors" - - "github.com/kataras/iris/v12/mvc" -) - -// HelloController is our sample controller -// it handles GET: /hello and GET: /hello/{name} -type HelloController struct{} - -var helloView = mvc.View{ - Name: "hello/index.html", - Data: map[string]interface{}{ - "Title": "Hello Page", - "MyMessage": "Welcome to my awesome website", - }, -} - -// Get will return a predefined view with bind data. -// -// `mvc.Result` is just an interface with a `Dispatch` function. -// `mvc.Response` and `mvc.View` are the builtin result type dispatchers -// you can even create custom response dispatchers by -// implementing the `github.com/kataras/iris/hero#Result` interface. -func (c *HelloController) Get() mvc.Result { - return helloView -} - -// you can define a standard error in order to re-use anywhere in your app. -var errBadName = errors.New("bad name") - -// you can just return it as error or even better -// wrap this error with an mvc.Response to make it an mvc.Result compatible type. -var badName = mvc.Response{Err: errBadName, Code: 400} - -// GetBy returns a "Hello {name}" response. -// Demos: -// curl -i http://localhost:8080/hello/iris -// curl -i http://localhost:8080/hello/anything -func (c *HelloController) GetBy(name string) mvc.Result { - if name != "iris" { - return badName - // or - // GetBy(name string) (mvc.Result, error) { - // return nil, errBadName - // } - } - - // return mvc.Response{Text: "Hello " + name} OR: - return mvc.View{ - Name: "hello/name.html", - Data: name, - } -} diff --git a/_examples/mvc/repository/web/controllers/movie_controller.go b/_examples/mvc/repository/web/controllers/movie_controller.go deleted file mode 100644 index a800d959..00000000 --- a/_examples/mvc/repository/web/controllers/movie_controller.go +++ /dev/null @@ -1,77 +0,0 @@ -// file: web/controllers/movie_controller.go - -package controllers - -import ( - "errors" - - "github.com/kataras/iris/v12/_examples/mvc/repository/datamodels" - "github.com/kataras/iris/v12/_examples/mvc/repository/services" - - "github.com/kataras/iris/v12" -) - -// MovieController is our /movies controller. -type MovieController struct { - // Our MovieService, it's an interface which - // is binded from the main application. - Service services.MovieService -} - -// Get returns list of the movies. -// Demo: -// curl -i http://localhost:8080/movies -// -// The correct way if you have sensitive data: -// func (c *MovieController) Get() (results []viewmodels.Movie) { -// data := c.Service.GetAll() -// -// for _, movie := range data { -// results = append(results, viewmodels.Movie{movie}) -// } -// return -// } -// otherwise just return the datamodels. -func (c *MovieController) Get() (results []datamodels.Movie) { - return c.Service.GetAll() -} - -// GetBy returns a movie. -// Demo: -// curl -i http://localhost:8080/movies/1 -func (c *MovieController) GetBy(id int64) (movie datamodels.Movie, found bool) { - return c.Service.GetByID(id) // it will throw 404 if not found. -} - -// PutBy updates a movie. -// Demo: -// curl -i -X PUT -F "genre=Thriller" -F "poster=@/Users/kataras/Downloads/out.gif" http://localhost:8080/movies/1 -func (c *MovieController) PutBy(ctx iris.Context, id int64) (datamodels.Movie, error) { - // get the request data for poster and genre - file, info, err := ctx.FormFile("poster") - if err != nil { - return datamodels.Movie{}, errors.New("failed due form file 'poster' missing") - } - // we don't need the file so close it now. - file.Close() - - // imagine that is the url of the uploaded file... - poster := info.Filename - genre := ctx.FormValue("genre") - - return c.Service.UpdatePosterAndGenreByID(id, poster, genre) -} - -// DeleteBy deletes a movie. -// Demo: -// curl -i -X DELETE -u admin:password http://localhost:8080/movies/1 -func (c *MovieController) DeleteBy(id int64) interface{} { - wasDel := c.Service.DeleteByID(id) - if wasDel { - // return the deleted movie's ID - return iris.Map{"deleted": id} - } - // right here we can see that a method function can return any of those two types(map or int), - // we don't have to specify the return type to a specific type. - return iris.StatusBadRequest -} diff --git a/_examples/mvc/repository/web/middleware/basicauth.go b/_examples/mvc/repository/web/middleware/basicauth.go deleted file mode 100644 index 5d61fc72..00000000 --- a/_examples/mvc/repository/web/middleware/basicauth.go +++ /dev/null @@ -1,12 +0,0 @@ -// file: web/middleware/basicauth.go - -package middleware - -import "github.com/kataras/iris/v12/middleware/basicauth" - -// BasicAuth middleware sample. -var BasicAuth = basicauth.New(basicauth.Config{ - Users: map[string]string{ - "admin": "password", - }, -}) diff --git a/_examples/mvc/repository/web/viewmodels/README.md b/_examples/mvc/repository/web/viewmodels/README.md deleted file mode 100644 index 10520287..00000000 --- a/_examples/mvc/repository/web/viewmodels/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# View Models - -There should be the view models, the structure that the client will be able to see. - -Example: - -```go -import ( - "github.com/kataras/iris/v12/_examples/mvc/repository/datamodels" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" -) - -type Movie struct { - datamodels.Movie -} - -func (m Movie) IsValid() bool { - /* do some checks and return true if it's valid... */ - return m.ID > 0 -} -``` - -Iris is able to convert any custom data Structure into an HTTP Response Dispatcher, -so theoretically, something like the following is permitted if it's really necessary; - -```go -// Dispatch completes the `kataras/iris/mvc#Result` interface. -// Sends a `Movie` as a controlled http response. -// If its ID is zero or less then it returns a 404 not found error -// else it returns its json representation, -// (just like the controller's functions do for custom types by default). -// -// Don't overdo it, the application's logic should not be here. -// It's just one more step of validation before the response, -// simple checks can be added here. -// -// It's just a showcase, -// imagine the potentials this feature gives when designing a bigger application. -// -// This is called where the return value from a controller's method functions -// is type of `Movie`. -// For example the `controllers/movie_controller.go#GetBy`. -func (m Movie) Dispatch(ctx iris.Context) { - if !m.IsValid() { - ctx.NotFound() - return - } - ctx.JSON(m, context.JSON{Indent: " "}) -} -``` - -However, we will use the "datamodels" as the only one models package because -Movie structure doesn't contain any sensitive data, clients are able to see all of its fields -and we don't need any extra functionality or validation inside it. \ No newline at end of file diff --git a/_examples/mvc/repository/web/views/hello/index.html b/_examples/mvc/repository/web/views/hello/index.html deleted file mode 100644 index 9e7b03d6..00000000 --- a/_examples/mvc/repository/web/views/hello/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - {{.Title}} - My App - - - -

{{.MyMessage}}

- - - \ No newline at end of file diff --git a/_examples/mvc/repository/web/views/hello/name.html b/_examples/mvc/repository/web/views/hello/name.html deleted file mode 100644 index d6dd5ac6..00000000 --- a/_examples/mvc/repository/web/views/hello/name.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - {{.}}' Portfolio - My App - - - -

Hello {{.}}

- - - \ No newline at end of file diff --git a/_examples/mvc/session-controller/main.go b/_examples/mvc/session-controller/main.go deleted file mode 100644 index 953f6e69..00000000 --- a/_examples/mvc/session-controller/main.go +++ /dev/null @@ -1,58 +0,0 @@ -package main - -import ( - "fmt" - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" - "github.com/kataras/iris/v12/sessions" -) - -// VisitController handles the root route. -type VisitController struct { - // the current request session, automatically binded. - Session *sessions.Session - - // A time.time which is binded from the MVC application manually. - StartTime time.Time -} - -// Get handles index -// Method: GET -// Path: http://localhost:8080 -func (c *VisitController) Get() string { - // it increments a "visits" value of integer by one, - // if the entry with key 'visits' doesn't exist it will create it for you. - visits := c.Session.Increment("visits", 1) - // write the current, updated visits. - since := time.Now().Sub(c.StartTime).Seconds() - return fmt.Sprintf("%d visit(s) from my current session in %0.1f seconds of server's up-time", - visits, since) -} - -func newApp() *iris.Application { - app := iris.New() - // Configure sessions manager as we used to. - sess := sessions.New(sessions.Config{Cookie: "mysession_cookie_name"}) - app.Use(sess.Handler()) - - visitApp := mvc.New(app) - visitApp.Register(time.Now()) - // The `VisitController.Session` is automatically binded to the current `sessions.Session`. - - visitApp.Handle(new(VisitController)) - - return app -} - -func main() { - app := newApp() - - // 1. Prepare a client, e.g. your browser - // 2. navigate to http://localhost:8080 - // 3. refresh the page some times - // 4. close the browser - // 5. re-open the browser (if it wasn't in private mode) and re-play 2. - app.Listen(":8080") -} diff --git a/_examples/mvc/session-controller/main_test.go b/_examples/mvc/session-controller/main_test.go deleted file mode 100644 index e7ec5929..00000000 --- a/_examples/mvc/session-controller/main_test.go +++ /dev/null @@ -1,21 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestMVCSession(t *testing.T) { - e := httptest.New(t, newApp(), httptest.URL("http://example.com")) - - e1 := e.GET("/").Expect().Status(httptest.StatusOK) - e1.Cookies().NotEmpty() - e1.Body().Contains("1 visit") - - e.GET("/").Expect().Status(httptest.StatusOK). - Body().Contains("2 visit") - - e.GET("/").Expect().Status(httptest.StatusOK). - Body().Contains("3 visit") -} diff --git a/_examples/mvc/singleton/main.go b/_examples/mvc/singleton/main.go deleted file mode 100644 index 971d2581..00000000 --- a/_examples/mvc/singleton/main.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "fmt" - "sync/atomic" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" -) - -func main() { - app := iris.New() - mvc.New(app.Party("/")).Handle(&globalVisitorsController{visits: 0}) - - // http://localhost:8080 - app.Listen(":8080") -} - -type globalVisitorsController struct { - // When a singleton controller is used then concurent safe access is up to the developers, because - // all clients share the same controller instance instead. - // Note that any controller's methods - // are per-client, but the struct's field can be shared across multiple clients if the structure - // does not have any dynamic struct field dependencies that depend on the iris.Context - // and ALL field's values are NOT zero, at this case we use uint64 which it's no zero (even if we didn't set it - // manually ease-of-understand reasons) because it's a value of &{0}. - // All the above declares a Singleton, note that you don't have to write a single line of code to do this, Iris is smart enough. - // - // see `Get`. - visits uint64 -} - -func (c *globalVisitorsController) Get() string { - count := atomic.AddUint64(&c.visits, 1) - return fmt.Sprintf("Total visitors: %d", count) -} diff --git a/_examples/mvc/versioned-controller/main.go b/_examples/mvc/versioned-controller/main.go deleted file mode 100644 index 9c8bb950..00000000 --- a/_examples/mvc/versioned-controller/main.go +++ /dev/null @@ -1,62 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" -) - -// Optional deprecated X-API-XXX headers for version 1. -var opts = mvc.DeprecationOptions{ - WarnMessage: "deprecated, see ", - DeprecationDate: time.Now().UTC(), - DeprecationInfo: "a bigger version is available, see for more information", -} - -func main() { - app := newApp() - - // See main_test.go for request examples. - app.Listen(":8080") -} - -func newApp() *iris.Application { - app := iris.New() - - dataRouter := app.Party("/data") - { - m := mvc.New(dataRouter) - - m.Handle(new(v1Controller), mvc.Version("1"), mvc.Deprecated(opts)) // 1 or 1.0, 1.0.0 ... - m.Handle(new(v2Controller), mvc.Version("2.3")) // 2.3 or 2.3.0 - m.Handle(new(v3Controller), mvc.Version(">=3, <4")) // 3, 3.x, 3.x.x ... - m.Handle(new(noVersionController)) // or if missing it will respond with 501 version not found. - } - - return app -} - -type v1Controller struct{} - -func (c *v1Controller) Get() string { - return "data (v1.x)" -} - -type v2Controller struct{} - -func (c *v2Controller) Get() string { - return "data (v2.x)" -} - -type v3Controller struct{} - -func (c *v3Controller) Get() string { - return "data (v3.x)" -} - -type noVersionController struct{} - -func (c *noVersionController) Get() string { - return "data" -} diff --git a/_examples/mvc/versioned-controller/main_test.go b/_examples/mvc/versioned-controller/main_test.go deleted file mode 100644 index 309a14f1..00000000 --- a/_examples/mvc/versioned-controller/main_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/httptest" - "github.com/kataras/iris/v12/versioning" -) - -func TestVersionedController(t *testing.T) { - app := newApp() - - e := httptest.New(t, app) - e.GET("/data").WithHeader(versioning.AcceptVersionHeaderKey, "1").Expect(). - Status(iris.StatusOK).Body().Equal("data (v1.x)") - e.GET("/data").WithHeader(versioning.AcceptVersionHeaderKey, "2.3.0").Expect(). - Status(iris.StatusOK).Body().Equal("data (v2.x)") - e.GET("/data").WithHeader(versioning.AcceptVersionHeaderKey, "3.1").Expect(). - Status(iris.StatusOK).Body().Equal("data (v3.x)") - - // Test invalid version or no version at all. - e.GET("/data").WithHeader(versioning.AcceptVersionHeaderKey, "4").Expect(). - Status(iris.StatusOK).Body().Equal("data") - e.GET("/data").Expect(). - Status(iris.StatusOK).Body().Equal("data") - - // Test Deprecated (v1) - ex := e.GET("/data").WithHeader(versioning.AcceptVersionHeaderKey, "1.0").Expect() - ex.Status(iris.StatusOK).Body().Equal("data (v1.x)") - ex.Header("X-API-Warn").Equal(opts.WarnMessage) - expectedDateStr := opts.DeprecationDate.Format(app.ConfigurationReadOnly().GetTimeFormat()) - ex.Header("X-API-Deprecation-Date").Equal(expectedDateStr) -} diff --git a/_examples/mvc/vuejs-todo-mvc/README.md b/_examples/mvc/vuejs-todo-mvc/README.md deleted file mode 100644 index fc9845c6..00000000 --- a/_examples/mvc/vuejs-todo-mvc/README.md +++ /dev/null @@ -1,593 +0,0 @@ -# A Todo MVC Application using Iris and Vue.js - -## Hackernoon Article: https://medium.com/hackernoon/a-todo-mvc-application-using-iris-and-vue-js-5019ff870064 - -Vue.js is a front-end framework for building web applications using javascript. It has a blazing fast Virtual DOM renderer. - -Iris is a back-end framework for building web applications using The Go Programming Language (disclaimer: author here). It's one of the fastest and featured web frameworks out there. We wanna use this to serve our "todo service". - -## The Tools - -Programming Languages are just tools for us, but we need a safe, fast and “cross-platform” programming language to power our service. - -[Go](https://golang.org) is a [rapidly growing](https://www.tiobe.com/tiobe-index/) open source programming language designed for building simple, fast, and reliable software. Take a look [here](https://github.com/golang/go/wiki/GoUsers) which great companies use Go to power their services. - -### Install the Go Programming Language - -Extensive information about downloading & installing Go can be found [here](https://golang.org/dl/). - -[![](https://i3.ytimg.com/vi/9x-pG3lvLi0/hqdefault.jpg)](https://youtu.be/9x-pG3lvLi0) - -> Maybe [Windows](https://www.youtube.com/watch?v=WT5mTznJBS0) or [Mac OS X](https://www.youtube.com/watch?v=5qI8z_lB5Lw) user? - -> The article does not contain an introduction to the language itself, if you’re a newcomer I recommend you to bookmark this article, [learn](https://github.com/golang/go/wiki/Learn) the language’s fundamentals and come back later on. - -## The Dependencies - -Many articles have been written, in the past, that lead developers not to use a web framework because they are useless and "bad". I have to tell you that there is no such thing, it always depends on the (web) framework that you’re going to use. At production environment, we don’t have the time or the experience to code everything that we wanna use in the applications, and if we could are we sure that we can do better and safely than others? In short term: **Good frameworks are helpful tools for any developer, company or startup and "bad" frameworks are waste of time, crystal clear.** - -You’ll need two dependencies: - -1. Vue.js, for our client-side requirements. Download it from [here](https://vuejs.org/), latest v2. -2. The Iris Web Framework, for our server-side requirements. Can be found [here](https://github.com/kataras/iris), latest v12. - -> If you have Go already installed then just execute `go get github.com/kataras/iris/v12@latest` to install the Iris Web Framework. - -## Start - -If we are all in the same page, it’s time to learn how we can create a live todo application that will be easy to deploy and extend even more! - -We're going to use a vue.js todo application which uses browser' -s local storage and doesn't have any user-specified features like live sync between browser's tabs, you can find the original version inside the vue's [docs](https://vuejs.org/v2/examples/todomvc.html). - -Assuming that you know how %GOPATH% works, create an empty folder, i.e "vuejs-todo-mvc" in the %GOPATH%/src directory, there you will create those files: - -- web/public/js/app.js -- web/public/index.html -- todo/item.go -- todo/service.go -- web/controllers/todo_controller.go -- web/main.go - -_Read the comments in the source code, they may be very helpful_ - -### The client-side (vue.js) - -```js -/* file: vuejs-todo-mvc/web/public/js/app.js */ -// Full spec-compliant TodoMVC with Iris -// and hash-based routing in ~200 effective lines of JavaScript. - -var ws; - -((async () => { - const events = { - todos: { - saved: function (ns, msg) { - app.todos = msg.unmarshal() - // or make a new http fetch - // fetchTodos(function (items) { - // app.todos = msg.unmarshal() - // }); - } - } - }; - - const conn = await neffos.dial("ws://localhost:8080/todos/sync", events); - ws = await conn.connect("todos"); -})()).catch(console.error); - -function fetchTodos(onComplete) { - axios.get("/todos").then(response => { - if (response.data === null) { - return; - } - - onComplete(response.data); - }); -} - -var todoStorage = { - fetch: function () { - var todos = []; - fetchTodos(function (items) { - for (var i = 0; i < items.length; i++) { - todos.push(items[i]); - } - }); - return todos; - }, - save: function (todos) { - axios.post("/todos", JSON.stringify(todos)).then(response => { - if (!response.data.success) { - window.alert("saving had a failure"); - return; - } - // console.log("send: save"); - ws.emit("save") - }); - } -} - -// visibility filters -var filters = { - all: function (todos) { - return todos - }, - active: function (todos) { - return todos.filter(function (todo) { - return !todo.completed - }) - }, - completed: function (todos) { - return todos.filter(function (todo) { - return todo.completed - }) - } -} - -// app Vue instance -var app = new Vue({ - // app initial state - data: { - todos: todoStorage.fetch(), - newTodo: '', - editedTodo: null, - visibility: 'all' - }, - - // we will not use the "watch" as it works with the fields like "hasChanges" - // and callbacks to make it true but let's keep things very simple as it's just a small getting started. - // // watch todos change for persistence - // watch: { - // todos: { - // handler: function (todos) { - // if (app.hasChanges) { - // todoStorage.save(todos); - // app.hasChanges = false; - // } - - // }, - // deep: true - // } - // }, - - // computed properties - // http://vuejs.org/guide/computed.html - computed: { - filteredTodos: function () { - return filters[this.visibility](this.todos) - }, - remaining: function () { - return filters.active(this.todos).length - }, - allDone: { - get: function () { - return this.remaining === 0 - }, - set: function (value) { - this.todos.forEach(function (todo) { - todo.completed = value - }) - this.notifyChange(); - } - } - }, - - filters: { - pluralize: function (n) { - return n === 1 ? 'item' : 'items' - } - }, - - // methods that implement data logic. - // note there's no DOM manipulation here at all. - methods: { - notifyChange: function () { - todoStorage.save(this.todos) - }, - addTodo: function () { - var value = this.newTodo && this.newTodo.trim() - if (!value) { - return - } - this.todos.push({ - id: this.todos.length + 1, // just for the client-side. - title: value, - completed: false - }) - this.newTodo = '' - this.notifyChange(); - }, - - completeTodo: function (todo) { - if (todo.completed) { - todo.completed = false; - } else { - todo.completed = true; - } - this.notifyChange(); - }, - removeTodo: function (todo) { - this.todos.splice(this.todos.indexOf(todo), 1) - this.notifyChange(); - }, - - editTodo: function (todo) { - this.beforeEditCache = todo.title - this.editedTodo = todo - }, - - doneEdit: function (todo) { - if (!this.editedTodo) { - return - } - this.editedTodo = null - todo.title = todo.title.trim(); - if (!todo.title) { - this.removeTodo(todo); - } - this.notifyChange(); - }, - - cancelEdit: function (todo) { - this.editedTodo = null - todo.title = this.beforeEditCache - }, - - removeCompleted: function () { - this.todos = filters.active(this.todos); - this.notifyChange(); - } - }, - - // a custom directive to wait for the DOM to be updated - // before focusing on the input field. - // http://vuejs.org/guide/custom-directive.html - directives: { - 'todo-focus': function (el, binding) { - if (binding.value) { - el.focus() - } - } - } -}) - -// handle routing -function onHashChange() { - var visibility = window.location.hash.replace(/#\/?/, '') - if (filters[visibility]) { - app.visibility = visibility - } else { - window.location.hash = '' - app.visibility = 'all' - } -} - -window.addEventListener('hashchange', onHashChange) -onHashChange() - -// mount -app.$mount('.todoapp'); -``` - -Let's add our view, the static html. - -```html - - - - - - - Iris + Vue.js • TodoMVC - - - - - - - - - - - - - -
-
-

todos

- -
-
- -
    -
  • -
    - - - - -
    - -
  • -
-
-
- - {{ remaining }} {{ remaining | pluralize }} left - - - -
-
-
-

Double-click to edit a todo

-
- - - - - -``` - -### The server-side (iris) - -Our view model. - -```go -// file: vuejs-todo-mvc/todo/item.go -package todo - -type Item struct { - SessionID string `json:"-"` - ID int64 `json:"id,omitempty"` - Title string `json:"title"` - Completed bool `json:"completed"` -} -``` - -Our service. - -```go -// file: vuejs-todo-mvc/todo/service.go -package todo - -import ( - "sync" -) - -type Service interface { - Get(owner string) []Item - Save(owner string, newItems []Item) error -} - -type MemoryService struct { - // key = session id, value the list of todo items that this session id has. - items map[string][]Item - // protected by locker for concurrent access. - mu sync.RWMutex -} - -func NewMemoryService() *MemoryService { - return &MemoryService{ - items: make(map[string][]Item, 0), - } -} - -func (s *MemoryService) Get(sessionOwner string) []Item { - s.mu.RLock() - items := s.items[sessionOwner] - s.mu.RUnlock() - - return items -} - -func (s *MemoryService) Save(sessionOwner string, newItems []Item) error { - var prevID int64 - for i := range newItems { - if newItems[i].ID == 0 { - newItems[i].ID = prevID - prevID++ - } - } - - s.mu.Lock() - s.items[sessionOwner] = newItems - s.mu.Unlock() - return nil -} -``` - -We are going to use some of the MVC functionalities of the iris web framework here but you can do the same with the standard API as well. - -```go -// file: vuejs-todo-mvc/web/controllers/todo_controller.go -package controllers - -import ( - "vuejs-todo-mvc/todo" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" - "github.com/kataras/iris/v12/sessions" - "github.com/kataras/iris/v12/websocket" -) - -// TodoController is our TODO app's web controller. -type TodoController struct { - Service todo.Service - - Session *sessions.Session - - NS *websocket.NSConn -} - -// BeforeActivation called once before the server ran, and before -// the routes and dependencies binded. -// You can bind custom things to the controller, add new methods, add middleware, -// add dependencies to the struct or the method(s) and more. -func (c *TodoController) BeforeActivation(b mvc.BeforeActivation) { - // this could be binded to a controller's function input argument - // if any, or struct field if any: - b.Dependencies().Add(func(ctx iris.Context) (items []todo.Item) { - ctx.ReadJSON(&items) - return - }) -} - -// Get handles the GET: /todos route. -func (c *TodoController) Get() []todo.Item { - return c.Service.Get(c.Session.ID()) -} - -// PostItemResponse the response data that will be returned as json -// after a post save action of all todo items. -type PostItemResponse struct { - Success bool `json:"success"` -} - -var emptyResponse = PostItemResponse{Success: false} - -// Post handles the POST: /todos route. -func (c *TodoController) Post(newItems []todo.Item) PostItemResponse { - if err := c.Service.Save(c.Session.ID(), newItems); err != nil { - return emptyResponse - } - - return PostItemResponse{Success: true} -} - -func (c *TodoController) Save(msg websocket.Message) error { - id := c.Session.ID() - c.NS.Conn.Server().Broadcast(nil, websocket.Message{ - Namespace: msg.Namespace, - Event: "saved", - To: id, - Body: websocket.Marshal(c.Service.Get(id)), - }) - - return nil -} - -``` - -And finally our main application's endpoint. - -```go -// file: web/main.go -package main - -import ( - "strings" - - "github.com/kataras/iris/v12/_examples/mvc/vuejs-todo-mvc/src/todo" - "github.com/kataras/iris/v12/_examples/mvc/vuejs-todo-mvc/src/web/controllers" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" - "github.com/kataras/iris/v12/sessions" - "github.com/kataras/iris/v12/websocket" -) - -func main() { - app := iris.New() - - // serve our app in public, public folder - // contains the client-side vue.js application, - // no need for any server-side template here, - // actually if you're going to just use vue without any - // back-end services, you can just stop afer this line and start the server. - app.HandleDir("/", iris.Dir("./public")) - - // configure the http sessions. - sess := sessions.New(sessions.Config{ - Cookie: "iris_session", - }) - - // create a sub router and register the http controllers. - todosRouter := app.Party("/todos") - - // create our mvc application targeted to /todos relative sub path. - todosApp := mvc.New(todosRouter) - - // any dependencies bindings here... - todosApp.Register( - todo.NewMemoryService(), - ) - - todosController := new(controllers.TodoController) - // controllers registration here... - todosApp.Handle(todosController) - - // Create a sub mvc app for websocket controller. - // Inherit the parent's dependencies. - todosWebsocketApp := todosApp.Party("/sync") - todosWebsocketApp.HandleWebsocket(todosController). - SetNamespace("todos"). - SetEventMatcher(func(methodName string) (string, bool) { - return strings.ToLower(methodName), true - }) - - websocketServer := websocket.New(websocket.DefaultGorillaUpgrader, todosWebsocketApp) - idGenerator := func(ctx iris.Context) string { - id := sess.Start(ctx).ID() - return id - } - todosWebsocketApp.Router.Get("/", websocket.Handler(websocketServer, idGenerator)) - - // start the web server at http://localhost:8080 - app.Listen(":8080") -} -``` - -Run the Iris web server you've just created by executing `go run main.go` from your current path (%GOPATH%/src/%your_folder%/web/). - -```sh -$ go run main.go -Now listening on: http://localhost:8080 -Application Started. Press CTRL+C to shut down. -_ -``` - -Open one or more browser tabs at: http://localhost:8080 and have fun! - -![](screen.png) - -### Download the Source Code - -The whole project, all the files you saw in this article are located at: https://github.com/kataras/iris/tree/master/_examples/mvc/vuejs-todo-mvc - -## References - -https://vuejs.org/v2/examples/todomvc.html (using browser's local storage) - -https://github.com/kataras/iris/tree/master/_examples/mvc (mvc examples and features overview repository) - -## Thank you, once again - -Happy new year and thank you for your pattience, once again:) Don't hesitate to post any questions and provide feedback(I'm very active dev therefore you will be heard here!) - -Don't forget to check out my medium profile and twitter as well, I'm posting some (useful) stuff there too:) - -- https://medium.com/@kataras -- https://twitter.com/MakisMaropoulos diff --git a/_examples/mvc/vuejs-todo-mvc/screen.png b/_examples/mvc/vuejs-todo-mvc/screen.png deleted file mode 100644 index 41df240d7fa4f06082319b77cfc8e29e3c064ee5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 103259 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%0DJ*7BA_EgO(Oa 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 BulE1| diff --git a/_examples/mvc/vuejs-todo-mvc/src/todo/item.go b/_examples/mvc/vuejs-todo-mvc/src/todo/item.go deleted file mode 100644 index eb464be2..00000000 --- a/_examples/mvc/vuejs-todo-mvc/src/todo/item.go +++ /dev/null @@ -1,8 +0,0 @@ -package todo - -type Item struct { - SessionID string `json:"-"` - ID int64 `json:"id,omitempty"` - Title string `json:"title"` - Completed bool `json:"completed"` -} diff --git a/_examples/mvc/vuejs-todo-mvc/src/todo/service.go b/_examples/mvc/vuejs-todo-mvc/src/todo/service.go deleted file mode 100644 index d9af2854..00000000 --- a/_examples/mvc/vuejs-todo-mvc/src/todo/service.go +++ /dev/null @@ -1,46 +0,0 @@ -package todo - -import ( - "sync" -) - -type Service interface { - Get(owner string) []Item - Save(owner string, newItems []Item) error -} - -type MemoryService struct { - // key = session id, value the list of todo items that this session id has. - items map[string][]Item - // protected by locker for concurrent access. - mu sync.RWMutex -} - -func NewMemoryService() *MemoryService { - return &MemoryService{ - items: make(map[string][]Item, 0), - } -} - -func (s *MemoryService) Get(sessionOwner string) []Item { - s.mu.RLock() - items := s.items[sessionOwner] - s.mu.RUnlock() - - return items -} - -func (s *MemoryService) Save(sessionOwner string, newItems []Item) error { - var prevID int64 - for i := range newItems { - if newItems[i].ID == 0 { - newItems[i].ID = prevID - prevID++ - } - } - - s.mu.Lock() - s.items[sessionOwner] = newItems - s.mu.Unlock() - return nil -} diff --git a/_examples/mvc/vuejs-todo-mvc/src/web/controllers/todo_controller.go b/_examples/mvc/vuejs-todo-mvc/src/web/controllers/todo_controller.go deleted file mode 100644 index 407b8eef..00000000 --- a/_examples/mvc/vuejs-todo-mvc/src/web/controllers/todo_controller.go +++ /dev/null @@ -1,66 +0,0 @@ -package controllers - -import ( - "github.com/kataras/iris/v12/_examples/mvc/vuejs-todo-mvc/src/todo" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" - "github.com/kataras/iris/v12/sessions" - "github.com/kataras/iris/v12/websocket" -) - -// TodoController is our TODO app's web controller. -type TodoController struct { - Service todo.Service - - Session *sessions.Session - - NS *websocket.NSConn -} - -// BeforeActivation called once before the server ran, and before -// the routes and dependencies binded. -// You can bind custom things to the controller, add new methods, add middleware, -// add dependencies to the struct or the method(s) and more. -func (c *TodoController) BeforeActivation(b mvc.BeforeActivation) { - // this could be binded to a controller's function input argument - // if any, or struct field if any: - b.Dependencies().Register(func(ctx iris.Context) (items []todo.Item) { - ctx.ReadJSON(&items) - return - }) // Note: from Iris v12.2 these type of dependencies are automatically resolved. -} - -// Get handles the GET: /todos route. -func (c *TodoController) Get() []todo.Item { - return c.Service.Get(c.Session.ID()) -} - -// PostItemResponse the response data that will be returned as json -// after a post save action of all todo items. -type PostItemResponse struct { - Success bool `json:"success"` -} - -var emptyResponse = PostItemResponse{Success: false} - -// Post handles the POST: /todos route. -func (c *TodoController) Post(newItems []todo.Item) PostItemResponse { - if err := c.Service.Save(c.Session.ID(), newItems); err != nil { - return emptyResponse - } - - return PostItemResponse{Success: true} -} - -func (c *TodoController) Save(msg websocket.Message) error { - id := c.Session.ID() - c.NS.Conn.Server().Broadcast(nil, websocket.Message{ - Namespace: msg.Namespace, - Event: "saved", - To: id, - Body: websocket.Marshal(c.Service.Get(id)), - }) - - return nil -} diff --git a/_examples/mvc/vuejs-todo-mvc/src/web/main.go b/_examples/mvc/vuejs-todo-mvc/src/web/main.go deleted file mode 100644 index 8a2d54e6..00000000 --- a/_examples/mvc/vuejs-todo-mvc/src/web/main.go +++ /dev/null @@ -1,63 +0,0 @@ -package main - -import ( - "strings" - - "github.com/kataras/iris/v12/_examples/mvc/vuejs-todo-mvc/src/todo" - "github.com/kataras/iris/v12/_examples/mvc/vuejs-todo-mvc/src/web/controllers" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" - "github.com/kataras/iris/v12/sessions" - "github.com/kataras/iris/v12/websocket" -) - -func main() { - app := iris.New() - - // serve our app in public, public folder - // contains the client-side vue.js application, - // no need for any server-side template here, - // actually if you're going to just use vue without any - // back-end services, you can just stop afer this line and start the server. - app.HandleDir("/", iris.Dir("./public")) - - // configure the http sessions. - sess := sessions.New(sessions.Config{ - Cookie: "iris_session", - }) - - // create a sub router and register the http controllers. - todosRouter := app.Party("/todos") - - // create our mvc application targeted to /todos relative sub path. - todosApp := mvc.New(todosRouter) - - // any dependencies bindings here... - todosApp.Register( - todo.NewMemoryService(), - ) - - todosController := new(controllers.TodoController) - // controllers registration here... - todosApp.Handle(todosController) - - // Create a sub mvc app for websocket controller. - // Inherit the parent's dependencies. - todosWebsocketApp := todosApp.Party("/sync") - todosWebsocketApp.HandleWebsocket(todosController). - SetNamespace("todos"). - SetEventMatcher(func(methodName string) (string, bool) { - return strings.ToLower(methodName), true - }) - - websocketServer := websocket.New(websocket.DefaultGorillaUpgrader, todosWebsocketApp) - idGenerator := func(ctx iris.Context) string { - id := sess.Start(ctx).ID() - return id - } - todosWebsocketApp.Router.Get("/", websocket.Handler(websocketServer, idGenerator)) - - // start the web server at http://localhost:8080 - app.Listen(":8080") -} diff --git a/_examples/mvc/vuejs-todo-mvc/src/web/public/css/index b/_examples/mvc/vuejs-todo-mvc/src/web/public/css/index deleted file mode 100644 index 3aea0097..00000000 --- a/_examples/mvc/vuejs-todo-mvc/src/web/public/css/index +++ /dev/null @@ -1,2 +0,0 @@ -index.css is not here to reduce the disk space for the examples. -https://unpkg.com/todomvc-app-css@2.0.4/index.css is used instead. \ No newline at end of file diff --git a/_examples/mvc/vuejs-todo-mvc/src/web/public/index.html b/_examples/mvc/vuejs-todo-mvc/src/web/public/index.html deleted file mode 100644 index 6b43069d..00000000 --- a/_examples/mvc/vuejs-todo-mvc/src/web/public/index.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - Iris + Vue.js • TodoMVC - - - - - - - - - - - - - -
-
-

todos

- -
-
- -
    -
  • -
    - - - - -
    - -
  • -
-
-
- - {{ remaining }} {{ remaining | pluralize }} left - - - -
-
-
-

Double-click to edit a todo

-
- - - - - \ No newline at end of file diff --git a/_examples/mvc/vuejs-todo-mvc/src/web/public/js/app.js b/_examples/mvc/vuejs-todo-mvc/src/web/public/js/app.js deleted file mode 100644 index fcc0863d..00000000 --- a/_examples/mvc/vuejs-todo-mvc/src/web/public/js/app.js +++ /dev/null @@ -1,214 +0,0 @@ -// Full spec-compliant TodoMVC with Iris -// and hash-based routing in ~200 effective lines of JavaScript. - -var ws; - -((async () => { - const events = { - todos: { - saved: function (ns, msg) { - app.todos = msg.unmarshal() - // or make a new http fetch - // fetchTodos(function (items) { - // app.todos = msg.unmarshal() - // }); - } - } - }; - - const conn = await neffos.dial("ws://localhost:8080/todos/sync", events); - ws = await conn.connect("todos"); -})()).catch(console.error); - -function fetchTodos(onComplete) { - axios.get("/todos").then(response => { - if (response.data === null) { - return; - } - - onComplete(response.data); - }); -} - -var todoStorage = { - fetch: function () { - var todos = []; - fetchTodos(function (items) { - for (var i = 0; i < items.length; i++) { - todos.push(items[i]); - } - }); - return todos; - }, - save: function (todos) { - axios.post("/todos", JSON.stringify(todos)).then(response => { - if (!response.data.success) { - window.alert("saving had a failure"); - return; - } - // console.log("send: save"); - ws.emit("save") - }); - } -} - -// visibility filters -var filters = { - all: function (todos) { - return todos - }, - active: function (todos) { - return todos.filter(function (todo) { - return !todo.completed - }) - }, - completed: function (todos) { - return todos.filter(function (todo) { - return todo.completed - }) - } -} - -// app Vue instance -var app = new Vue({ - // app initial state - data: { - todos: todoStorage.fetch(), - newTodo: '', - editedTodo: null, - visibility: 'all' - }, - - // we will not use the "watch" as it works with the fields like "hasChanges" - // and callbacks to make it true but let's keep things very simple as it's just a small getting started. - // // watch todos change for persistence - // watch: { - // todos: { - // handler: function (todos) { - // if (app.hasChanges) { - // todoStorage.save(todos); - // app.hasChanges = false; - // } - - // }, - // deep: true - // } - // }, - - // computed properties - // http://vuejs.org/guide/computed.html - computed: { - filteredTodos: function () { - return filters[this.visibility](this.todos) - }, - remaining: function () { - return filters.active(this.todos).length - }, - allDone: { - get: function () { - return this.remaining === 0 - }, - set: function (value) { - this.todos.forEach(function (todo) { - todo.completed = value - }) - this.notifyChange(); - } - } - }, - - filters: { - pluralize: function (n) { - return n === 1 ? 'item' : 'items' - } - }, - - // methods that implement data logic. - // note there's no DOM manipulation here at all. - methods: { - notifyChange: function () { - todoStorage.save(this.todos) - }, - addTodo: function () { - var value = this.newTodo && this.newTodo.trim() - if (!value) { - return - } - this.todos.push({ - id: this.todos.length + 1, // just for the client-side. - title: value, - completed: false - }) - this.newTodo = '' - this.notifyChange(); - }, - - completeTodo: function (todo) { - if (todo.completed) { - todo.completed = false; - } else { - todo.completed = true; - } - this.notifyChange(); - }, - removeTodo: function (todo) { - this.todos.splice(this.todos.indexOf(todo), 1) - this.notifyChange(); - }, - - editTodo: function (todo) { - this.beforeEditCache = todo.title - this.editedTodo = todo - }, - - doneEdit: function (todo) { - if (!this.editedTodo) { - return - } - this.editedTodo = null - todo.title = todo.title.trim(); - if (!todo.title) { - this.removeTodo(todo); - } - this.notifyChange(); - }, - - cancelEdit: function (todo) { - this.editedTodo = null - todo.title = this.beforeEditCache - }, - - removeCompleted: function () { - this.todos = filters.active(this.todos); - this.notifyChange(); - } - }, - - // a custom directive to wait for the DOM to be updated - // before focusing on the input field. - // http://vuejs.org/guide/custom-directive.html - directives: { - 'todo-focus': function (el, binding) { - if (binding.value) { - el.focus() - } - } - } -}) - -// handle routing -function onHashChange() { - var visibility = window.location.hash.replace(/#\/?/, '') - if (filters[visibility]) { - app.visibility = visibility - } else { - window.location.hash = '' - app.visibility = 'all' - } -} - -window.addEventListener('hashchange', onHashChange) -onHashChange() - -// mount -app.$mount('.todoapp'); \ No newline at end of file diff --git a/_examples/mvc/vuejs-todo-mvc/src/web/public/js/lib/vue b/_examples/mvc/vuejs-todo-mvc/src/web/public/js/lib/vue deleted file mode 100644 index 8da03f48..00000000 --- a/_examples/mvc/vuejs-todo-mvc/src/web/public/js/lib/vue +++ /dev/null @@ -1,2 +0,0 @@ -vue.js is not here to reduce the disk space for the examples. -Instead https://vuejs.org/js/vue.js is used instead. \ No newline at end of file diff --git a/_examples/mvc/websocket/browser/index.html b/_examples/mvc/websocket/browser/index.html deleted file mode 100644 index c7a2f910..00000000 --- a/_examples/mvc/websocket/browser/index.html +++ /dev/null @@ -1,106 +0,0 @@ - - - - Online visitors MVC example - - - - -
- 1 online visitor -
- - - - - - - - -

-    
-    
-    
-
-
-
-
\ No newline at end of file
diff --git a/_examples/mvc/websocket/main.go b/_examples/mvc/websocket/main.go
deleted file mode 100644
index 71076016..00000000
--- a/_examples/mvc/websocket/main.go
+++ /dev/null
@@ -1,118 +0,0 @@
-package main
-
-import (
-	"fmt"
-	"sync/atomic"
-
-	"github.com/kataras/iris/v12"
-	"github.com/kataras/iris/v12/mvc"
-	"github.com/kataras/iris/v12/websocket"
-)
-
-func main() {
-	app := iris.New()
-	app.Logger().SetLevel("debug")
-
-	// load templates.
-	// app.RegisterView(iris.HTML("./views", ".html"))
-
-	// render the ./browser/index.html.
-	app.HandleDir("/", iris.Dir("./browser"))
-
-	websocketAPI := app.Party("/websocket")
-
-	m := mvc.New(websocketAPI)
-	m.Register(
-		&prefixedLogger{prefix: "DEV"},
-	)
-	m.HandleWebsocket(&websocketController{Namespace: "default", Age: 42, Otherstring: "other string"})
-
-	websocketServer := websocket.New(websocket.DefaultGorillaUpgrader, m)
-
-	websocketAPI.Get("/", websocket.Handler(websocketServer))
-	// http://localhost:8080
-	app.Listen(":8080")
-}
-
-var visits uint64
-
-func increment() uint64 {
-	return atomic.AddUint64(&visits, 1)
-}
-
-func decrement() uint64 {
-	return atomic.AddUint64(&visits, ^uint64(0))
-}
-
-type websocketController struct {
-	*websocket.NSConn `stateless:"true"`
-	Namespace         string
-	Age               int
-	Otherstring       string
-
-	Logger LoggerService
-}
-
-// or
-// func (c *websocketController) Namespace() string {
-// 	return "default"
-// }
-
-func (c *websocketController) OnNamespaceDisconnect(msg websocket.Message) error {
-	c.Logger.Log("Disconnected")
-	// visits--
-	newCount := decrement()
-	// This will call the "OnVisit" event on all clients, except the current one,
-	// (it can't because it's left but for any case use this type of design)
-	c.Conn.Server().Broadcast(nil, websocket.Message{
-		Namespace: msg.Namespace,
-		Event:     "OnVisit",
-		Body:      []byte(fmt.Sprintf("%d", newCount)),
-	})
-
-	return nil
-}
-
-func (c *websocketController) OnNamespaceConnected(msg websocket.Message) error {
-	// println("Broadcast prefix is: " + c.BroadcastPrefix)
-	c.Logger.Log("Connected")
-
-	// visits++
-	newCount := increment()
-
-	// This will call the "OnVisit" event on all clients, including the current one,
-	// with the 'newCount' variable.
-	//
-	// There are many ways that u can do it and faster, for example u can just send a new visitor
-	// and client can increment itself, but here we are just "showcasing" the websocket controller.
-	c.Conn.Server().Broadcast(nil, websocket.Message{
-		Namespace: msg.Namespace,
-		Event:     "OnVisit",
-		Body:      []byte(fmt.Sprintf("%d", newCount)),
-	})
-
-	return nil
-}
-
-func (c *websocketController) OnChat(msg websocket.Message) error {
-	ctx := websocket.GetContext(c.Conn)
-
-	ctx.Application().Logger().Infof("[IP: %s] [ID: %s]  broadcast to other clients the message [%s]",
-		ctx.RemoteAddr(), c, string(msg.Body))
-
-	c.Conn.Server().Broadcast(c, msg)
-
-	return nil
-}
-
-type LoggerService interface {
-	Log(string)
-}
-
-type prefixedLogger struct {
-	prefix string
-}
-
-func (s *prefixedLogger) Log(msg string) {
-	fmt.Printf("%s: %s\n", s.prefix, msg)
-}
diff --git a/_examples/pprof/main.go b/_examples/pprof/main.go
deleted file mode 100644
index 47705503..00000000
--- a/_examples/pprof/main.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package main
-
-import (
-	"github.com/kataras/iris/v12"
-
-	"github.com/kataras/iris/v12/middleware/pprof"
-)
-
-func main() {
-	app := iris.New()
-
-	app.Get("/", func(ctx iris.Context) {
-		ctx.HTML("

Please click here") - }) - - p := pprof.New() - app.Any("/debug/pprof", p) - app.Any("/debug/pprof/{action:path}", p) - // ___________ - app.Listen(":8080") -} diff --git a/_examples/recover/main.go b/_examples/recover/main.go deleted file mode 100644 index 7825180d..00000000 --- a/_examples/recover/main.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - - "github.com/kataras/iris/v12/middleware/recover" -) - -func main() { - app := iris.New() - app.Use(recover.New()) - - i := 0 - // let's simulate a panic every next request - app.Get("/", func(ctx iris.Context) { - i++ - if i%2 == 0 { - panic("a panic here") - } - ctx.Writef("Hello, refresh one time more to get panic!") - }) - - // http://localhost:8080, refresh it 5-6 times. - app.Listen(":8080") -} - -// Note: -// app := iris.Default() instead of iris.New() makes use of the recovery middleware automatically. diff --git a/_examples/request-body/read-body/main.go b/_examples/request-body/read-body/main.go deleted file mode 100644 index 001edca4..00000000 --- a/_examples/request-body/read-body/main.go +++ /dev/null @@ -1,58 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := newApp() - // See main_test.go for usage. - app.Listen(":8080") -} - -func newApp() *iris.Application { - app := iris.New() - // To automatically decompress using gzip: - // app.Use(iris.GzipReader) - - app.Use(setAllowedResponses) - - app.Post("/", readBody) - - return app -} - -type payload struct { - Message string `json:"message" xml:"message" msgpack:"message" yaml:"Message" url:"message" form:"message"` -} - -func readBody(ctx iris.Context) { - var p payload - - // Bind request body to "p" depending on the content-type that client sends the data, - // e.g. JSON, XML, YAML, MessagePack, Form, URL Query. - err := ctx.ReadBody(&p) - if err != nil { - ctx.StopWithProblem(iris.StatusBadRequest, - iris.NewProblem().Title("Parser issue").Detail(err.Error())) - return - } - - // For the sake of the example, log the received payload. - ctx.Application().Logger().Infof("Received: %#+v", p) - - // Send back the payload depending on the accept content type and accept-encoding of the client, - // e.g. JSON, XML and so on. - ctx.Negotiate(p) -} - -func setAllowedResponses(ctx iris.Context) { - // Indicate that the Server can send JSON, XML, YAML and MessagePack for this request. - ctx.Negotiation().JSON().XML().YAML().MsgPack() - // Add more, allowed by the server format of responses, mime types here... - - // If client is missing an "Accept: " header then default it to JSON. - ctx.Negotiation().Accept.JSON() - - ctx.Next() -} diff --git a/_examples/request-body/read-body/main_test.go b/_examples/request-body/read-body/main_test.go deleted file mode 100644 index 6522c9ab..00000000 --- a/_examples/request-body/read-body/main_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestReadBodyAndNegotiate(t *testing.T) { - app := newApp() - - e := httptest.New(t, app) - - var ( - expectedPayload = payload{Message: "a message"} - expectedMsgPackPayload = "\x81\xa7message\xa9a message" - expectedXMLPayload = ` - a message - -` - expectedYAMLPayload = "Message: a message\n" - ) - - // Test send JSON and receive JSON. - e.POST("/").WithJSON(expectedPayload).Expect().Status(httptest.StatusOK). - JSON().Equal(expectedPayload) - - // Test send Form and receive XML. - e.POST("/").WithForm(expectedPayload). - WithHeader("Accept", "application/xml"). - Expect().Status(httptest.StatusOK). - Body().Equal(expectedXMLPayload) - - // Test send URL Query and receive MessagePack. - e.POST("/").WithQuery("message", expectedPayload.Message). - WithHeader("Accept", "application/msgpack"). - Expect().Status(httptest.StatusOK).ContentType("application/msgpack"). - Body().Equal(expectedMsgPackPayload) - - // Test send MessagePack and receive MessagePack. - e.POST("/").WithBytes([]byte(expectedMsgPackPayload)). - WithHeader("Content-Type", "application/msgpack"). - WithHeader("Accept", "application/msgpack"). - Expect().Status(httptest.StatusOK). - ContentType("application/msgpack").Body().Equal(expectedMsgPackPayload) - - // Test send YAML and receive YAML. - e.POST("/").WithBytes([]byte(expectedYAMLPayload)). - WithHeader("Content-Type", "application/x-yaml"). - WithHeader("Accept", "application/x-yaml"). - Expect().Status(httptest.StatusOK). - ContentType("application/x-yaml").Body().Equal(expectedYAMLPayload) -} diff --git a/_examples/request-body/read-custom-per-type/main.go b/_examples/request-body/read-custom-per-type/main.go deleted file mode 100644 index e60b3429..00000000 --- a/_examples/request-body/read-custom-per-type/main.go +++ /dev/null @@ -1,64 +0,0 @@ -package main - -import ( - "gopkg.in/yaml.v3" - - "github.com/kataras/iris/v12" -) - -func main() { - app := newApp() - - // use Postman or whatever to do a POST request - // (however you are always free to use app.Get and GET http method requests to read body of course) - // to the http://localhost:8080 with RAW BODY: - /* - addr: localhost:8080 - serverName: Iris - */ - // - // The response should be: - // Received: main.config{Addr:"localhost:8080", ServerName:"Iris"} - app.Listen(":8080", iris.WithOptimizations) -} - -func newApp() *iris.Application { - app := iris.New() - app.Post("/", handler) - - return app -} - -// simple yaml stuff, read more at https://github.com/go-yaml/yaml -type config struct { - Addr string `yaml:"addr"` - ServerName string `yaml:"serverName"` -} - -// Decode implements the `kataras/iris/context#BodyDecoder` optional interface -// that any go type can implement in order to be self-decoded when reading the request's body. -func (c *config) Decode(body []byte) error { - return yaml.Unmarshal(body, c) -} - -func handler(ctx iris.Context) { - var c config - - // - // Note: - // second parameter is nil because our &c implements the `context#BodyDecoder` - // which has a priority over the context#Unmarshaler (which can be a more global option for reading request's body) - // see the `request-body/read-custom-via-unmarshaler/main.go` example to learn how to use the context#Unmarshaler too. - // - // Note 2: - // If you need to read the body again for any reason - // you should disable the body consumption via `app.Run(..., iris.WithoutBodyConsumptionOnUnmarshal)`. - // - - if err := ctx.UnmarshalBody(&c, nil); err != nil { - ctx.StopWithError(iris.StatusBadRequest, err) - return - } - - ctx.Writef("Received: %#+v", c) -} diff --git a/_examples/request-body/read-custom-per-type/main_test.go b/_examples/request-body/read-custom-per-type/main_test.go deleted file mode 100644 index 70b96c04..00000000 --- a/_examples/request-body/read-custom-per-type/main_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestReadCustomPerType(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - expectedResponse := `Received: main.config{Addr:"localhost:8080", ServerName:"Iris"}` - - e.POST("/").WithText("addr: localhost:8080\nserverName: Iris").Expect(). - Status(httptest.StatusOK).Body().Equal(expectedResponse) -} diff --git a/_examples/request-body/read-custom-via-unmarshaler/main.go b/_examples/request-body/read-custom-via-unmarshaler/main.go deleted file mode 100644 index ad0d1332..00000000 --- a/_examples/request-body/read-custom-via-unmarshaler/main.go +++ /dev/null @@ -1,72 +0,0 @@ -package main - -import ( - "gopkg.in/yaml.v3" - - "github.com/kataras/iris/v12" -) - -func main() { - app := newApp() - - // use Postman or whatever to do a POST request - // (however you are always free to use app.Get and GET http method requests to read body of course) - // to the http://localhost:8080 with RAW BODY: - /* - addr: localhost:8080 - serverName: Iris - */ - // - // The response should be: - // Received: main.config{Addr:"localhost:8080", ServerName:"Iris"} - app.Listen(":8080", iris.WithOptimizations) -} - -func newApp() *iris.Application { - app := iris.New() - app.Post("/", handler) - - return app -} - -// simple yaml stuff, read more at https://github.com/go-yaml/yaml -type config struct { - Addr string `yaml:"addr"` - ServerName string `yaml:"serverName"` -} - -/* -type myBodyDecoder struct{} - -var DefaultBodyDecoder = myBodyDecoder{} - -// Implements the `kataras/iris/context#Unmarshaler` but at our example -// we will use the simplest `context#UnmarshalerFunc` to pass just the yaml.Unmarshal. -// -// Can be used as: ctx.UnmarshalBody(&c, DefaultBodyDecoder) -func (r *myBodyDecoder) Unmarshal(data []byte, outPtr interface{}) error { - return yaml.Unmarshal(data, outPtr) -} -*/ - -func handler(ctx iris.Context) { - var c config - - // - // Note: - // yaml.Unmarshal already implements the `context#Unmarshaler` - // so we can use it directly, like the json.Unmarshal(ctx.ReadJSON), xml.Unmarshal(ctx.ReadXML) - // and every library which follows the best practises and is aligned with the Go standards. - // - // Note 2: - // If you need to read the body again for any reason - // you should disable the body consumption via `app.Run(..., iris.WithoutBodyConsumptionOnUnmarshal)`. - // - - if err := ctx.UnmarshalBody(&c, iris.UnmarshalerFunc(yaml.Unmarshal)); err != nil { - ctx.StopWithError(iris.StatusBadRequest, err) - return - } - - ctx.Writef("Received: %#+v", c) -} diff --git a/_examples/request-body/read-custom-via-unmarshaler/main_test.go b/_examples/request-body/read-custom-via-unmarshaler/main_test.go deleted file mode 100644 index 75efdd76..00000000 --- a/_examples/request-body/read-custom-via-unmarshaler/main_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestReadCustomViaUnmarshaler(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - expectedResponse := `Received: main.config{Addr:"localhost:8080", ServerName:"Iris"}` - - e.POST("/").WithText("addr: localhost:8080\nserverName: Iris").Expect(). - Status(httptest.StatusOK).Body().Equal(expectedResponse) -} diff --git a/_examples/request-body/read-form/main.go b/_examples/request-body/read-form/main.go deleted file mode 100644 index cb82ffe4..00000000 --- a/_examples/request-body/read-form/main.go +++ /dev/null @@ -1,47 +0,0 @@ -// package main contains an example on how to use the ReadForm, but with the same way you can do the ReadJSON & ReadJSON -package main - -import ( - "github.com/kataras/iris/v12" -) - -type Visitor struct { - Username string - Mail string - Data []string `form:"mydata"` -} - -func main() { - app := iris.New() - - // set the view html template engine - app.RegisterView(iris.HTML("./templates", ".html").Reload(true)) - - app.Get("/", func(ctx iris.Context) { - if err := ctx.View("form.html"); err != nil { - ctx.StopWithError(iris.StatusInternalServerError, err) - return - } - }) - - app.Post("/form_action", func(ctx iris.Context) { - visitor := Visitor{} - err := ctx.ReadForm(&visitor) - if err != nil { - if !iris.IsErrPath(err) /* see: https://github.com/kataras/iris/issues/1157 */ || - err == iris.ErrEmptyForm { - ctx.StopWithError(iris.StatusInternalServerError, err) - return - } - } - - ctx.Writef("Visitor: %#v", visitor) - }) - - app.Post("/post_value", func(ctx iris.Context) { - username := ctx.PostValueDefault("Username", "iris") - ctx.Writef("Username: %s", username) - }) - - app.Listen(":8080", iris.WithEmptyFormError /* returns ErrEmptyForm if the request form body was empty */) -} diff --git a/_examples/request-body/read-form/templates/form.html b/_examples/request-body/read-form/templates/form.html deleted file mode 100644 index 7f85b962..00000000 --- a/_examples/request-body/read-form/templates/form.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - -
- Username:
- Mail:
- Select one or more:
- - -
- - -
- - diff --git a/_examples/request-body/read-json-struct-validation/main.go b/_examples/request-body/read-json-struct-validation/main.go deleted file mode 100644 index 29493183..00000000 --- a/_examples/request-body/read-json-struct-validation/main.go +++ /dev/null @@ -1,146 +0,0 @@ -// Package main shows the validator(latest, version 10) integration with Iris' Context methods of -// `ReadJSON`, `ReadXML`, `ReadMsgPack`, `ReadYAML`, `ReadForm`, `ReadQuery`, `ReadBody`. -// -// You can find more examples of this 3rd-party library at: -// https://github.com/go-playground/validator/blob/master/_examples -package main - -import ( - "fmt" - - "github.com/kataras/iris/v12" - - // $ go get github.com/go-playground/validator/v10@latest - "github.com/go-playground/validator/v10" -) - -func main() { - app := iris.New() - app.Validator = validator.New() - - userRouter := app.Party("/user") - { - userRouter.Get("/validation-errors", resolveErrorsDocumentation) - userRouter.Post("/", postUser) - } - - // Use Postman or any tool to perform a POST request - // to the http://localhost:8080/user with RAW BODY of: - /* - { - "fname": "", - "lname": "", - "age": 45, - "email": "mail@example.com", - "favColor": "#000", - "addresses": [{ - "street": "Eavesdown Docks", - "planet": "Persphone", - "phone": "none", - "city": "Unknown" - }] - } - */ - /* The response should be: - { - "title": "Validation error", - "detail": "One or more fields failed to be validated", - "type": "http://localhost:8080/user/validation-errors", - "status": 400, - "fields": [ - { - "tag": "required", - "namespace": "User.FirstName", - "kind": "string", - "type": "string", - "value": "", - "param": "" - }, - { - "tag": "required", - "namespace": "User.LastName", - "kind": "string", - "type": "string", - "value": "", - "param": "" - } - ] - } - */ - app.Listen(":8080") -} - -// User contains user information. -type User struct { - FirstName string `json:"fname" validate:"required"` - LastName string `json:"lname" validate:"required"` - Age uint8 `json:"age" validate:"gte=0,lte=130"` - Email string `json:"email" validate:"required,email"` - FavouriteColor string `json:"favColor" validate:"hexcolor|rgb|rgba"` - Addresses []*Address `json:"addresses" validate:"required,dive,required"` // a User can have a home and cottage... -} - -// Address houses a users address information. -type Address struct { - Street string `json:"street" validate:"required"` - City string `json:"city" validate:"required"` - Planet string `json:"planet" validate:"required"` - Phone string `json:"phone" validate:"required"` -} - -type validationError struct { - ActualTag string `json:"tag"` - Namespace string `json:"namespace"` - Kind string `json:"kind"` - Type string `json:"type"` - Value string `json:"value"` - Param string `json:"param"` -} - -func wrapValidationErrors(errs validator.ValidationErrors) []validationError { - validationErrors := make([]validationError, 0, len(errs)) - for _, validationErr := range errs { - validationErrors = append(validationErrors, validationError{ - ActualTag: validationErr.ActualTag(), - Namespace: validationErr.Namespace(), - Kind: validationErr.Kind().String(), - Type: validationErr.Type().String(), - Value: fmt.Sprintf("%v", validationErr.Value()), - Param: validationErr.Param(), - }) - } - - return validationErrors -} - -func postUser(ctx iris.Context) { - var user User - err := ctx.ReadJSON(&user) - if err != nil { - // Handle the error, below you will find the right way to do that... - - if errs, ok := err.(validator.ValidationErrors); ok { - // Wrap the errors with JSON format, the underline library returns the errors as interface. - validationErrors := wrapValidationErrors(errs) - - // Fire an application/json+problem response and stop the handlers chain. - ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem(). - Title("Validation error"). - Detail("One or more fields failed to be validated"). - Type("/user/validation-errors"). - Key("errors", validationErrors)) - - return - } - - // It's probably an internal JSON error, let's dont give more info here. - ctx.StopWithStatus(iris.StatusInternalServerError) - return - } - - ctx.JSON(iris.Map{"message": "OK"}) -} - -func resolveErrorsDocumentation(ctx iris.Context) { - ctx.WriteString("A page that should document to web developers or users of the API on how to resolve the validation errors") -} diff --git a/_examples/request-body/read-json/main.go b/_examples/request-body/read-json/main.go deleted file mode 100644 index fee580f5..00000000 --- a/_examples/request-body/read-json/main.go +++ /dev/null @@ -1,62 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -type Company struct { - Name string - City string - Other string -} - -func MyHandler(ctx iris.Context) { - var c Company - - if err := ctx.ReadJSON(&c); err != nil { - ctx.StopWithError(iris.StatusBadRequest, err) - return - } - - ctx.Writef("Received: %#+v\n", c) -} - -// simple json stuff, read more at https://golang.org/pkg/encoding/json -type Person struct { - Name string `json:"name"` - Age int `json:"age"` -} - -// MyHandler2 reads a collection of Person from JSON post body. -func MyHandler2(ctx iris.Context) { - var persons []Person - err := ctx.ReadJSON(&persons) - if err != nil { - ctx.StopWithError(iris.StatusBadRequest, err) - return - } - - ctx.Writef("Received: %#+v\n", persons) -} - -func main() { - app := iris.New() - - app.Post("/", MyHandler) - app.Post("/slice", MyHandler2) - - // use Postman or whatever to do a POST request - // to the http://localhost:8080 with RAW BODY: - /* - { - "Name": "iris-Go", - "City": "New York", - "Other": "Something here" - } - */ - // and Content-Type to application/json (optionally but good practise) - // - // The response should be: - // Received: main.Company{Name:"iris-Go", City:"New York", Other:"Something here"} - app.Listen(":8080", iris.WithOptimizations) -} diff --git a/_examples/request-body/read-many/main.go b/_examples/request-body/read-many/main.go deleted file mode 100644 index cc22d775..00000000 --- a/_examples/request-body/read-many/main.go +++ /dev/null @@ -1,60 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.Post("/", logAllBody, logJSON, logFormValues, func(ctx iris.Context) { - // body, err := ioutil.ReadAll(ctx.Request().Body) once or - body, err := ctx.GetBody() // as many times as you need. - if err != nil { - ctx.StopWithError(iris.StatusInternalServerError, err) - return - } - - if len(body) == 0 { - ctx.WriteString(`The body was empty -or iris.WithoutBodyConsumptionOnUnmarshal option is missing from app.Run. -Check the terminal window for any queries logs.`) - } else { - ctx.WriteString("OK body is still:\n") - ctx.Write(body) - } - }) - - // With ctx.UnmarshalBody, ctx.ReadJSON, ctx.ReadXML, ctx.ReadForm, ctx.FormValues - // and ctx.GetBody methods the default golang and net/http behavior - // is to consume the readen data - they are not available on any next handlers in the chain - - // to change that behavior just pass the `WithoutBodyConsumptionOnUnmarshal` option. - app.Listen(":8080", iris.WithoutBodyConsumptionOnUnmarshal) -} - -func logAllBody(ctx iris.Context) { - body, err := ctx.GetBody() - if err == nil && len(body) > 0 { - ctx.Application().Logger().Infof("logAllBody: %s", string(body)) - } - - ctx.Next() -} - -func logJSON(ctx iris.Context) { - var p interface{} - if err := ctx.ReadJSON(&p); err == nil { - ctx.Application().Logger().Infof("logJSON: %#+v", p) - } - - ctx.Next() -} - -func logFormValues(ctx iris.Context) { - values := ctx.FormValues() - if values != nil { - ctx.Application().Logger().Infof("logFormValues: %v", values) - } - - ctx.Next() -} diff --git a/_examples/request-body/read-msgpack/main.go b/_examples/request-body/read-msgpack/main.go deleted file mode 100644 index 4a4e92b5..00000000 --- a/_examples/request-body/read-msgpack/main.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -// User example struct to bind to. -type User struct { - Firstname string `msgpack:"firstname"` - Lastname string `msgpack:"lastname"` - City string `msgpack:"city"` - Age int `msgpack:"age"` -} - -// readMsgPack reads a `User` from MsgPack post body. -func readMsgPack(ctx iris.Context) { - var u User - err := ctx.ReadMsgPack(&u) - if err != nil { - ctx.StopWithError(iris.StatusBadRequest, err) - return - } - - ctx.Writef("Received: %#+v\n", u) -} - -func main() { - app := iris.New() - app.Post("/", readMsgPack) - - // POST: http://localhost:8080 - // - // To run the example, use a tool like Postman: - // 1. Body: Binary - // 2. Select File, select the one from "_examples/response-writer/write-rest" example. - // The output should be: - // Received: main.User{Firstname:"John", Lastname:"Doe", City:"Neither FBI knows!!!", Age:25} - app.Listen(":8080") -} diff --git a/_examples/request-body/read-query/main.go b/_examples/request-body/read-query/main.go deleted file mode 100644 index ca0975dd..00000000 --- a/_examples/request-body/read-query/main.go +++ /dev/null @@ -1,30 +0,0 @@ -// package main contains an example on how to use the ReadQuery, -// same way you can do the ReadJSON & ReadProtobuf and e.t.c. -package main - -import ( - "github.com/kataras/iris/v12" -) - -type MyType struct { - Name string `url:"name"` - Age int `url:"age"` -} - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - var t MyType - err := ctx.ReadQuery(&t) - if err != nil && !iris.IsErrPath(err) { - ctx.StopWithError(iris.StatusInternalServerError, err) - return - } - - ctx.Writef("MyType: %#v", t) - }) - - // http://localhost:8080?name=iris&age=3 - app.Listen(":8080") -} diff --git a/_examples/request-body/read-xml/main.go b/_examples/request-body/read-xml/main.go deleted file mode 100644 index 9b42e9ae..00000000 --- a/_examples/request-body/read-xml/main.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import ( - "encoding/xml" - - "github.com/kataras/iris/v12" -) - -func main() { - app := newApp() - - // use Postman or whatever to do a POST request - // to the http://localhost:8080 with RAW BODY: - /* - - Description of this person, the body of this inner element. - - */ - // and Content-Type to application/xml (optionally but good practise) - // - // The response should be: - // Received: main.person{XMLName:xml.Name{Space:"", Local:"person"}, Name:"Winston Churchill", Age:90, Description:"Description of this person, the body of this inner element."} - app.Listen(":8080", iris.WithOptimizations) -} - -func newApp() *iris.Application { - app := iris.New() - app.Post("/", handler) - - return app -} - -// simple xml stuff, read more at https://golang.org/pkg/encoding/xml -type person struct { - XMLName xml.Name `xml:"person"` // element name - Name string `xml:"name,attr"` // ,attr for attribute. - Age int `xml:"age,attr"` // ,attr attribute. - Description string `xml:"description"` // inner element name, value is its body. -} - -func handler(ctx iris.Context) { - var p person - if err := ctx.ReadXML(&p); err != nil { - ctx.StopWithError(iris.StatusBadRequest, err) - return - } - - ctx.Writef("Received: %#+v", p) -} diff --git a/_examples/request-body/read-xml/main_test.go b/_examples/request-body/read-xml/main_test.go deleted file mode 100644 index 3fa36b31..00000000 --- a/_examples/request-body/read-xml/main_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestReadXML(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - expectedResponse := `Received: main.person{XMLName:xml.Name{Space:"", Local:"person"}, Name:"Winston Churchill", Age:90, Description:"Description of this person, the body of this inner element."}` - send := `Description of this person, the body of this inner element.` - - e.POST("/").WithText(send).Expect(). - Status(httptest.StatusOK).Body().Equal(expectedResponse) -} diff --git a/_examples/request-body/read-yaml/main.go b/_examples/request-body/read-yaml/main.go deleted file mode 100644 index b353e94c..00000000 --- a/_examples/request-body/read-yaml/main.go +++ /dev/null @@ -1,35 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func newApp() *iris.Application { - app := iris.New() - app.Post("/", handler) - - return app -} - -// simple yaml stuff, read more at https://yaml.org/start.html -type product struct { - Invoice int `yaml:"invoice"` - Tax float32 `yaml:"tax"` - Total float32 `yaml:"total"` - Comments string `yaml:"comments"` -} - -func handler(ctx iris.Context) { - var p product - if err := ctx.ReadYAML(&p); err != nil { - ctx.StopWithError(iris.StatusBadRequest, err) - return - } - - ctx.Writef("Received: %#+v", p) -} - -func main() { - app := newApp() - app.Listen(":8080") -} diff --git a/_examples/request-body/read-yaml/main_test.go b/_examples/request-body/read-yaml/main_test.go deleted file mode 100644 index 644ba558..00000000 --- a/_examples/request-body/read-yaml/main_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestReadYAML(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - expectedResponse := `Received: main.product{Invoice:34843, Tax:251.42, Total:4443.52, Comments:"Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338."}` - send := `invoice: 34843 -tax : 251.42 -total: 4443.52 -comments: > - Late afternoon is best. - Backup contact is Nancy - Billsmer @ 338-4338.` - - e.POST("/").WithHeader("Content-Type", "application/x-yaml").WithBytes([]byte(send)).Expect(). - Status(httptest.StatusOK).Body().Equal(expectedResponse) -} diff --git a/_examples/request-ratelimit/main.go b/_examples/request-ratelimit/main.go deleted file mode 100644 index 84629524..00000000 --- a/_examples/request-ratelimit/main.go +++ /dev/null @@ -1,90 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/rate" -) - -func main() { - app := newApp() - app.Logger().SetLevel("debug") - - // * http://localhost:8080/v1 - // * http://localhost:8080/v1/other - // * http://localhost:8080/v2/list (with X-API-Key request header) - // Read more at: https://en.wikipedia.org/wiki/Token_bucket - // - // Alternatives: - // * https://github.com/iris-contrib/middleware/blob/master/throttler/_example/main.go - // Read more at: https://en.wikipedia.org/wiki/Generic_cell_rate_algorithm - // * https://github.com/iris-contrib/middleware/tree/master/tollboothic/_examples/limit-handler - app.Listen(":8080") -} - -func newApp() *iris.Application { - app := iris.New() - - v1 := app.Party("/v1") - { - // Register the rate limiter middleware at the "/v1" subrouter. - // - // Fist and second input parameters: - // Allow 1 request per second, with a maximum burst size of 5. - // - // Third optional variadic input parameter: - // Can be a cleanup function. - // Iris provides a cleanup function that will check for old entries and remove them. - // You can customize it, e.g. check every 1 minute - // if a client's last visit was 5 minutes ago ("old" entry) - // and remove it from the memory. - limitV1 := rate.Limit(1, 5, rate.PurgeEvery(time.Minute, 5*time.Minute)) - // rate.Every helper: - // rate.Limit(rate.Every(time.Minute), 5) - v1.Use(limitV1) - - v1.Get("/", index) - v1.Get("/other", other) - } - - v2 := app.Party("/v2") - { - v2.Use(useAPIKey) - // Initialize a new rate limit middleware to limit requests - // per API Key(see `useAPIKey` below) instead of client's Remote IP Address. - limitV2 := rate.Limit(rate.Every(time.Minute), 300, rate.PurgeEvery(5*time.Minute, 15*time.Minute)) - v2.Use(limitV2) - - v2.Get("/list", list) - } - - return app -} - -func useAPIKey(ctx iris.Context) { - apiKey := ctx.GetHeader("X-API-Key") - if apiKey == "" { // [validate your API Key here...] - ctx.StopWithStatus(iris.StatusForbidden) - return - } - - // Change the method that rate limit matches the requests with a specific user - // and set our own api key as theirs identifier. - rate.SetIdentifier(ctx, apiKey) - ctx.Next() -} - -func list(ctx iris.Context) { - ctx.JSON(iris.Map{"key": "value"}) -} - -func index(ctx iris.Context) { - ctx.HTML("

Index Page

") -} - -func other(ctx iris.Context) { - ctx.HTML("

Other Page

") -} - -// Note: Use `ctx.SendFileWithRate` to use a download rate limiter instead. diff --git a/_examples/request-referrer/main.go b/_examples/request-referrer/main.go deleted file mode 100644 index adfbe3b7..00000000 --- a/_examples/request-referrer/main.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - // GetReferrer extracts and returns the information from the "Referer" (or "Referrer") header - // and url query parameter as specified in https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy. - r := ctx.GetReferrer() - switch r.Type { - case iris.ReferrerSearch: - ctx.Writef("Search %s: %s\n", r.Label, r.Query) - ctx.Writef("Google: %s\n", r.GoogleType) - case iris.ReferrerSocial: - ctx.Writef("Social %s\n", r.Label) - case iris.ReferrerIndirect: - ctx.Writef("Indirect: %s\n", r.URL) - } - }) - - // http://localhost:8080?referrer=https://twitter.com/Xinterio/status/1023566830974251008 - // http://localhost:8080?referrer=https://www.google.com/search?q=Top+6+golang+web+frameworks&oq=Top+6+golang+web+frameworks - app.Listen(":8080") -} diff --git a/_examples/response-writer/cache/client-side/main.go b/_examples/response-writer/cache/client-side/main.go deleted file mode 100644 index f460b463..00000000 --- a/_examples/response-writer/cache/client-side/main.go +++ /dev/null @@ -1,39 +0,0 @@ -// Package main shows how you can use the `WriteWithExpiration` -// based on the "modtime", if it's newer than the request header then -// it will refresh the contents, otherwise will let the client (99.9% the browser) -// to handle the cache mechanism, it's faster than iris.Cache because server-side -// has nothing to do and no need to store the responses in the memory. -package main - -import ( - "time" - - "github.com/kataras/iris/v12" -) - -const refreshEvery = 10 * time.Second - -func main() { - app := iris.New() - app.Use(iris.Cache304(refreshEvery)) - // same as: - // app.Use(func(ctx iris.Context) { - // now := time.Now() - // if modified, err := ctx.CheckIfModifiedSince(now.Add(-refresh)); !modified && err == nil { - // ctx.WriteNotModified() - // return - // } - - // ctx.SetLastModified(now) - - // ctx.Next() - // }) - - app.Get("/", greet) - app.Listen(":8080") -} - -func greet(ctx iris.Context) { - ctx.Header("X-Custom", "my custom header") - ctx.Writef("Hello World! %s", time.Now()) -} diff --git a/_examples/response-writer/cache/simple/main.go b/_examples/response-writer/cache/simple/main.go deleted file mode 100644 index 010c3511..00000000 --- a/_examples/response-writer/cache/simple/main.go +++ /dev/null @@ -1,80 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12" - - "github.com/kataras/iris/v12/cache" -) - -var markdownContents = []byte(`## Hello Markdown - -This is a sample of Markdown contents - - - -Features --------- - -All features of Sundown are supported, including: - -* **Compatibility**. The Markdown v1.0.3 test suite passes with - the --tidy option. Without --tidy, the differences are - mostly in whitespace and entity escaping, where blackfriday is - more consistent and cleaner. - -* **Common extensions**, including table support, fenced code - blocks, autolinks, strikethroughs, non-strict emphasis, etc. - -* **Safety**. Blackfriday is paranoid when parsing, making it safe - to feed untrusted user input without fear of bad things - happening. The test suite stress tests this and there are no - known inputs that make it crash. If you find one, please let me - know and send me the input that does it. - - NOTE: "safety" in this context means *runtime safety only*. In order to - protect yourself against JavaScript injection in untrusted content, see - [this example](https://github.com/russross/blackfriday#sanitize-untrusted-content). - -* **Fast processing**. It is fast enough to render on-demand in - most web applications without having to cache the output. - -* **Routine safety**. You can run multiple parsers in different - goroutines without ill effect. There is no dependence on global - shared state. - -* **Minimal dependencies**. Blackfriday only depends on standard - library packages in Go. The source code is pretty - self-contained, so it is easy to add to any project, including - Google App Engine projects. - -* **Standards compliant**. Output successfully validates using the - W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional. - - [this is a link](https://github.com/kataras/iris) `) - -// Cache should not be used on handlers that contain dynamic data. -// Cache is a good and a must-feature on static content, i.e "about page" or for a whole blog site. -func main() { - app := iris.New() - app.Logger().SetLevel("debug") - app.Get("/", cache.Handler(10*time.Second), writeMarkdown) - // saves its content on the first request and serves it instead of re-calculating the content. - // After 10 seconds it will be cleared and reset. - - app.Listen(":8080") -} - -func writeMarkdown(ctx iris.Context) { - // tap multiple times the browser's refresh button and you will - // see this println only once every 10 seconds. - println("Handler executed. Content refreshed.") - - ctx.Markdown(markdownContents) -} - -/* Note that `HandleDir` does use the browser's disk caching by-default -therefore, register the cache handler AFTER any HandleDir calls, -for a faster solution that server doesn't need to keep track of the response -navigate to https://github.com/kataras/iris/blob/master/_examples/cache/client-side/main.go */ diff --git a/_examples/response-writer/content-negotiation/main.go b/_examples/response-writer/content-negotiation/main.go deleted file mode 100644 index d5619e1d..00000000 --- a/_examples/response-writer/content-negotiation/main.go +++ /dev/null @@ -1,114 +0,0 @@ -// Package main contains three different ways to render content based on the client's accepted. -package main - -import "github.com/kataras/iris/v12" - -type testdata struct { - Name string `json:"name" xml:"Name"` - Age int `json:"age" xml:"Age"` -} - -func newApp() *iris.Application { - app := iris.New() - app.Logger().SetLevel("debug") - - // app.Use(func(ctx iris.Context) { - // requestedMime := ctx.URLParamDefault("type", "application/json") - // - // ctx.Negotiation().Accept.Override().MIME(requestedMime, nil) - // ctx.Next() - // }) - - app.Get("/resource", func(ctx iris.Context) { - data := testdata{ - Name: "test name", - Age: 26, - } - - // Server allows response only JSON and XML. These values - // are compared with the clients mime needs. Iris comes with default mime types responses - // but you can add a custom one by the `Negotiation().Mime(mime, content)` method, - // same for the "accept". - // You can also pass a custom ContentSelector(mime string) or ContentNegotiator to the - // `Context.Negotiate` method if you want to perform more advanced things. - // - // - // By-default the client accept mime is retrieved by the "Accept" header - // Indeed you can override or update it by `Negotiation().Accept.XXX` i.e - // ctx.Negotiation().Accept.Override().XML() - // - // All these values can change inside middlewares, the `Negotiation().Override()` and `.Accept.Override()` - // can override any previously set values. - // Order matters, if the client accepts anything (*/*) - // then the first prioritized mime's response data will be rendered. - ctx.Negotiation().JSON().XML() - // Accept-Charset vs: - ctx.Negotiation().Charset("utf-8", "iso-8859-7") - // Alternatively you can define the content/data per mime type - // anywhere in the handlers chain using the optional "v" variadic - // input argument of the Context.Negotiation().JSON,XML,YAML,Binary,Text,HTML(...) and e.t.c - // example (order matters): - // ctx.Negotiation().JSON(data).XML(data).Any("content for */*") - // ctx.Negotiate(nil) - - // if not nil passed in the `Context.Negotiate` method - // then it overrides any contents made by the negotitation builder above. - _, err := ctx.Negotiate(data) - if err != nil { - ctx.Writef("%v", err) - } - }) - - app.Get("/resource2", func(ctx iris.Context) { - jsonAndXML := testdata{ - Name: "test name", - Age: 26, - } - - // I prefer that one, as it gives me the freedom to modify - // response data per accepted mime content type on middlewares as well. - ctx.Negotiation(). - JSON(jsonAndXML). - XML(jsonAndXML). - HTML("

Test Name

Age 26

") - - ctx.Negotiate(nil) - }) - - app.Get("/resource3", func(ctx iris.Context) { - // If that line is missing and the requested - // mime type of content is */* or application/xml or application/json - // then 406 Not Acceptable http error code will be rendered instead. - // - // We also add the "gzip" algorithm as an option to encode - // resources on send. - ctx.Negotiation().JSON().XML().HTML().EncodingGzip() - - jsonAndXML := testdata{ - Name: "test name", - Age: 26, - } - - // Prefer that way instead of the '/resource2' above - // if "iris.N" is a static one and can be declared - // outside of a handler. - ctx.Negotiate(iris.N{ - // Text: for text/plain, - // Markdown: for text/mardown, - // Binary: for application/octet-stream, - // YAML: for application/x-yaml, - // JSONP: for text/javascript - // Other: for anything else, - JSON: jsonAndXML, // for application/json - XML: jsonAndXML, // for application/xml or text/xml - HTML: "

Test Name

Age 26

", // for text/html - }) - }) - - return app -} - -func main() { - app := newApp() - app.Listen(":8080") -} diff --git a/_examples/response-writer/content-negotiation/main_test.go b/_examples/response-writer/content-negotiation/main_test.go deleted file mode 100644 index 08c5e5a6..00000000 --- a/_examples/response-writer/content-negotiation/main_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package main - -import ( - "bytes" - "compress/gzip" - "encoding/xml" - "io/ioutil" - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/httptest" -) - -func TestContentNegotiation(t *testing.T) { - var ( - expectedJSONResponse = testdata{ - Name: "test name", - Age: 26, - } - expectedXMLResponse, _ = xml.Marshal(expectedJSONResponse) - expectedHTMLResponse = "

Test Name

Age 26

" - ) - - app := newApp() - app.Configure(iris.WithOptimizations) - e := httptest.New(t, app) - - e.GET("/resource").WithHeader("Accept", "application/json"). - Expect().Status(httptest.StatusOK). - ContentType("application/json", "utf-8"). - JSON().Equal(expectedJSONResponse) - e.GET("/resource").WithHeader("Accept", "application/xml").WithHeader("Accept-Charset", "iso-8859-7"). - Expect().Status(httptest.StatusOK). - ContentType("application/xml", "iso-8859-7"). - Body().Equal(string(expectedXMLResponse)) - - e.GET("/resource2").WithHeader("Accept", "application/json"). - Expect().Status(httptest.StatusOK). - ContentType("application/json", "utf-8"). - JSON().Equal(expectedJSONResponse) - e.GET("/resource2").WithHeader("Accept", "application/xml"). - Expect().Status(httptest.StatusOK). - ContentType("application/xml", "utf-8"). - Body().Equal(string(expectedXMLResponse)) - e.GET("/resource2").WithHeader("Accept", "text/html"). - Expect().Status(httptest.StatusOK). - ContentType("text/html", "utf-8"). - Body().Equal(expectedHTMLResponse) - - e.GET("/resource3").WithHeader("Accept", "application/json"). - Expect().Status(httptest.StatusOK). - ContentType("application/json", "utf-8"). - JSON().Equal(expectedJSONResponse) - e.GET("/resource3").WithHeader("Accept", "application/xml"). - Expect().Status(httptest.StatusOK). - ContentType("application/xml", "utf-8"). - Body().Equal(string(expectedXMLResponse)) - - // test html with "gzip" encoding algorithm. - rawGzipResponse := e.GET("/resource3").WithHeader("Accept", "text/html"). - WithHeader("Accept-Encoding", "gzip"). - Expect().Status(httptest.StatusOK). - ContentType("text/html", "utf-8"). - ContentEncoding("gzip"). - Body().Raw() - - zr, err := gzip.NewReader(bytes.NewReader([]byte(rawGzipResponse))) - if err != nil { - t.Fatal(err) - } - - rawResponse, err := ioutil.ReadAll(zr) - if err != nil { - t.Fatal(err) - } - - if expected, got := expectedHTMLResponse, string(rawResponse); expected != got { - t.Fatalf("expected response to be:\n%s but got:\n%s", expected, got) - } -} diff --git a/_examples/response-writer/http2push/main.go b/_examples/response-writer/http2push/main.go deleted file mode 100644 index f6b9f4d9..00000000 --- a/_examples/response-writer/http2push/main.go +++ /dev/null @@ -1,47 +0,0 @@ -// Server push lets the server preemptively "push" website assets -// to the client without the user having explicitly asked for them. -// When used with care, we can send what we know the user is going -// to need for the page they're requesting. -package main - -import ( - "net/http" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - app.Get("/", pushHandler) - app.Get("/main.js", simpleAssetHandler) - - app.Run(iris.TLS("127.0.0.1:443", "mycert.crt", "mykey.key")) - // $ openssl req -new -newkey rsa:4096 -x509 -sha256 \ - // -days 365 -nodes -out mycert.crt -keyout mykey.key -} - -func pushHandler(ctx iris.Context) { - // The target must either be an absolute path (like "/path") or an absolute - // URL that contains a valid host and the same scheme as the parent request. - // If the target is a path, it will inherit the scheme and host of the - // parent request. - target := "/main.js" - - if pusher, ok := ctx.ResponseWriter().Naive().(http.Pusher); ok { - err := pusher.Push(target, nil) - if err != nil { - if err == iris.ErrPushNotSupported { - ctx.StopWithText(iris.StatusHTTPVersionNotSupported, "HTTP/2 push not supported.") - } else { - ctx.StopWithError(iris.StatusInternalServerError, err) - } - return - } - } - - ctx.HTML(``, target) -} - -func simpleAssetHandler(ctx iris.Context) { - ctx.ServeFile("./public/main.js") -} diff --git a/_examples/response-writer/http2push/mycert.crt b/_examples/response-writer/http2push/mycert.crt deleted file mode 100644 index 9db93b09..00000000 --- a/_examples/response-writer/http2push/mycert.crt +++ /dev/null @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIUfwMd9auWixp19UnXOmyxJ9Jkv7IwDQYJKoZIhvcNAQEL -BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM -GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA2MjUwOTUxNDdaFw0yMTA2 -MjUwOTUxNDdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw -HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQDlVGyGAQ9uyfNbwZyrtYOSjLpxf5NpNToh2OzU7gy2 -OexBji5lmWBQ3oYDG+FjAkbHORPzOMNpeMwje+IjGZBw8x6E+8WoGdSzbrEZ6pUV -wKJGKEuDlx6g6HEmtv3ZwgGe20gvPjjW+oCO888dwK/mbIHrHTq4nO3o0gAdAJwu -amn9BlHU5O4RW7BQ4tLF+j/fBCACWRG1NHXA0AT8eg544GyCdyteAH11oCDsHS8/ -DAPsM6t+tZrMCIt9+9dzPdVoOmQNaMMrcz8eJohddRTK6zHe9ixZTt/soayOF7OS -QQeekbr3HPYhD450zRVplLMHx7wnph/+O+Po6bqDnUzdnkqAAwwymQapHMuHXZKN -rhdfKau3rVo1GeXLIRgeWLUoxFSm4TYshrgt+0AidLRH+dCY7MS9Ngga/sAK3vID -gSF75mFgOhY+q7nvY9Ecao6TnoNNRY29hUat4y0VwSyysUy887vHr6lMK5CrAT/l -Ch8fuu20HUCoiLwMJvA6+wpivZkuiIvWY7bVGYsEYrrW+bCNN9wCGYTZEyX++os9 -v/38wdOqGUT00ewXkjIUFCWbrnxxSr98kF3w3wPf9K4Y40MNxeR90nyX4zjXGF1/ -91msUh+iivsz9mcN9DK83fgTyOsoVLX5cm/L2UBwMacsfjBbN4djOc5IuYMar/VN -GQIDAQABo1MwUTAdBgNVHQ4EFgQUtkf+yAvqgZC8f22iJny9hFEDolMwHwYDVR0j -BBgwFoAUtkf+yAvqgZC8f22iJny9hFEDolMwDwYDVR0TAQH/BAUwAwEB/zANBgkq -hkiG9w0BAQsFAAOCAgEAE2QasBVru618rxupyJgEHw6r4iv7sz1Afz3Q5qJ4oSA9 -xVsrVCjr3iHRFSw8Rf670E8Ffk/JjzS65mHw6zeZj/ANBKQWLjRlqzYXeetq5HzG -SIgaG7p1RFvvzz3+leFGzjinZ6sKbfB4OB72o2YN+fO8DsDxgGKll0W4KAazizSe -HY9Pgu437tWnwF16rFO3IL47n5HzYlRoGIPOpzFoNX5+fyn9GlnKEtONF2QBKTjY -rdjvqFRByDiC74d8z/Yx8IiDRn1mTcG90JLR9+c6M7fruha9Y/rJfw+4AhVh5ZDz -Bl9rGPjwEs5zwutYvVAJzs7AVcighYP1lHKoJ7DxBDQeyBsYlUNk2l6bmZgLgGUZ -+2OyWlqc/jD2GdDsIaZ4i7QqhTI/6aYZIf5zUkblKV1aMSaDulKxRv//OwW28Jax -9EEoV7VaFb3sOkB/tZGhusXeQVtdrhahT3KkZLNwmNXoXWKJ5LjeUlFWJyV6JbDe -y/PIWWCwWqyuFCSZS+Cg3RDgAzfSxkI8uVZ+IKKJS3UluDX45lxXtbRrvTQ+oDrA -6ga5c1Vz9C4kn1K5yW4d7QIvg6vPiy7gvl+//sz9oxUM3yswInDBY0HKLgT0Uq9b -YzLDh2RSaHsgHMPy2BKqR+q2N+lpg7inAWuJM1Huq6eHFqhiyQkzsfscBd1Dpm8= ------END CERTIFICATE----- diff --git a/_examples/response-writer/http2push/mykey.key b/_examples/response-writer/http2push/mykey.key deleted file mode 100644 index 39f7b3af..00000000 --- a/_examples/response-writer/http2push/mykey.key +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -W2TzuSMYNDu876twbTVQJED3mwOAQ3J7 ------END PRIVATE KEY----- diff --git a/_examples/response-writer/http2push/public/main.js b/_examples/response-writer/http2push/public/main.js deleted file mode 100644 index 2aae6c4c..00000000 --- a/_examples/response-writer/http2push/public/main.js +++ /dev/null @@ -1 +0,0 @@ -window.alert("javascript loaded"); \ No newline at end of file diff --git a/_examples/response-writer/protobuf/README.md b/_examples/response-writer/protobuf/README.md deleted file mode 100644 index 4c69034c..00000000 --- a/_examples/response-writer/protobuf/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Protocol Buffers - -The `Context.Protobuf(proto.Message)` is the method which sends protos to the client. It accepts a [proto.Message](https://godoc.org/google.golang.org/protobuf/proto#Message) value. - -> Note: Iris is using the newest version of the Go protocol buffers implementation. Read more about it at [The Go Blog: A new Go API for Protocol Buffers](https://blog.golang.org/protobuf-apiv2). - - -1. Install the protoc-gen-go tool. - -```sh -$ go get -u google.golang.org/protobuf/cmd/protoc-gen-go@latest -``` - -2. Generate proto - -```sh -$ protoc -I protos/ protos/hello.proto --go_out=. -``` diff --git a/_examples/response-writer/protobuf/go.mod b/_examples/response-writer/protobuf/go.mod deleted file mode 100644 index 366f0b14..00000000 --- a/_examples/response-writer/protobuf/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module app - -go 1.15 diff --git a/_examples/response-writer/protobuf/main.go b/_examples/response-writer/protobuf/main.go deleted file mode 100644 index 8996c813..00000000 --- a/_examples/response-writer/protobuf/main.go +++ /dev/null @@ -1,60 +0,0 @@ -package main - -import ( - "app/protos" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.Get("/", send) - app.Get("/json", sendAsJSON) - app.Post("/read", read) - app.Post("/read_json", readFromJSON) - - app.Listen(":8080") -} - -func send(ctx iris.Context) { - response := &protos.HelloReply{Message: "Hello, World!"} - ctx.Protobuf(response) -} - -func sendAsJSON(ctx iris.Context) { - response := &protos.HelloReply{Message: "Hello, World!"} - options := iris.JSON{ - Proto: iris.ProtoMarshalOptions{ - AllowPartial: true, - Multiline: true, - Indent: " ", - }, - } - - ctx.JSON(response, options) -} - -func read(ctx iris.Context) { - var request protos.HelloRequest - - err := ctx.ReadProtobuf(&request) - if err != nil { - ctx.StopWithError(iris.StatusBadRequest, err) - return - } - - ctx.Writef("HelloRequest.Name = %s", request.Name) -} - -func readFromJSON(ctx iris.Context) { - var request protos.HelloRequest - - err := ctx.ReadJSONProtobuf(&request) - if err != nil { - ctx.StopWithError(iris.StatusBadRequest, err) - return - } - - ctx.Writef("HelloRequest.Name = %s", request.Name) -} diff --git a/_examples/response-writer/protobuf/protos/hello.pb.go b/_examples/response-writer/protobuf/protos/hello.pb.go deleted file mode 100644 index ee512210..00000000 --- a/_examples/response-writer/protobuf/protos/hello.pb.go +++ /dev/null @@ -1,209 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.25.0 -// protoc v3.11.1 -// source: hello.proto - -package protos - -import ( - proto "github.com/golang/protobuf/proto" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -type HelloRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` -} - -func (x *HelloRequest) Reset() { - *x = HelloRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_hello_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *HelloRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HelloRequest) ProtoMessage() {} - -func (x *HelloRequest) ProtoReflect() protoreflect.Message { - mi := &file_hello_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead. -func (*HelloRequest) Descriptor() ([]byte, []int) { - return file_hello_proto_rawDescGZIP(), []int{0} -} - -func (x *HelloRequest) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -type HelloReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` -} - -func (x *HelloReply) Reset() { - *x = HelloReply{} - if protoimpl.UnsafeEnabled { - mi := &file_hello_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *HelloReply) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HelloReply) ProtoMessage() {} - -func (x *HelloReply) ProtoReflect() protoreflect.Message { - mi := &file_hello_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead. -func (*HelloReply) Descriptor() ([]byte, []int) { - return file_hello_proto_rawDescGZIP(), []int{1} -} - -func (x *HelloReply) GetMessage() string { - if x != nil { - return x.Message - } - return "" -} - -var File_hello_proto protoreflect.FileDescriptor - -var file_hello_proto_rawDesc = []byte{ - 0x0a, 0x0b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x22, 0x22, 0x0a, 0x0c, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x26, 0x0a, 0x0a, 0x48, 0x65, 0x6c, - 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_hello_proto_rawDescOnce sync.Once - file_hello_proto_rawDescData = file_hello_proto_rawDesc -) - -func file_hello_proto_rawDescGZIP() []byte { - file_hello_proto_rawDescOnce.Do(func() { - file_hello_proto_rawDescData = protoimpl.X.CompressGZIP(file_hello_proto_rawDescData) - }) - return file_hello_proto_rawDescData -} - -var file_hello_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_hello_proto_goTypes = []interface{}{ - (*HelloRequest)(nil), // 0: protos.HelloRequest - (*HelloReply)(nil), // 1: protos.HelloReply -} -var file_hello_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_hello_proto_init() } -func file_hello_proto_init() { - if File_hello_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_hello_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HelloRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_hello_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HelloReply); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_hello_proto_rawDesc, - NumEnums: 0, - NumMessages: 2, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_hello_proto_goTypes, - DependencyIndexes: file_hello_proto_depIdxs, - MessageInfos: file_hello_proto_msgTypes, - }.Build() - File_hello_proto = out.File - file_hello_proto_rawDesc = nil - file_hello_proto_goTypes = nil - file_hello_proto_depIdxs = nil -} diff --git a/_examples/response-writer/protobuf/protos/hello.proto b/_examples/response-writer/protobuf/protos/hello.proto deleted file mode 100644 index 31281615..00000000 --- a/_examples/response-writer/protobuf/protos/hello.proto +++ /dev/null @@ -1,13 +0,0 @@ -syntax = "proto3"; - -package protos; - -option go_package = "./protos"; - -message HelloRequest { - string name = 1; -} - -message HelloReply { - string message = 1; -} \ No newline at end of file diff --git a/_examples/response-writer/sse-third-party/main.go b/_examples/response-writer/sse-third-party/main.go deleted file mode 100644 index ed87b9f0..00000000 --- a/_examples/response-writer/sse-third-party/main.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12" - "github.com/r3labs/sse" -) - -// First of all install the sse third-party package (you can use other if you don't like this approach or go ahead to the "sse" example) -// $ go get -u github.com/r3labs/sse -func main() { - app := iris.New() - s := sse.New() - /* - This creates a new stream inside of the scheduler. - Seeing as there are no consumers, publishing a message - to this channel will do nothing. - Clients can connect to this stream once the iris handler is started - by specifying stream as a url parameter, like so: - http://localhost:8080/events?stream=messages - */ - s.CreateStream("messages") - - app.Any("/events", iris.FromStd(s.HTTPHandler)) - - go func() { - // You design when to send messages to the client, - // here we just wait 5 seconds to send the first message - // in order to give u time to open a browser window... - time.Sleep(5 * time.Second) - // Publish a payload to the stream. - s.Publish("messages", &sse.Event{ - Data: []byte("ping"), - }) - - time.Sleep(3 * time.Second) - s.Publish("messages", &sse.Event{ - Data: []byte("second message"), - }) - time.Sleep(2 * time.Second) - s.Publish("messages", &sse.Event{ - Data: []byte("third message"), - }) - }() // ... - - app.Listen(":8080") -} - -/* For a golang SSE client you can look at: https://github.com/r3labs/sse#example-client */ diff --git a/_examples/response-writer/sse/main.go b/_examples/response-writer/sse/main.go deleted file mode 100644 index 7ac0a21d..00000000 --- a/_examples/response-writer/sse/main.go +++ /dev/null @@ -1,191 +0,0 @@ -// Package main shows how to send continuous event messages to the clients through SSE via a broker. -// Read details at: https://www.w3schools.com/htmL/html5_serversentevents.asp and -// https://robots.thoughtbot.com/writing-a-server-sent-events-server-in-go -package main - -import ( - "encoding/json" - "fmt" - "time" - - "github.com/kataras/golog" - "github.com/kataras/iris/v12" -) - -// A Broker holds open client connections, -// listens for incoming events on its Notifier channel -// and broadcast event data to all registered connections. -type Broker struct { - - // Events are pushed to this channel by the main events-gathering routine. - Notifier chan []byte - - // New client connections. - newClients chan chan []byte - - // Closed client connections. - closingClients chan chan []byte - - // Client connections registry. - clients map[chan []byte]bool -} - -// NewBroker returns a new broker factory. -func NewBroker() *Broker { - b := &Broker{ - Notifier: make(chan []byte, 1), - newClients: make(chan chan []byte), - closingClients: make(chan chan []byte), - clients: make(map[chan []byte]bool), - } - - // Set it running - listening and broadcasting events. - go b.listen() - - return b -} - -// Listen on different channels and act accordingly. -func (b *Broker) listen() { - for { - select { - case s := <-b.newClients: - // A new client has connected. - // Register their message channel. - b.clients[s] = true - golog.Infof("Client added. %d registered clients", len(b.clients)) - - case s := <-b.closingClients: - // A client has dettached and we want to - // stop sending them messages. - delete(b.clients, s) - golog.Infof("Removed client. %d registered clients", len(b.clients)) - - case event := <-b.Notifier: - // We got a new event from the outside! - // Send event to all connected clients. - for clientMessageChan := range b.clients { - clientMessageChan <- event - } - } - } -} - -func (b *Broker) ServeHTTP(ctx iris.Context) { - // Make sure that the writer supports flushing. - - flusher, ok := ctx.ResponseWriter().Flusher() - if !ok { - ctx.StopWithText(iris.StatusHTTPVersionNotSupported, "Streaming unsupported!") - return - } - - // Set the headers related to event streaming, you can omit the "application/json" if you send plain text. - // If you develop a go client, you must have: "Accept" : "application/json, text/event-stream" header as well. - ctx.ContentType("application/json, text/event-stream") - ctx.Header("Cache-Control", "no-cache") - ctx.Header("Connection", "keep-alive") - // We also add a Cross-origin Resource Sharing header so browsers on different domains can still connect. - ctx.Header("Access-Control-Allow-Origin", "*") - - // Each connection registers its own message channel with the Broker's connections registry. - messageChan := make(chan []byte) - - // Signal the broker that we have a new connection. - b.newClients <- messageChan - - // Listen to connection close and when the entire request handler chain exits(this handler here) and un-register messageChan. - ctx.OnClose(func(iris.Context) { - // Remove this client from the map of connected clients - // when this handler exits. - b.closingClients <- messageChan - }) - - // Block waiting for messages broadcast on this connection's messageChan. - for { - // Write to the ResponseWriter. - // Server Sent Events compatible. - ctx.Writef("data: %s\n\n", <-messageChan) - // or json: data:{obj}. - - // Flush the data immediately instead of buffering it for later. - flusher.Flush() - } -} - -type event struct { - Timestamp int64 `json:"timestamp"` - Message string `json:"message"` -} - -const script = `` - -func main() { - broker := NewBroker() - - go func() { - for { - time.Sleep(2 * time.Second) - - now := time.Now() - evt := event{ - Timestamp: now.Unix(), - Message: fmt.Sprintf("Hello at %s", now.Format(time.RFC1123)), - } - - evtBytes, err := json.Marshal(evt) - if err != nil { - golog.Error(err) - continue - } - - broker.Notifier <- evtBytes - } - }() - - app := iris.New() - app.Logger().SetLevel("debug") - - app.Get("/", func(ctx iris.Context) { - ctx.HTML( - `SSE` + script + ` - -

Waiting for messages...

- - - - - -
Timestamp (server)Message
- - `) - }) - - app.Get("/events", broker.ServeHTTP) - - // http://localhost:8080 - // http://localhost:8080/events - app.Listen(":8080") -} diff --git a/_examples/response-writer/sse/optional.sse.mini.js.html b/_examples/response-writer/sse/optional.sse.mini.js.html deleted file mode 100644 index 01e1304a..00000000 --- a/_examples/response-writer/sse/optional.sse.mini.js.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - SSE (javascript side) - - - - -

Open the browser's console(F12) and watch for incoming event messages

- - \ No newline at end of file diff --git a/_examples/response-writer/stream-writer/main.go b/_examples/response-writer/stream-writer/main.go deleted file mode 100644 index 58b2f11e..00000000 --- a/_examples/response-writer/stream-writer/main.go +++ /dev/null @@ -1,79 +0,0 @@ -package main - -import ( - "errors" - "io" - "time" // showcase the delay - - "github.com/kataras/iris/v12" -) - -var errDone = errors.New("done") - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.ContentType("text/html") - ctx.Header("Transfer-Encoding", "chunked") - i := 0 - ints := []int{1, 2, 3, 5, 7, 9, 11, 13, 15, 17, 23, 29} - // Send the response in chunks and wait for half a second between each chunk, - // until connection close. - err := ctx.StreamWriter(func(w io.Writer) error { - ctx.Writef("Message number %d
", ints[i]) - time.Sleep(500 * time.Millisecond) // simulate delay. - if i == len(ints)-1 { - return errDone // ends the loop. - } - i++ - return nil // continue write - }) - - if err != errDone { - // Test it by canceling the request before the stream ends: - // [ERRO] $DATETIME stream: context canceled. - ctx.Application().Logger().Errorf("stream: %v", err) - } - }) - - type messageNumber struct { - Number int `json:"number"` - } - - app.Get("/json", func(ctx iris.Context) { - ctx.Header("Transfer-Encoding", "chunked") - i := 0 - ints := []int{1, 2, 3, 5, 7, 9, 11, 13, 15, 17, 23, 29} - // Send the response in chunks and wait for half a second between each chunk, - // until connection close. - notifyClose := ctx.Request().Context().Done() - for { - select { - case <-notifyClose: - // err := ctx.Request().Context().Err() - ctx.Application().Logger().Infof("Connection closed, loop end.") - return - default: - ctx.JSON(messageNumber{Number: ints[i]}) - ctx.WriteString("\n") - time.Sleep(500 * time.Millisecond) // simulate delay. - if i == len(ints)-1 { - ctx.Application().Logger().Infof("Loop end.") - return - } - i++ - ctx.ResponseWriter().Flush() - } - } - }) - - app.Listen(":8080") -} - -/* -Look the following methods too: -- Context.OnClose(callback) -- Context.OnConnectionClose(callback) and -- Context.Request().Context().Done()/.Err() too -*/ diff --git a/_examples/response-writer/transactions/main.go b/_examples/response-writer/transactions/main.go deleted file mode 100644 index 7b18b64d..00000000 --- a/_examples/response-writer/transactions/main.go +++ /dev/null @@ -1,54 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" -) - -func main() { - app := iris.New() - - // subdomains works with all available routers, like other features too. - - app.Get("/", func(ctx iris.Context) { - ctx.BeginTransaction(func(t *context.Transaction) { - // OPTIONAl STEP: , if true then the next transictions will not be executed if this transiction fails - // t.SetScope(context.RequestTransactionScope) - - // OPTIONAL STEP: - // create a new custom type of error here to keep track of the status code and reason message - err := context.NewTransactionErrResult() - - // we should use t.Context if we want to rollback on any errors lives inside this function clojure. - t.Context().Text("Blablabla this should not be sent to the client because we will fill the err with a message and status") - - // virtualize a fake error here, for the sake of the example - fail := true - if fail { - err.StatusCode = iris.StatusInternalServerError - // NOTE: if empty reason then the default or the custom http error will be fired (like ctx.FireStatusCode) - err.Reason = "Error: Virtual failure!!" - } - - // OPTIONAl STEP: - // but useful if we want to post back an error message to the client if the transaction failed. - // if the reason is empty then the transaction completed successfully, - // otherwise we rollback the whole response writer's body, - // headers and cookies, status code and everything lives inside this transaction - t.Complete(err) - }) - - ctx.BeginTransaction(func(t *context.Transaction) { - t.Context().HTML("

This will sent at all cases because it lives on different transaction and it doesn't fails

") - // * if we don't have any 'throw error' logic then no need of scope.Complete() - }) - - // OPTIONALLY, depends on the usage: - // at any case, what ever happens inside the context's transactions send this to the client - ctx.HTML("

Let's add a second html message to the response, " + - "if the transaction was failed and it was request scoped then this message would " + - "not been shown. But it has a transient scope(default) so, it is visible as expected!

") - }) - - app.Listen(":8080") -} diff --git a/_examples/response-writer/write-rest/main.go b/_examples/response-writer/write-rest/main.go deleted file mode 100644 index 5e757827..00000000 --- a/_examples/response-writer/write-rest/main.go +++ /dev/null @@ -1,125 +0,0 @@ -package main - -import ( - "encoding/xml" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" -) - -// User example struct for json and msgpack. -type User struct { - Firstname string `json:"firstname" msgpack:"firstname"` - Lastname string `json:"lastname" msgpack:"lastname"` - City string `json:"city" msgpack:"city"` - Age int `json:"age" msgpack:"age"` -} - -// ExampleXML just a test struct to view represents xml content-type -type ExampleXML struct { - XMLName xml.Name `xml:"example"` - One string `xml:"one,attr"` - Two string `xml:"two,attr"` -} - -// ExampleYAML just a test struct to write yaml to the client. -type ExampleYAML struct { - Name string `yaml:"name"` - ServerAddr string `yaml:"ServerAddr"` -} - -func main() { - app := iris.New() - - // Read - app.Post("/decode", func(ctx iris.Context) { - // Read https://github.com/kataras/iris/blob/master/_examples/request-body/read-json/main.go as well. - var user User - ctx.ReadJSON(&user) - - ctx.Writef("%s %s is %d years old and comes from %s!", user.Firstname, user.Lastname, user.Age, user.City) - }) - - // Write - app.Get("/encode", func(ctx iris.Context) { - u := User{ - Firstname: "John", - Lastname: "Doe", - City: "Neither FBI knows!!!", - Age: 25, - } - - // Manually setting a content type: ctx.ContentType("text/javascript") - ctx.JSON(u) - }) - - // Other content types, - - app.Get("/binary", func(ctx iris.Context) { - // useful when you want force-download of contents of raw bytes form. - ctx.Binary([]byte("Some binary data here.")) - }) - - app.Get("/text", func(ctx iris.Context) { - ctx.Text("Plain text here") - }) - - app.Get("/json", func(ctx iris.Context) { - ctx.JSON(map[string]string{"hello": "json"}) // or myjsonStruct{hello:"json} - }) - - app.Get("/jsonp", func(ctx iris.Context) { - ctx.JSONP(map[string]string{"hello": "jsonp"}, context.JSONP{Callback: "callbackName"}) - }) - - app.Get("/xml", func(ctx iris.Context) { - ctx.XML(ExampleXML{One: "hello", Two: "xml"}) - // OR: - // ctx.XML(iris.XMLMap("keys", iris.Map{"key": "value"})) - }) - - app.Get("/markdown", func(ctx iris.Context) { - ctx.Markdown([]byte("# Hello Dynamic Markdown -- iris")) - }) - - app.Get("/yaml", func(ctx iris.Context) { - ctx.YAML(ExampleYAML{Name: "Iris", ServerAddr: "localhost:8080"}) - // OR: - // ctx.YAML(iris.Map{"name": "Iris", "serverAddr": "localhost:8080"}) - }) - - // app.Get("/protobuf", func(ctx iris.Context) { - // ctx.Protobuf(proto.Message) - // }) - - app.Get("/msgpack", func(ctx iris.Context) { - u := User{ - Firstname: "John", - Lastname: "Doe", - City: "Neither FBI knows!!!", - Age: 25, - } - - ctx.MsgPack(u) - }) - - // http://localhost:8080/decode - // http://localhost:8080/encode - // - // http://localhost:8080/binary - // http://localhost:8080/text - // http://localhost:8080/json - // http://localhost:8080/jsonp - // http://localhost:8080/xml - // http://localhost:8080/markdown - // http://localhost:8080/msgpack - // - // `iris.WithOptimizations` is an optional configurator, - // if passed to the `Run` then it will ensure that the application - // response to the client as fast as possible. - // - // - // `iris.WithoutServerError` is an optional configurator, - // if passed to the `Run` then it will not print its passed error as an actual server error. - app.Listen(":8080", iris.WithOptimizations) -} diff --git a/_examples/routing/README.md b/_examples/routing/README.md deleted file mode 100644 index a5fb3d63..00000000 --- a/_examples/routing/README.md +++ /dev/null @@ -1 +0,0 @@ -https://github.com/kataras/iris/wiki/Routing diff --git a/_examples/routing/basic/.dockerignore b/_examples/routing/basic/.dockerignore deleted file mode 100644 index ffdca42e..00000000 --- a/_examples/routing/basic/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -.git -node_modules -bin \ No newline at end of file diff --git a/_examples/routing/basic/Dockerfile b/_examples/routing/basic/Dockerfile deleted file mode 100644 index 09daa324..00000000 --- a/_examples/routing/basic/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -# docker build -t myapp . -# docker run --rm -it -p 8080:8080 myapp:latest -FROM golang:latest AS builder -RUN apt-get update -ENV GO111MODULE=on \ - CGO_ENABLED=0 \ - GOOS=linux \ - GOARCH=amd64 -WORKDIR /go/src/app -COPY go.mod . -RUN go mod download -COPY . . -RUN go install - -FROM scratch -COPY --from=builder /go/bin/app . -ENTRYPOINT ["./app"] \ No newline at end of file diff --git a/_examples/routing/basic/README.md b/_examples/routing/basic/README.md deleted file mode 100644 index 350562a9..00000000 --- a/_examples/routing/basic/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Basic Example - -The only requirement for this example is [Docker](https://docs.docker.com/install/). - -## Docker Compose - -The Docker Compose is pre-installed with Docker for Windows. For linux please follow the steps described at: https://docs.docker.com/compose/install/. - -Build and run the application for linux arch and expose it on http://localhost:8080. - -```sh -$ docker-compose up -``` - -See [docker-compose file](docker-compose.yml). - -## Without Docker Compose - -1. Build the image as "myapp" (docker build) -2. Run the image and map exposed ports (-p 8080:8080) -3. Attach the interactive mode so CTRL/CMD+C signals are respected to shutdown the Iris Server (-it) -4. Cleanup the image on finish (--rm) - -```sh -$ docker build -t myapp . -$ docker run --rm -it -p 8080:8080 myapp:latest -``` diff --git a/_examples/routing/basic/docker-compose.yml b/_examples/routing/basic/docker-compose.yml deleted file mode 100644 index 54c86b33..00000000 --- a/_examples/routing/basic/docker-compose.yml +++ /dev/null @@ -1,8 +0,0 @@ -# docker-compose up [--build] -version: '3' - -services: - app: - build: . - ports: - - 8080:8080 \ No newline at end of file diff --git a/_examples/routing/basic/main.go b/_examples/routing/basic/main.go deleted file mode 100644 index 1ba67a82..00000000 --- a/_examples/routing/basic/main.go +++ /dev/null @@ -1,206 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func newApp() *iris.Application { - app := iris.New() - app.Logger().SetLevel("debug") - - // registers a custom handler for 404 not found http (error) status code, - // fires when route not found or manually by ctx.StatusCode(iris.StatusNotFound). - app.OnErrorCode(iris.StatusNotFound, notFoundHandler) - - // GET -> HTTP Method - // / -> Path - // func(ctx iris.Context) -> The route's handler. - // - // Third receiver should contains the route's handler(s), they are executed by order. - app.Handle("GET", "/", func(ctx iris.Context) { - // navigate to the https://github.com/kataras/iris/wiki/Routing-context-methods - // to overview all context's method. - ctx.HTML("Hello from " + ctx.Path()) // Hello from / - }) - - app.Get("/home", func(ctx iris.Context) { - ctx.Writef(`Same as app.Handle("GET", "/", [...])`) - }) - - // Different path parameters types in the same path. - // Note that: fallback should registered first e.g. {path} {string}, - // because the handler on this case is executing from last to top. - app.Get("/u/{p:path}", func(ctx iris.Context) { - ctx.Writef(":string, :int, :uint, :alphabetical and :path in the same path pattern.") - }) - - app.Get("/u/{username:string}", func(ctx iris.Context) { - ctx.Writef("before username (string), current route name: %s\n", ctx.RouteName()) - ctx.Next() - }, func(ctx iris.Context) { - ctx.Writef("username (string): %s", ctx.Params().Get("username")) - }) - - app.Get("/u/{firstname:alphabetical}", func(ctx iris.Context) { - ctx.Writef("before firstname (alphabetical), current route name: %s\n", ctx.RouteName()) - ctx.Next() - }, func(ctx iris.Context) { - ctx.Writef("firstname (alphabetical): %s", ctx.Params().Get("firstname")) - }) - - app.Get("/u/{id:int}", func(ctx iris.Context) { - ctx.Writef("before id (int), current route name: %s\n", ctx.RouteName()) - ctx.Next() - }, func(ctx iris.Context) { - ctx.Writef("id (int): %d", ctx.Params().GetIntDefault("id", 0)) - }) - - app.Get("/u/{uid:uint}", func(ctx iris.Context) { - ctx.Writef("before uid (uint), current route name: %s\n", ctx.RouteName()) - ctx.Next() - }, func(ctx iris.Context) { - ctx.Writef("uid (uint): %d", ctx.Params().GetUintDefault("uid", 0)) - }) - - /* - /u/some/path/here maps to :path - /u/abcd maps to :alphabetical (if :alphabetical registered otherwise :string) - /u/42 maps to :uint (if :uint registered otherwise :int) - /u/-1 maps to :int (if :int registered otherwise :string) - /u/abcd123 maps to :string - */ - - // Pssst, don't forget dynamic-path example for more "magic"! - app.Get("/api/users/{userid:uint64 min(1)}", func(ctx iris.Context) { - userID, err := ctx.Params().GetUint64("userid") - if err != nil { - ctx.Writef("error while trying to parse userid parameter," + - "this will never happen if :uint64 is being used because if it's not a valid uint64 it will fire Not Found automatically.") - ctx.StatusCode(iris.StatusBadRequest) - return - } - - ctx.JSON(map[string]interface{}{ - // you can pass any custom structured go value of course. - "user_id": userID, - }) - }) - // app.Post("/", func(ctx iris.Context){}) -> for POST http method. - // app.Put("/", func(ctx iris.Context){})-> for "PUT" http method. - // app.Delete("/", func(ctx iris.Context){})-> for "DELETE" http method. - // app.Options("/", func(ctx iris.Context){})-> for "OPTIONS" http method. - // app.Trace("/", func(ctx iris.Context){})-> for "TRACE" http method. - // app.Head("/", func(ctx iris.Context){})-> for "HEAD" http method. - // app.Connect("/", func(ctx iris.Context){})-> for "CONNECT" http method. - // app.Patch("/", func(ctx iris.Context){})-> for "PATCH" http method. - // app.Any("/", func(ctx iris.Context){}) for all http methods. - - // More than one route can contain the same path with a different http mapped method. - // You can catch any route creation errors with: - // route, err := app.Get(...) - // set a name to a route: route.Name = "myroute" - - // You can also group routes by path prefix, sharing middleware(s) and done handlers. - - adminRoutes := app.Party("/admin", adminMiddleware) - - adminRoutes.Done(func(ctx iris.Context) { // executes always last if ctx.Next() - ctx.Application().Logger().Infof("response sent to " + ctx.Path()) - }) - // adminRoutes.Layout("/views/layouts/admin.html") // set a view layout for these routes, see more at view examples. - - // GET: http://localhost:8080/admin - adminRoutes.Get("/", func(ctx iris.Context) { - // [...] - ctx.StatusCode(iris.StatusOK) // default is 200 == iris.StatusOK - ctx.HTML("

Hello from admin/

") - - ctx.Next() // in order to execute the party's "Done" Handler(s) - }) - - // GET: http://localhost:8080/admin/login - adminRoutes.Get("/login", func(ctx iris.Context) { - // [...] - }) - // POST: http://localhost:8080/admin/login - adminRoutes.Post("/login", func(ctx iris.Context) { - // [...] - }) - - // subdomains, easier than ever, should add localhost or 127.0.0.1 into your hosts file, - // etc/hosts on unix or C:/windows/system32/drivers/etc/hosts on windows. - v1 := app.Party("v1.") - { // braces are optional, it's just type of style, to group the routes visually. - - // http://v1.localhost:8080 - // Note: for versioning-specific features checkout the _examples/routing/versioning instead. - v1.Get("/", func(ctx iris.Context) { - ctx.HTML(`Version 1 API. go to /api/users`) - }) - - usersAPI := v1.Party("/api/users") - { - // http://v1.localhost:8080/api/users - usersAPI.Get("/", func(ctx iris.Context) { - ctx.Writef("All users") - }) - // http://v1.localhost:8080/api/users/42 - usersAPI.Get("/{userid:int}", func(ctx iris.Context) { - ctx.Writef("user with id: %d", ctx.Params().GetIntDefault("userid", 0)) - }) - } - } - - // wildcard subdomains. - wildcardSubdomain := app.Party("*.") - { - wildcardSubdomain.Get("/", func(ctx iris.Context) { - ctx.Writef("Subdomain can be anything, now you're here from: %s", ctx.Subdomain()) - }) - } - - return app -} - -func main() { - app := newApp() - - // http://localhost:8080 - // http://localhost:8080/home - // http://localhost:8080/api/users/42 - // http://localhost:8080/admin - // http://localhost:8080/admin/login - // - // http://localhost:8080/api/users/0 - // http://localhost:8080/api/users/blabla - // http://localhost:8080/wontfound - // - // http://localhost:8080/u/abcd - // http://localhost:8080/u/42 - // http://localhost:8080/u/-1 - // http://localhost:8080/u/abcd123 - // http://localhost:8080/u/some/path/here - // - // if hosts edited: - // http://v1.localhost:8080 - // http://v1.localhost:8080/api/users - // http://v1.localhost:8080/api/users/42 - // http://anything.localhost:8080 - app.Listen(":8080") -} - -func adminMiddleware(ctx iris.Context) { - // [...] - ctx.Next() // to move to the next handler, or don't that if you have any auth logic. -} - -func notFoundHandler(ctx iris.Context) { - ctx.HTML("Custom route for 404 not found http code, here you can render a view, html, json any valid response.") -} - -// Notes: -// A path parameter name should contain only alphabetical letters, symbols, containing '_' and numbers are NOT allowed. -// If route failed to be registered, the app will panic without any warnings -// if you didn't catch the second return value(error) on .Handle/.Get.... - -// See "file-server/single-page-application" to see how another feature, "WrapRouter", works. diff --git a/_examples/routing/basic/main_test.go b/_examples/routing/basic/main_test.go deleted file mode 100644 index 5756fb3d..00000000 --- a/_examples/routing/basic/main_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package main - -import ( - "fmt" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -// Shows a very basic usage of the httptest. -// The tests are written in a way to be easy to understand, -// for a more comprehensive testing examples check out the: -// _examples/routing/main_test.go, -// _examples/routing/subdomains/www/main_test.go -// _examples/file-server and e.t.c. -// Almost every example which covers -// a new feature from you to learn -// contains a test file as well. -func TestRoutingBasic(t *testing.T) { - expectedUResponse := func(paramName, paramType, paramValue string) string { - s := fmt.Sprintf("before %s (%s), current route name: GET/u/{%s:%s}\n", paramName, paramType, paramName, paramType) - s += fmt.Sprintf("%s (%s): %s", paramName, paramType, paramValue) - return s - } - - var ( - expectedNotFoundResponse = "Custom route for 404 not found http code, here you can render a view, html, json any valid response." - - expectedIndexResponse = "Hello from /" - expectedHomeResponse = `Same as app.Handle("GET", "/", [...])` - - expectedUpathResponse = ":string, :int, :uint, :alphabetical and :path in the same path pattern." - expectedUStringResponse = expectedUResponse("username", "string", "abcd123") - expectedUIntResponse = expectedUResponse("id", "int", "-1") - expectedUUintResponse = expectedUResponse("uid", "uint", "42") - expectedUAlphabeticalResponse = expectedUResponse("firstname", "alphabetical", "abcd") - - expectedAPIUsersIndexResponse = map[string]interface{}{"user_id": 42} - - expectedAdminIndexResponse = "

Hello from admin/

" - - expectedSubdomainV1IndexResponse = `Version 1 API. go to /api/users` - expectedSubdomainV1APIUsersIndexResponse = "All users" - expectedSubdomainV1APIUsersIndexWithParamResponse = "user with id: 42" - - expectedSubdomainWildcardIndexResponse = "Subdomain can be anything, now you're here from: any-subdomain-here" - ) - - app := newApp() - e := httptest.New(t, app) - - e.GET("/anotfound").Expect().Status(httptest.StatusNotFound). - Body().Equal(expectedNotFoundResponse) - - e.GET("/").Expect().Status(httptest.StatusOK). - Body().Equal(expectedIndexResponse) - e.GET("/home").Expect().Status(httptest.StatusOK). - Body().Equal(expectedHomeResponse) - - e.GET("/u/some/path/here").Expect().Status(httptest.StatusOK). - Body().Equal(expectedUpathResponse) - e.GET("/u/abcd123").Expect().Status(httptest.StatusOK). - Body().Equal(expectedUStringResponse) - e.GET("/u/-1").Expect().Status(httptest.StatusOK). - Body().Equal(expectedUIntResponse) - e.GET("/u/42").Expect().Status(httptest.StatusOK). - Body().Equal(expectedUUintResponse) - e.GET("/u/abcd").Expect().Status(httptest.StatusOK). - Body().Equal(expectedUAlphabeticalResponse) - - e.GET("/api/users/42").Expect().Status(httptest.StatusOK). - JSON().Equal(expectedAPIUsersIndexResponse) - - e.GET("/admin").Expect().Status(httptest.StatusOK). - Body().Equal(expectedAdminIndexResponse) - - e.Request("GET", "/").WithURL("http://v1.example.com").Expect().Status(httptest.StatusOK). - Body().Equal(expectedSubdomainV1IndexResponse) - - e.Request("GET", "/api/users").WithURL("http://v1.example.com").Expect().Status(httptest.StatusOK). - Body().Equal(expectedSubdomainV1APIUsersIndexResponse) - - e.Request("GET", "/api/users/42").WithURL("http://v1.example.com").Expect().Status(httptest.StatusOK). - Body().Equal(expectedSubdomainV1APIUsersIndexWithParamResponse) - - e.Request("GET", "/").WithURL("http://any-subdomain-here.example.com").Expect().Status(httptest.StatusOK). - Body().Equal(expectedSubdomainWildcardIndexResponse) -} diff --git a/_examples/routing/conditional-chain/main.go b/_examples/routing/conditional-chain/main.go deleted file mode 100644 index 4d0747f6..00000000 --- a/_examples/routing/conditional-chain/main.go +++ /dev/null @@ -1,56 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func newApp() *iris.Application { - app := iris.New() - v1 := app.Party("/api/v1") - - myFilter := func(ctx iris.Context) bool { - // don't do that on production, use session or/and database calls and etc. - ok, _ := ctx.URLParamBool("admin") - return ok - } - - onlyWhenFilter1 := func(ctx iris.Context) { - ctx.Application().Logger().Infof("admin: %#+v", ctx.URLParams()) - ctx.Writef("Admin\n") - ctx.Next() - } - - onlyWhenFilter2 := func(ctx iris.Context) { - // You can always use the per-request storage - // to perform actions like this ofc. - // - // this handler: ctx.Values().Set("is_admin", true) - // next handler: isAdmin := ctx.Values().GetBoolDefault("is_admin", false) - // - // but, let's simplify it: - ctx.HTML("

Hello Admin


") - ctx.Next() - } - - // HERE: - // It can be registered anywhere, as a middleware. - // It will fire the `onlyWhenFilter1` and `onlyWhenFilter2` as middlewares (with ctx.Next()) - // if myFilter pass otherwise it will just continue the handler chain with ctx.Next() by ignoring - // the `onlyWhenFilter1` and `onlyWhenFilter2`. - myMiddleware := iris.NewConditionalHandler(myFilter, onlyWhenFilter1, onlyWhenFilter2) - - v1UsersRouter := v1.Party("/users", myMiddleware) - v1UsersRouter.Get("/", func(ctx iris.Context) { - ctx.HTML("requested: /api/v1/users") - }) - - return app -} - -func main() { - app := newApp() - - // http://localhost:8080/api/v1/users - // http://localhost:8080/api/v1/users?admin=true - app.Listen(":8080") -} diff --git a/_examples/routing/conditional-chain/main_test.go b/_examples/routing/conditional-chain/main_test.go deleted file mode 100644 index ca0bb139..00000000 --- a/_examples/routing/conditional-chain/main_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestNewConditionalHandler(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - e.GET("/api/v1/users").Expect().Status(httptest.StatusOK). - Body().Equal("requested: /api/v1/users") - e.GET("/api/v1/users").WithQuery("admin", "true").Expect().Status(httptest.StatusOK). - Body().Equal("Admin\n

Hello Admin


requested: /api/v1/users") -} diff --git a/_examples/routing/custom-router/main.go b/_examples/routing/custom-router/main.go deleted file mode 100644 index 3ec24fe2..00000000 --- a/_examples/routing/custom-router/main.go +++ /dev/null @@ -1,108 +0,0 @@ -package main - -import ( - "strings" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/core/router" -) - -/* A Router should contain all three of the following methods: - - HandleRequest should handle the request based on the Context. - HandleRequest(ctx iris.Context) - - Build should builds the handler, it's being called on router's BuildRouter. - Build(provider router.RoutesProvider) error - - RouteExists reports whether a particular route exists. - RouteExists(ctx iris.Context, method, path string) bool - - FireErrorCode(ctx iris.Context) should handle the given ctx.GetStatusCode(). - -For a more detailed, complete and useful example -you can take a look at the iris' router itself which is located at: -https://github.com/kataras/iris/tree/master/core/router/handler.go -which completes this exact interface, the `router#RequestHandler`. -*/ -type customRouter struct { - // a copy of routes (safer because you will not be able to alter a route on serve-time without a `app.RefreshRouter` call): - // []router.Route - // or just expect the whole routes provider: - provider router.RoutesProvider -} - -// HandleRequest a silly example which finds routes based only on the first part of the requested path -// which must be a static one as well, the rest goes to fill the parameters. -func (r *customRouter) HandleRequest(ctx iris.Context) { - path := ctx.Path() - ctx.Application().Logger().Infof("Requested resource path: %s", path) - - parts := strings.Split(path, "/")[1:] - staticPath := "/" + parts[0] - for _, route := range r.provider.GetRoutes() { - if strings.HasPrefix(route.Path, staticPath) && route.Method == ctx.Method() { - paramParts := parts[1:] - for _, paramValue := range paramParts { - for _, p := range route.Tmpl().Params { - ctx.Params().Set(p.Name, paramValue) - } - } - - ctx.SetCurrentRoute(route.ReadOnly) - ctx.Do(route.Handlers) - return - } - } - - // if nothing found... - ctx.StatusCode(iris.StatusNotFound) -} - -func (r *customRouter) Build(provider router.RoutesProvider) error { - for _, route := range provider.GetRoutes() { - // do any necessary validation or conversations based on your custom logic here - // but always run the "BuildHandlers" for each registered route. - route.BuildHandlers() - // [...] r.routes = append(r.routes, *route) - } - - r.provider = provider - return nil -} - -func (r *customRouter) RouteExists(ctx iris.Context, method, path string) bool { - // [...] - return false -} - -func (r *customRouter) FireErrorCode(ctx iris.Context) { - // responseStatusCode := ctx.GetStatusCode() // set by prior ctx.StatusCode calls - // [...] -} - -func main() { - app := iris.New() - - // In case you are wondering, the parameter types and macros like "{param:string $func()}" still work inside - // your custom router if you fetch by the Route's Handler - // because they are middlewares under the hood, so you don't have to implement the logic of handling them manually, - // though you have to match what requested path is what route and fill the ctx.Params(), this is the work of your custom router. - app.Get("/hello/{name}", func(ctx iris.Context) { - name := ctx.Params().Get("name") - ctx.Writef("Hello %s\n", name) - }) - - app.Get("/cs/{num:uint64 min(10) else 400}", func(ctx iris.Context) { - num := ctx.Params().GetUint64Default("num", 0) - ctx.Writef("num is: %d\n", num) - }) - - // To replace the existing router with a customized one by using the iris/context.Context - // you have to use the `app.BuildRouter` method before `app.Run` and after the routes registered. - // You should pass your custom router's instance as the second input arg, which must completes the `router#RequestHandler` - // interface as shown above. - // - // To see how you can build something even more low-level without direct iris' context support (you can do that manually as well) - // navigate to the "custom-wrapper" example instead. - myCustomRouter := new(customRouter) - app.BuildRouter(app.ContextPool, myCustomRouter, app.APIBuilder, true) - - app.Listen(":8080") -} diff --git a/_examples/routing/custom-wrapper/main.go b/_examples/routing/custom-wrapper/main.go deleted file mode 100644 index 9f18cdf6..00000000 --- a/_examples/routing/custom-wrapper/main.go +++ /dev/null @@ -1,69 +0,0 @@ -package main - -import ( - "net/http" - "strings" - - "github.com/kataras/iris/v12" -) - -// In this example you'll just see one use case of .WrapRouter. -// You can use the .WrapRouter to add custom logic when or when not the router should -// be executed in order to execute the registered routes' handlers. -func newApp() *iris.Application { - app := iris.New() - - app.OnErrorCode(iris.StatusNotFound, func(ctx iris.Context) { - ctx.HTML("Resource Not found") - }) - - app.Get("/profile/{username}", func(ctx iris.Context) { - ctx.Writef("Hello %s", ctx.Params().Get("username")) - }) - - app.HandleDir("/", iris.Dir("./public")) - - myOtherHandler := func(ctx iris.Context) { - ctx.Writef("inside a handler which is fired manually by our custom router wrapper") - } - - // wrap the router with a native net/http handler. - // if url does not contain any "." (i.e: .css, .js...) - // (depends on the app , you may need to add more file-server exceptions), - // then the handler will execute the router that is responsible for the - // registered routes (look "/" and "/profile/{username}") - // if not then it will serve the files based on the root "/" path. - app.WrapRouter(func(w http.ResponseWriter, r *http.Request, router http.HandlerFunc) { - path := r.URL.Path - - if strings.HasPrefix(path, "/other") { - // acquire and release a context in order to use it to execute - // our custom handler - // remember: we use net/http.Handler because here we are in the "low-level", before the router itself. - ctx := app.ContextPool.Acquire(w, r) - myOtherHandler(ctx) - app.ContextPool.Release(ctx) - return - } - - router.ServeHTTP(w, r) // else continue serving routes as usual. - }) - - return app -} - -func main() { - app := newApp() - - // http://localhost:8080 - // http://localhost:8080/index.html - // http://localhost:8080/app.js - // http://localhost:8080/css/main.css - // http://localhost:8080/profile/anyusername - // http://localhost:8080/other/random - app.Listen(":8080") - - // Note: In this example we just saw one use case, - // you may want to .WrapRouter or .Downgrade in order to bypass the iris' default router, i.e: - // you can use that method to setup custom proxies too. -} diff --git a/_examples/routing/custom-wrapper/main_test.go b/_examples/routing/custom-wrapper/main_test.go deleted file mode 100644 index 540f0435..00000000 --- a/_examples/routing/custom-wrapper/main_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package main - -import ( - "io/ioutil" - "path/filepath" - "strings" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -type resource string - -func (r resource) String() string { - return string(r) -} - -func (r resource) strip(strip string) string { - s := r.String() - return strings.TrimPrefix(s, strip) -} - -func (r resource) loadFromBase(dir string) string { - filename := r.String() - - if filename == "/" { - filename = "/index.html" - } - - fullpath := filepath.Join(dir, filename) - - b, err := ioutil.ReadFile(fullpath) - if err != nil { - panic(fullpath + " failed with error: " + err.Error()) - } - - return string(b) -} - -var urls = []resource{ - "/", - "/index.html", - "/app.js", - "/css/main.css", -} - -func TestCustomWrapper(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - for _, u := range urls { - url := u.String() - contents := u.loadFromBase("./public") - - e.GET(url).Expect(). - Status(httptest.StatusOK). - Body().Equal(contents) - } - - e.GET("/other/something").Expect().Status(httptest.StatusOK) -} diff --git a/_examples/routing/custom-wrapper/public/app.js b/_examples/routing/custom-wrapper/public/app.js deleted file mode 100644 index c47a1fd5..00000000 --- a/_examples/routing/custom-wrapper/public/app.js +++ /dev/null @@ -1 +0,0 @@ -window.alert("app.js loaded from \"/"); \ No newline at end of file diff --git a/_examples/routing/custom-wrapper/public/css/main.css b/_examples/routing/custom-wrapper/public/css/main.css deleted file mode 100644 index fb72e54a..00000000 --- a/_examples/routing/custom-wrapper/public/css/main.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - background-color: black; -} diff --git a/_examples/routing/custom-wrapper/public/index.html b/_examples/routing/custom-wrapper/public/index.html deleted file mode 100644 index 960869d7..00000000 --- a/_examples/routing/custom-wrapper/public/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - Index Page - - - -

Hello from index.html

- - - - - - \ No newline at end of file diff --git a/_examples/routing/dynamic-path/main.go b/_examples/routing/dynamic-path/main.go deleted file mode 100644 index 8cc0ce73..00000000 --- a/_examples/routing/dynamic-path/main.go +++ /dev/null @@ -1,293 +0,0 @@ -package main - -import ( - "regexp" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - // At the previous example "routing/basic", - // we've seen static routes, group of routes, subdomains, wildcard subdomains, a small example of parameterized path - // with a single known paramete and custom http errors, now it's time to see wildcard parameters and macros. - - // Iris, like net/http std package registers route's handlers - // by a Handler, the iris' type of handler is just a func(ctx iris.Context) - // where context comes from github.com/kataras/iris/context. - // - // Iris has the easiest and the most powerful routing process you have ever meet. - // - // At the same time, - // Iris has its own interpeter(yes like a programming language) - // for route's path syntax and their dynamic path parameters parsing and evaluation, - // We call them "macros" for shortcut. - // How? It calculates its needs and if not any special regexp needed then it just - // registers the route with the low-level underline path syntax, - // otherwise it pre-compiles the regexp and adds the necessary middleware(s). - // - // Standard macro types for parameters: - // +------------------------+ - // | {param:string} | - // +------------------------+ - // string type - // anything (single path segmnent) - // - // +-------------------------------+ - // | {param:int} | - // +-------------------------------+ - // int type - // -9223372036854775808 to 9223372036854775807 (x64) or -2147483648 to 2147483647 (x32), depends on the host arch - // - // +------------------------+ - // | {param:int8} | - // +------------------------+ - // int8 type - // -128 to 127 - // - // +------------------------+ - // | {param:int16} | - // +------------------------+ - // int16 type - // -32768 to 32767 - // - // +------------------------+ - // | {param:int32} | - // +------------------------+ - // int32 type - // -2147483648 to 2147483647 - // - // +------------------------+ - // | {param:int64} | - // +------------------------+ - // int64 type - // -9223372036854775808 to 9223372036854775807 - // - // +------------------------+ - // | {param:uint} | - // +------------------------+ - // uint type - // 0 to 18446744073709551615 (x64) or 0 to 4294967295 (x32) - // - // +------------------------+ - // | {param:uint8} | - // +------------------------+ - // uint8 type - // 0 to 255 - // - // +------------------------+ - // | {param:uint16} | - // +------------------------+ - // uint16 type - // 0 to 65535 - // - // +------------------------+ - // | {param:uint32} | - // +------------------------+ - // uint32 type - // 0 to 4294967295 - // - // +------------------------+ - // | {param:uint64} | - // +------------------------+ - // uint64 type - // 0 to 18446744073709551615 - // - // +---------------------------------+ - // | {param:bool} or {param:boolean} | - // +---------------------------------+ - // bool type - // only "1" or "t" or "T" or "TRUE" or "true" or "True" - // or "0" or "f" or "F" or "FALSE" or "false" or "False" - // - // +------------------------+ - // | {param:alphabetical} | - // +------------------------+ - // alphabetical/letter type - // letters only (upper or lowercase) - // - // +------------------------+ - // | {param:file} | - // +------------------------+ - // file type - // letters (upper or lowercase) - // numbers (0-9) - // underscore (_) - // dash (-) - // point (.) - // no spaces ! or other character - // - // +------------------------+ - // | {param:path} | - // +------------------------+ - // path type - // anything, should be the last part, can be more than one path segment, - // i.e: "/test/{param:path}" and request: "/test/path1/path2/path3" , ctx.Params().Get("param") == "path1/path2/path3" - // - // if type is missing then parameter's type is defaulted to string, so - // {param} == {param:string}. - // - // If a function not found on that type then the `string` macro type's functions are being used. - // - // - // Besides the fact that iris provides the basic types and some default "macro funcs" - // you are able to register your own too!. - // - // Register a named path parameter function: - // app.Macros().Number.RegisterFunc("min", func(argument int) func(paramValue string) bool { - // [...] - // return true/false -> true means valid. - // }) - // - // at the func(argument ...) you can have any standard type, it will be validated before the server starts - // so don't care about performance here, the only thing it runs at serve time is the returning func(paramValue string) bool. - // - // {param:string equal(iris)} , "iris" will be the argument here: - // app.Macros().String.RegisterFunc("equal", func(argument string) func(paramValue string) bool { - // return func(paramValue string) bool { return argument == paramValue } - // }) - - // you can use the "string" type which is valid for a single path parameter that can be anything. - app.Get("/username/{name}", func(ctx iris.Context) { - ctx.Writef("Hello %s", ctx.Params().Get("name")) - }) // type is missing = {name:string} - - // Let's register our first macro attached to uint64 macro type. - // "min" = the function - // "minValue" = the argument of the function - // func(uint64) bool = our func's evaluator, this executes in serve time when - // a user requests a path which contains the :uint64 macro parameter type with the min(...) macro parameter function. - app.Macros().Get("uint64").RegisterFunc("min", func(minValue uint64) func(uint64) bool { - // type of "paramValue" should match the type of the internal macro's evaluator function, which in this case is "uint64". - return func(paramValue uint64) bool { - return paramValue >= minValue - } - }) - - // http://localhost:8080/profile/id>=20 - // this will throw 404 even if it's found as route on : /profile/0, /profile/blabla, /profile/-1 - // macro parameter functions are optional of course. - app.Get("/profile/{id:uint64 min(20)}", func(ctx iris.Context) { - // second parameter is the error but it will always nil because we use macros, - // the validaton already happened. - id := ctx.Params().GetUint64Default("id", 0) - ctx.Writef("Hello id: %d", id) - }) - - // to change the error code per route's macro evaluator: - app.Get("/profile/{id:uint64 min(1)}/friends/{friendid:uint64 min(1) else 504}", func(ctx iris.Context) { - id := ctx.Params().GetUint64Default("id", 0) - friendid := ctx.Params().GetUint64Default("friendid", 0) - ctx.Writef("Hello id: %d looking for friend id: %d", id, friendid) - }) // this will throw e 504 error code instead of 404 if all route's macros not passed. - - // :uint8 0 to 255. - app.Get("/ages/{age:uint8 else 400}", func(ctx iris.Context) { - age, _ := ctx.Params().GetUint8("age") - ctx.Writef("age selected: %d", age) - }) - - // Another example using a custom regexp or any custom logic. - - // Register your custom argument-less macro function to the :string param type. - latLonExpr := "^-?[0-9]{1,3}(?:\\.[0-9]{1,10})?$" - latLonRegex, err := regexp.Compile(latLonExpr) - if err != nil { - panic(err) - } - - // MatchString is a type of func(string) bool, so we use it as it is. - app.Macros().Get("string").RegisterFunc("coordinate", latLonRegex.MatchString) - - app.Get("/coordinates/{lat:string coordinate() else 502}/{lon:string coordinate() else 502}", func(ctx iris.Context) { - ctx.Writef("Lat: %s | Lon: %s", ctx.Params().Get("lat"), ctx.Params().Get("lon")) - }) - - // - - // Another one is by using a custom body. - app.Macros().Get("string").RegisterFunc("range", func(minLength, maxLength int) func(string) bool { - return func(paramValue string) bool { - return len(paramValue) >= minLength && len(paramValue) <= maxLength - } - }) - - app.Get("/limitchar/{name:string range(1,200)}", func(ctx iris.Context) { - name := ctx.Params().Get("name") - ctx.Writef(`Hello %s | the name should be between 1 and 200 characters length - otherwise this handler will not be executed`, name) - }) - - // - - // Register your custom macro function which accepts a slice of strings `[...,...]`. - app.Macros().Get("string").RegisterFunc("has", func(validNames []string) func(string) bool { - return func(paramValue string) bool { - for _, validName := range validNames { - if validName == paramValue { - return true - } - } - - return false - } - }) - - app.Get("/static_validation/{name:string has([kataras,gerasimos,maropoulos])}", func(ctx iris.Context) { - name := ctx.Params().Get("name") - ctx.Writef(`Hello %s | the name should be "kataras" or "gerasimos" or "maropoulos" - otherwise this handler will not be executed`, name) - }) - - // - - // http://localhost:8080/game/a-zA-Z/level/42 - // remember, alphabetical is lowercase or uppercase letters only. - app.Get("/game/{name:alphabetical}/level/{level:int}", func(ctx iris.Context) { - ctx.Writef("name: %s | level: %s", ctx.Params().Get("name"), ctx.Params().Get("level")) - }) - - app.Get("/lowercase/static", func(ctx iris.Context) { - ctx.Writef("static and dynamic paths are not conflicted anymore!") - }) - - // let's use a trivial custom regexp that validates a single path parameter - // which its value is only lowercase letters. - - // http://localhost:8080/lowercase/anylowercase - app.Get("/lowercase/{name:string regexp(^[a-z]+)}", func(ctx iris.Context) { - ctx.Writef("name should be only lowercase, otherwise this handler will never executed: %s", ctx.Params().Get("name")) - }) - - // http://localhost:8080/single_file/app.js - app.Get("/single_file/{myfile:file}", func(ctx iris.Context) { - ctx.Writef("file type validates if the parameter value has a form of a file name, got: %s", ctx.Params().Get("myfile")) - }) - - // http://localhost:8080/myfiles/any/directory/here/ - // this is the only macro type that accepts any number of path segments. - app.Get("/myfiles/{directory:path}", func(ctx iris.Context) { - ctx.Writef("path type accepts any number of path segments, path after /myfiles/ is: %s", ctx.Params().Get("directory")) - }) // for wildcard path (any number of path segments) without validation you can use: - // /myfiles/* - - // "{param}"'s performance is exactly the same of ":param"'s. - - // alternatives -> ":param" for single path parameter and "*" for wildcard path parameter. - // Note these: - // if "/mypath/*" then the parameter name is "*". - // if "/mypath/{myparam:path}" then the parameter has two names, one is the "*" and the other is the user-defined "myparam". - - // WARNING: - // A path parameter name should contain only alphabetical letters or digits. Symbols like '_' are NOT allowed. - // Last, do not confuse `ctx.Params()` with `ctx.Values()`. - // Path parameter's values can be retrieved from `ctx.Params()`, - // context's local storage that can be used to communicate between handlers and middleware(s) can be stored to `ctx.Values()`. - // - // When registering different parameter types in the same exact path pattern, the path parameter's name - // should differ e.g. - // /path/{name:string} - // /path/{id:uint} - app.Listen(":8080") -} diff --git a/_examples/routing/dynamic-path/root-wildcard/main.go b/_examples/routing/dynamic-path/root-wildcard/main.go deleted file mode 100644 index 2ccb8489..00000000 --- a/_examples/routing/dynamic-path/root-wildcard/main.go +++ /dev/null @@ -1,70 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - // this works as expected now, - // will handle all GET requests - // except: - // / -> because of app.Get("/", ...) - // /other/anything/here -> because of app.Get("/other/{paramother:path}", ...) - // /other2/anything/here -> because of app.Get("/other2/{paramothersecond:path}", ...) - // /other2/static2 -> because of app.Get("/other2/static", ...) - // - // It isn't conflicts with the rest of the routes, without routing performance cost! - // - // i.e /something/here/that/cannot/be/found/by/other/registered/routes/order/not/matters - app.Get("/{p:path}", h) - // app.Get("/static/{p:path}", staticWildcardH) - - // this will handle only GET / - app.Get("/", staticPath) - - // this will handle all GET requests starting with "/other/" - // - // i.e /other/more/than/one/path/parts - app.Get("/other/{paramother:path}", other) - - // this will handle all GET requests starting with "/other2/" - // except /other2/static (because of the next static route) - // - // i.e /other2/more/than/one/path/parts - app.Get("/other2/{paramothersecond:path}", other2) - - // this will handle only GET "/other2/static" - app.Get("/other2/static2", staticPathOther2) - - app.Listen(":8080") -} - -func h(ctx iris.Context) { - param := ctx.Params().Get("p") - ctx.WriteString(param) -} - -func staticWildcardH(ctx iris.Context) { - param := ctx.Params().Get("p") - ctx.WriteString("from staticWildcardH: param=" + param) -} - -func other(ctx iris.Context) { - param := ctx.Params().Get("paramother") - ctx.Writef("from other: %s", param) -} - -func other2(ctx iris.Context) { - param := ctx.Params().Get("paramothersecond") - ctx.Writef("from other2: %s", param) -} - -func staticPath(ctx iris.Context) { - ctx.Writef("from the static path(/): %s", ctx.Path()) -} - -func staticPathOther2(ctx iris.Context) { - ctx.Writef("from the static path(/other2/static2): %s", ctx.Path()) -} diff --git a/_examples/routing/dynamic-path/same-pattern-different-func/main.go b/_examples/routing/dynamic-path/same-pattern-different-func/main.go deleted file mode 100644 index e241a51b..00000000 --- a/_examples/routing/dynamic-path/same-pattern-different-func/main.go +++ /dev/null @@ -1,33 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := newApp() - app.Logger().SetLevel("debug") - app.Listen(":8080") -} - -func newApp() *iris.Application { - app := iris.New() - - app.HandleMany(iris.MethodGet, "/ /api/{page:string suffix(.html)}", handler1) - app.Get("/api/{name:string suffix(.zip)}", handler2) - - return app -} - -func handler1(ctx iris.Context) { - reply(ctx) -} - -func handler2(ctx iris.Context) { - reply(ctx) -} - -func reply(ctx iris.Context) { - ctx.JSON(iris.Map{ - "handler": ctx.HandlerName(), - "params": ctx.Params().Store, - }) -} diff --git a/_examples/routing/dynamic-path/same-pattern-different-func/main_test.go b/_examples/routing/dynamic-path/same-pattern-different-func/main_test.go deleted file mode 100644 index 1e99dd6c..00000000 --- a/_examples/routing/dynamic-path/same-pattern-different-func/main_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/core/memstore" - "github.com/kataras/iris/v12/httptest" -) - -func TestSameParameterTypeDifferentMacroFunctions(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - type resp struct { - Handler string `json:"handler"` - Params memstore.Store `json:"params"` - } - - var ( - expectedIndex = resp{ - Handler: "iris/_examples/routing/dynamic-path/same-pattern-different-func.handler1", - Params: nil, - } - expectedHTMLPage = resp{ - Handler: "iris/_examples/routing/dynamic-path/same-pattern-different-func.handler1", - Params: memstore.Store{ - {Key: "page", ValueRaw: "random.html"}, - }, - } - expectedZipName = resp{ - Handler: "iris/_examples/routing/dynamic-path/same-pattern-different-func.handler2", - Params: memstore.Store{ - {Key: "name", ValueRaw: "random.zip"}, - }, - } - ) - - e.GET("/").Expect().Status(httptest.StatusOK).JSON().Equal(expectedIndex) - e.GET("/api/random.html").Expect().Status(httptest.StatusOK).JSON().Equal(expectedHTMLPage) - e.GET("/api/random.zip").Expect().Status(httptest.StatusOK).JSON().Equal(expectedZipName) -} diff --git a/_examples/routing/dynamic-path/same-pattern-different-func/use-global/main.go b/_examples/routing/dynamic-path/same-pattern-different-func/use-global/main.go deleted file mode 100644 index 2f18f84f..00000000 --- a/_examples/routing/dynamic-path/same-pattern-different-func/use-global/main.go +++ /dev/null @@ -1,42 +0,0 @@ -package main // #1552 - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := newApp() - app.Listen(":8080") -} - -func newApp() *iris.Application { - app := iris.New() - - app.UseGlobal(middleware("first")) - app.UseGlobal(middleware("second")) - app.DoneGlobal(onDone) - - app.Get("/{name prefix(one)}", handler("first route")) - app.Get("/{name prefix(two)}", handler("second route")) - app.Get("/{name prefix(three)}", handler("third route")) - - return app -} - -func middleware(str string) iris.Handler { - return func(ctx iris.Context) { - ctx.Writef("Called %s middleware\n", str) - ctx.Next() - } -} - -func handler(str string) iris.Handler { - return func(ctx iris.Context) { - ctx.Writef("%s\n", str) - ctx.Next() // or ignroe that and use app.SetRegisterRules. - } -} - -func onDone(ctx iris.Context) { - ctx.Writef("Called done: %s", ctx.Params().Get("name")) -} diff --git a/_examples/routing/dynamic-path/same-pattern-different-func/use-global/main_test.go b/_examples/routing/dynamic-path/same-pattern-different-func/use-global/main_test.go deleted file mode 100644 index 6cc2cc58..00000000 --- a/_examples/routing/dynamic-path/same-pattern-different-func/use-global/main_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import ( - "fmt" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestSamePatternDifferentFuncUseGlobal(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - expectedResultFmt := "Called first middleware\nCalled second middleware\n%s\nCalled done: %s" - tests := map[string]string{ - "/one-num": "first route", - "/two-num": "second route", - "/three-num": "third route", - } - - for path, mainBody := range tests { - result := fmt.Sprintf(expectedResultFmt, mainBody, path[1:]) - e.GET(path).Expect().Status(httptest.StatusOK).Body().Equal(result) - } -} diff --git a/_examples/routing/hello-world/main.go b/_examples/routing/hello-world/main.go deleted file mode 100644 index 2b0ec41d..00000000 --- a/_examples/routing/hello-world/main.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - - "github.com/kataras/iris/v12/middleware/logger" - "github.com/kataras/iris/v12/middleware/recover" -) - -func main() { - app := iris.New() - app.Logger().SetLevel("debug") - // Optionally, add two builtin handlers - // that can recover from any http-relative panics - // and log the requests to the terminal. - app.Use(recover.New()) - app.Use(logger.New()) - - // Method: GET - // Resource: http://localhost:8080 - app.Handle("GET", "/", func(ctx iris.Context) { - ctx.HTML("

Welcome

") - }) - - // same as app.Handle("GET", "/ping", [...]) - // Method: GET - // Resource: http://localhost:8080/ping - app.Get("/ping", func(ctx iris.Context) { - ctx.WriteString("pong") - }) - - // Method: GET - // Resource: http://localhost:8080/hello - app.Get("/hello", func(ctx iris.Context) { - ctx.JSON(iris.Map{"message": "Hello Iris!"}) - }) - - // http://localhost:8080 - // http://localhost:8080/ping - // http://localhost:8080/hello - app.Listen(":8080") -} diff --git a/_examples/routing/http-errors/main.go b/_examples/routing/http-errors/main.go deleted file mode 100644 index e3fdca01..00000000 --- a/_examples/routing/http-errors/main.go +++ /dev/null @@ -1,116 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - // Catch a specific error code. - app.OnErrorCode(iris.StatusInternalServerError, func(ctx iris.Context) { - ctx.HTML("Message: " + ctx.Values().GetString("message") + "") - }) - - // Catch all error codes [app.OnAnyErrorCode...] - - app.Get("/", func(ctx iris.Context) { - ctx.HTML(`Click here to pretend an HTTP error`) - }) - - app.Get("/my500", func(ctx iris.Context) { - ctx.Values().Set("message", "this is the error message") - ctx.StatusCode(500) - }) - - app.Get("/u/{firstname:alphabetical}", func(ctx iris.Context) { - ctx.Writef("Hello %s", ctx.Params().Get("firstname")) - }) - - // Read more at: https://github.com/kataras/iris/issues/1335 - app.Get("/product-problem", problemExample) - - app.Get("/product-error", func(ctx iris.Context) { - ctx.Writef("explain the error") - }) - - // http://localhost:8080 - // http://localhost:8080/my500 - // http://localhost:8080/u/gerasimos - // http://localhost:8080/product-problem - app.Listen(":8080") -} - -func newProductProblem(productName, detail string) iris.Problem { - return iris.NewProblem(). - // The type URI, if relative it automatically convert to absolute. - Type("/product-error"). - // The title, if empty then it gets it from the status code. - Title("Product validation problem"). - // Any optional details. - Detail(detail). - // The status error code, required. - Status(iris.StatusBadRequest). - // Any custom key-value pair. - Key("productName", productName) - // Optional cause of the problem, chain of Problems. - // Cause(iris.NewProblem().Type("/error").Title("cause of the problem").Status(400)) -} - -func problemExample(ctx iris.Context) { - /* - p := iris.NewProblem(). - Type("/validation-error"). - Title("Your request parameters didn't validate"). - Detail("Optional details about the error."). - Status(iris.StatusBadRequest). - Key("customField1", customValue1) - Key("customField2", customValue2) - ctx.Problem(p) - - // OR - ctx.Problem(iris.Problem{ - "type": "/validation-error", - "title": "Your request parameters didn't validate", - "detail": "Optional details about the error.", - "status": iris.StatusBadRequest, - "customField1": customValue1, - "customField2": customValue2, - }) - - // OR - */ - - // Response like JSON but with indent of " " and - // content type of "application/problem+json" - ctx.Problem(newProductProblem("product name", "problem error details"), iris.ProblemOptions{ - // Optional JSON renderer settings. - JSON: iris.JSON{ - Indent: " ", - }, - // OR - // Render as XML: - // - // RenderXML: true, - // XML: iris.XML{Indent: " "}, - // and ctx.StatusCode(200) to see the result on browser as a user. - // - // The below `RetryAfter` field sets the "Retry-After" response header. - // - // Can accept: - // time.Time for HTTP-Date, - // time.Duration, int64, float64, int for seconds - // or string for date or duration. - // Examples: - // time.Now().Add(5 * time.Minute), - // 300 * time.Second, - // "5m", - // - RetryAfter: 300, - // A function that, if specified, can dynamically set - // retry-after based on the request. Useful for ProblemOptions reusability. - // Overrides the RetryAfter field. - // - // RetryAfterFunc: func(iris.Context) interface{} { [...] } - }) -} diff --git a/_examples/routing/http-errors/reset-body/main.go b/_examples/routing/http-errors/reset-body/main.go deleted file mode 100644 index f00de102..00000000 --- a/_examples/routing/http-errors/reset-body/main.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/kataras/iris/v12" -) - -func main() { - app := newApp() - app.Listen(":8080") -} - -func newApp() *iris.Application { - app := iris.New() - app.Use(iris.Compression) - - app.OnAnyErrorCode(onErrorCode) - app.Get("/", handler) - - app.Configure(iris.WithResetOnFireErrorCode) - return app -} - -// This is the default error handler Iris uses for any error codes. -func onErrorCode(ctx iris.Context) { - if err := ctx.GetErr(); err != nil { - ctx.WriteString(err.Error()) - } else { - ctx.WriteString(iris.StatusText(ctx.GetStatusCode())) - } -} - -func handler(ctx iris.Context) { - ctx.Record() - - ctx.WriteString("This should NOT be written") - - // [....something bad happened after we "write"] - err := fmt.Errorf("custom error") - ctx.StopWithError(iris.StatusBadRequest, err) -} diff --git a/_examples/routing/http-errors/reset-body/main_test.go b/_examples/routing/http-errors/reset-body/main_test.go deleted file mode 100644 index 3218213e..00000000 --- a/_examples/routing/http-errors/reset-body/main_test.go +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestResetCompressionAndFireError(t *testing.T) { // #1569 - app := newApp() - - e := httptest.New(t, app) - e.GET("/").Expect().Status(httptest.StatusBadRequest).Body().Equal("custom error") -} diff --git a/_examples/routing/intelligence/main.go b/_examples/routing/intelligence/main.go deleted file mode 100644 index dbc2c631..00000000 --- a/_examples/routing/intelligence/main.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - app.Get("/home", handler) - app.Get("/contact", handler) - app.Get("/contract", handler) - - // http://localhost:8080/home - // http://localhost:8080/hom - // - // http://localhost:8080/contact - // http://localhost:8080/cont - // - // http://localhost:8080/contract - // http://localhost:8080/contr - app.Listen(":8080", iris.WithPathIntelligence) -} - -func handler(ctx iris.Context) { - ctx.Writef("Path: %s", ctx.Path()) -} diff --git a/_examples/routing/intelligence/manual/main.go b/_examples/routing/intelligence/manual/main.go deleted file mode 100644 index b2bfb5a8..00000000 --- a/_examples/routing/intelligence/manual/main.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - app.OnErrorCode(iris.StatusNotFound, notFound) - - // [register some routes...] - app.Get("/home", handler) - app.Get("/news", handler) - app.Get("/news/politics", handler) - app.Get("/user/profile", handler) - app.Get("/user", handler) - app.Get("/newspaper", handler) - app.Get("/user/{id}", handler) - - app.Listen(":8080") -} - -func notFound(ctx iris.Context) { - suggestPaths := ctx.FindClosest(3) - if len(suggestPaths) == 0 { - ctx.WriteString("404 not found") - return - } - - ctx.HTML("Did you mean?
    ") - for _, s := range suggestPaths { - ctx.HTML(`
  • %s
  • `, s, s) - } - ctx.HTML("
") -} - -func handler(ctx iris.Context) { - ctx.Writef("Path: %s", ctx.Path()) -} diff --git a/_examples/routing/macros/main.go b/_examples/routing/macros/main.go deleted file mode 100644 index 3a41b646..00000000 --- a/_examples/routing/macros/main.go +++ /dev/null @@ -1,76 +0,0 @@ -// Package main shows how you can register a custom parameter type and macro functions that belongs to it. -package main - -import ( - "fmt" - "reflect" - "sort" - "strings" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/hero" -) - -func main() { - app := iris.New() - app.Logger().SetLevel("debug") - - app.Macros().Register("slice", "", false, true, func(paramValue string) (interface{}, bool) { - return strings.Split(paramValue, "/"), true - }).RegisterFunc("contains", func(expectedItems []string) func(paramValue []string) bool { - sort.Strings(expectedItems) - return func(paramValue []string) bool { - if len(paramValue) != len(expectedItems) { - return false - } - - sort.Strings(paramValue) - for i := 0; i < len(paramValue); i++ { - if paramValue[i] != expectedItems[i] { - return false - } - } - - return true - } - }) - - // In order to use your new param type inside MVC controller's function input argument or a hero function input argument - // you have to tell the Iris what type it is, the `ValueRaw` of the parameter is the same type - // as you defined it above with the func(paramValue string) (interface{}, bool). - // The new value and its type(from string to your new custom type) it is stored only once now, - // you don't have to do any conversions for simple cases like this. - context.ParamResolvers[reflect.TypeOf([]string{})] = func(paramIndex int) interface{} { - return func(ctx iris.Context) []string { - // When you want to retrieve a parameter with a value type that it is not supported by-default, such as ctx.Params().GetInt - // then you can use the `GetEntry` or `GetEntryAt` and cast its underline `ValueRaw` to the desired type. - // The type should be the same as the macro's evaluator function (last argument on the Macros#Register) return value. - return ctx.Params().GetEntryAt(paramIndex).ValueRaw.([]string) - } - } - - /* - http://localhost:8080/test_slice_hero/myvaluei1/myavlue2 -> - myparam's value (a trailing path parameter type) is: []string{"myvalue1", "myavlue2"} - */ - app.Get("/test_slice_hero/{myparam:slice}", hero.Handler(func(myparam []string) string { - return fmt.Sprintf("myparam's value (a trailing path parameter type) is: %#v\n", myparam) - })) - - /* - http://localhost:8080/test_slice_contains/notcontains1/value2 -> - (404) Not Found - - http://localhost:8080/test_slice_contains/value1/value2 -> - myparam's value (a trailing path parameter type) is: []string{"value1", "value2"} - */ - app.Get("/test_slice_contains/{myparam:slice contains([value1,value2])}", func(ctx iris.Context) { - // When it is not a builtin function available to retrieve your value with the type you want, such as ctx.Params().GetInt - // then you can use the `GetEntry.ValueRaw` to get the real value, which is set-ed by your macro above. - myparam := ctx.Params().GetEntry("myparam").ValueRaw.([]string) - ctx.Writef("myparam's value (a trailing path parameter type) is: %#v\n", myparam) - }) - - app.Listen(":8080") -} diff --git a/_examples/routing/main.go b/_examples/routing/main.go deleted file mode 100644 index d7537ea4..00000000 --- a/_examples/routing/main.go +++ /dev/null @@ -1,182 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -/* -Read: -"overview" -"basic" -"dynamic-path" -and "reverse" examples if you want to release iris' real power. -*/ - -const maxBodySize = 1 << 20 -const notFoundHTML = "

custom http error page

" - -func registerErrors(app *iris.Application) { - // set a custom 404 handler - app.OnErrorCode(iris.StatusNotFound, func(ctx iris.Context) { - ctx.HTML(notFoundHTML) - }) -} - -func registerGamesRoutes(app *iris.Application) { - gamesMiddleware := func(ctx iris.Context) { - ctx.Next() - } - - // party is just a group of routes with the same prefix - // and middleware, i.e: "/games" and gamesMiddleware. - games := app.Party("/games", gamesMiddleware) - { // braces are optional of course, it's just a style of code - - // "GET" method - games.Get("/{gameID:uint64}/clans", h) - games.Get("/{gameID:uint64}/clans/clan/{clanPublicID:uint64}", h) - games.Get("/{gameID:uint64}/clans/search", h) - - // "PUT" method - games.Put("/{gameID:uint64}/players/{clanPublicID:uint64}", h) - games.Put("/{gameID:uint64}/clans/clan/{clanPublicID:uint64}", h) - // remember: "clanPublicID" should not be changed to other routes with the same prefix. - // "POST" method - games.Post("/{gameID:uint64}/clans", h) - games.Post("/{gameID:uint64}/players", h) - games.Post("/{gameID:uint64}/clans/{clanPublicID:uint64}/leave", h) - games.Post("/{gameID:uint64}/clans/{clanPublicID:uint64}/memberships/application", h) - games.Post("/{gameID:uint64}/clans/{clanPublicID:uint64}/memberships/application/{action}", h) // {action} == {action:string} - games.Post("/{gameID:uint64}/clans/{clanPublicID:uint64}/memberships/invitation", h) - games.Post("/{gameID:uint64}/clans/{clanPublicID:uint64}/memberships/invitation/{action}", h) - games.Post("/{gameID:uint64}/clans/{clanPublicID:uint64}/memberships/delete", h) - games.Post("/{gameID:uint64}/clans/{clanPublicID:uint64}/memberships/promote", h) - games.Post("/{gameID:uint64}/clans/{clanPublicID:uint64}/memberships/demote", h) - - gamesCh := games.Party("/challenge") - { - // games/challenge - gamesCh.Get("/", h) - - gamesChBeginner := gamesCh.Party("/beginner") - { - // games/challenge/beginner/start - gamesChBeginner.Get("/start", h) - levelBeginner := gamesChBeginner.Party("/level") - { - // games/challenge/beginner/level/first - levelBeginner.Get("/first", h) - } - } - - gamesChIntermediate := gamesCh.Party("/intermediate") - { - // games/challenge/intermediate - gamesChIntermediate.Get("/", h) - // games/challenge/intermediate/start - gamesChIntermediate.Get("/start", h) - } - } - - } -} - -func registerSubdomains(app *iris.Application) { - mysubdomain := app.Party("mysubdomain.") - // http://mysubdomain.myhost.com - mysubdomain.Get("/", h) - - willdcardSubdomain := app.Party("*.") - willdcardSubdomain.Get("/", h) - willdcardSubdomain.Party("/party").Get("/", h) -} - -func newApp() *iris.Application { - app := iris.New() - - registerErrors(app) - registerGamesRoutes(app) - registerSubdomains(app) - - app.Handle("GET", "/healthcheck", h) - - // "POST" method - // this handler reads raw body from the client/request - // and sends back the same body - // remember, we have limit to that body in order - // to protect ourselves from "over heating". - app.Post("/", iris.LimitRequestBodySize(maxBodySize), func(ctx iris.Context) { - // get request body - b, err := ctx.GetBody() - // if is larger then send a bad request status - if err != nil { - ctx.StatusCode(iris.StatusBadRequest) - ctx.Writef(err.Error()) - return - } - // send back the post body - ctx.Write(b) - }) - - app.HandleMany("POST PUT", "/postvalue", func(ctx iris.Context) { - name := ctx.PostValueDefault("name", "iris") - headervale := ctx.GetHeader("headername") - ctx.Writef("Hello %s | %s", name, headervale) - }) - - return app -} - -func h(ctx iris.Context) { - method := ctx.Method() // the http method requested a server's resource. - subdomain := ctx.Subdomain() // the subdomain, if any. - - // the request path (without scheme and host). - path := ctx.Path() - // how to get all parameters, if we don't know - // the names: - paramsLen := ctx.Params().Len() - - ctx.Params().Visit(func(name string, value string) { - ctx.Writef("%s = %s\n", name, value) - }) - ctx.Writef("Info\n\n") - ctx.Writef("Method: %s\nSubdomain: %s\nPath: %s\nParameters length: %d", method, subdomain, path, paramsLen) -} - -func main() { - app := newApp() - app.Logger().SetLevel("debug") - - /* - // GET - http://localhost:8080/healthcheck - http://localhost:8080/games/42/clans - http://localhost:8080/games/42/clans/clan/93 - http://localhost:8080/games/42/clans/search - http://mysubdomain.localhost:8080/ - - // PUT - http://localhost:8080/postvalue - http://localhost:8080/games/42/players/93 - http://localhost:8080/games/42/clans/clan/93 - - // POST - http://localhost:8080/ - http://localhost:8080/postvalue - http://localhost:8080/games/42/clans - http://localhost:8080/games/42/players - http://localhost:8080/games/42/clans/93/leave - http://localhost:8080/games/42/clans/93/memberships/application - http://localhost:8080/games/42/clans/93/memberships/application/anystring - http://localhost:8080/games/42/clans/93/memberships/invitation - http://localhost:8080/games/42/clans/93/memberships/invitation/anystring - http://localhost:8080/games/42/clans/93/memberships/delete - http://localhost:8080/games/42/clans/93/memberships/promote - http://localhost:8080/games/42/clans/93/memberships/demote - - // FIRE NOT FOUND - http://localhost:8080/coudlntfound - */ - app.Listen(":8080") -} diff --git a/_examples/routing/main_test.go b/_examples/routing/main_test.go deleted file mode 100644 index 93db302d..00000000 --- a/_examples/routing/main_test.go +++ /dev/null @@ -1,141 +0,0 @@ -package main - -import ( - "strconv" - "strings" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func calculatePathAndResponse(method, subdomain, path string, paramKeyValue ...string) (string, string) { - paramsLen := 0 - - if l := len(paramKeyValue); l >= 2 { - paramsLen = len(paramKeyValue) / 2 - } - - paramsInfo := "" - if paramsLen > 0 { - for i := 0; i < len(paramKeyValue); i++ { - paramKey := paramKeyValue[i] - i++ - if i >= len(paramKeyValue) { - panic("paramKeyValue should be align with path parameters {} and must be placed in order") - } - - paramValue := paramKeyValue[i] - paramsInfo += paramKey + " = " + paramValue + "\n" - - beginParam := strings.IndexByte(path, '{') - endParam := strings.IndexByte(path, '}') - if beginParam == -1 || endParam == -1 { - panic("something wrong with parameters, please define them in order") - } - - path = path[:beginParam] + paramValue + path[endParam+1:] - } - } - - return path, paramsInfo + `Info - -Method: ` + method + ` -Subdomain: ` + subdomain + ` -Path: ` + path + ` -Parameters length: ` + strconv.Itoa(paramsLen) -} - -type troute struct { - method, subdomain, path string - status int - expectedBody string - contentType string -} - -func newTroute(method, subdomain, path string, status int, paramKeyValue ...string) troute { - finalPath, expectedBody := calculatePathAndResponse(method, subdomain, path, paramKeyValue...) - contentType := "text/plain; charset=UTF-8" - - if status == httptest.StatusNotFound { - expectedBody = notFoundHTML - contentType = "text/html; charset=UTF-8" - } - - return troute{ - contentType: contentType, - method: method, - subdomain: subdomain, - path: finalPath, - status: status, - expectedBody: expectedBody, - } -} - -func TestRouting(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - tests := []troute{ - // GET - newTroute("GET", "", "/healthcheck", httptest.StatusOK), - newTroute("GET", "", "/games/{gameID}/clans", httptest.StatusOK, "gameID", "42"), - newTroute("GET", "", "/games/{gameID}/clans/clan/{clanPublicID}", httptest.StatusOK, "gameID", "42", "clanPublicID", "93"), - newTroute("GET", "", "/games/{gameID}/clans/search", httptest.StatusOK, "gameID", "42"), - newTroute("GET", "", "/games/challenge", httptest.StatusOK), - newTroute("GET", "", "/games/challenge/beginner/start", httptest.StatusOK), - newTroute("GET", "", "/games/challenge/beginner/level/first", httptest.StatusOK), - newTroute("GET", "", "/games/challenge/intermediate", httptest.StatusOK), - newTroute("GET", "", "/games/challenge/intermediate/start", httptest.StatusOK), - newTroute("GET", "mysubdomain", "/", httptest.StatusOK), - newTroute("GET", "mywildcardsubdomain", "/", httptest.StatusOK), - newTroute("GET", "mywildcardsubdomain", "/party", httptest.StatusOK), - // PUT - newTroute("PUT", "", "/games/{gameID}/players/{clanPublicID}", httptest.StatusOK, "gameID", "42", "clanPublicID", "93"), - newTroute("PUT", "", "/games/{gameID}/clans/clan/{clanPublicID}", httptest.StatusOK, "gameID", "42", "clanPublicID", "93"), - // POST - newTroute("POST", "", "/games/{gameID}/clans", httptest.StatusOK, "gameID", "42"), - newTroute("POST", "", "/games/{gameID}/players", httptest.StatusOK, "gameID", "42"), - newTroute("POST", "", "/games/{gameID}/clans/{clanPublicID}/leave", httptest.StatusOK, "gameID", "42", "clanPublicID", "93"), - newTroute("POST", "", "/games/{gameID}/clans/{clanPublicID}/memberships/application", httptest.StatusOK, "gameID", "42", "clanPublicID", "93"), - newTroute("POST", "", "/games/{gameID}/clans/{clanPublicID}/memberships/application/{action}", httptest.StatusOK, "gameID", "42", "clanPublicID", "93", "action", "somethinghere"), - newTroute("POST", "", "/games/{gameID}/clans/{clanPublicID}/memberships/invitation", httptest.StatusOK, "gameID", "42", "clanPublicID", "93"), - newTroute("POST", "", "/games/{gameID}/clans/{clanPublicID}/memberships/invitation/{action}", httptest.StatusOK, "gameID", "42", "clanPublicID", "93", "action", "somethinghere"), - newTroute("POST", "", "/games/{gameID}/clans/{clanPublicID}/memberships/delete", httptest.StatusOK, "gameID", "42", "clanPublicID", "93"), - newTroute("POST", "", "/games/{gameID}/clans/{clanPublicID}/memberships/promote", httptest.StatusOK, "gameID", "42", "clanPublicID", "93"), - newTroute("POST", "", "/games/{gameID}/clans/{clanPublicID}/memberships/demote", httptest.StatusOK, "gameID", "42", "clanPublicID", "93"), - // POST: / will be tested alone - // custom not found - newTroute("GET", "", "/notfound", httptest.StatusNotFound), - newTroute("POST", "", "/notfound2", httptest.StatusNotFound), - newTroute("PUT", "", "/notfound3", httptest.StatusNotFound), - newTroute("GET", "mysubdomain", "/notfound42", httptest.StatusNotFound), - } - - for _, tt := range tests { - et := e.Request(tt.method, tt.path) - if tt.subdomain != "" { - et.WithURL("http://" + tt.subdomain + ".localhost:8080") - } - et.Expect().Status(tt.status).Body().Equal(tt.expectedBody) - } - - // test POST "/" limit data and post data return - - // test with small body - e.POST("/").WithBytes([]byte("ok")).Expect().Status(httptest.StatusOK).Body().Equal("ok") - // test with equal to max body size limit - bsent := make([]byte, maxBodySize, maxBodySize) - e.POST("/").WithBytes(bsent).Expect().Status(httptest.StatusOK).Body().Length().Equal(len(bsent)) - // test with larger body sent and wait for the custom response - largerBSent := make([]byte, maxBodySize+1, maxBodySize+1) - e.POST("/").WithBytes(largerBSent).Expect().Status(httptest.StatusBadRequest).Body().Equal("http: request body too large") - - // test the post value (both post and put) and headers. - e.PUT("/postvalue").WithFormField("name", "test_put"). - WithHeader("headername", "headervalue_put").Expect(). - Status(httptest.StatusOK).Body().Equal("Hello test_put | headervalue_put") - - e.POST("/postvalue").WithFormField("name", "test_post"). - WithHeader("headername", "headervalue_post").Expect(). - Status(httptest.StatusOK).Body().Equal("Hello test_post | headervalue_post") -} diff --git a/_examples/routing/overview-2/main.go b/_examples/routing/overview-2/main.go deleted file mode 100644 index 83b222cf..00000000 --- a/_examples/routing/overview-2/main.go +++ /dev/null @@ -1,126 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -// User is just a bindable object structure. -type User struct { - Username string `json:"username"` - Firstname string `json:"firstname"` - Lastname string `json:"lastname"` - City string `json:"city"` - Age int `json:"age"` -} - -func main() { - app := iris.New() - app.Logger().SetLevel("debug") - // app.Logger().SetLevel("disable") to disable the logger. - - // Define templates using the std html/template engine. - // Parse and load all files inside "./views" folder with ".html" file extension. - // Reload the templates on each request (development mode). - app.RegisterView(iris.HTML("./views", ".html").Reload(true)) - - // Register custom handler for specific http errors. - app.OnErrorCode(iris.StatusInternalServerError, func(ctx iris.Context) { - // .Values are used to communicate between handlers, middleware. - errMessage := ctx.Values().GetString("error") - if errMessage != "" { - ctx.Writef("Internal server error: %s", errMessage) - return - } - - ctx.Writef("(Unexpected) internal server error") - }) - - app.Use(func(ctx iris.Context) { - ctx.Application().Logger().Infof("Begin request for path: %s", ctx.Path()) - ctx.Next() - }) - // app.Done(func(ctx iris.Context) {]}) - - // POST: scheme://mysubdomain.$domain.com/decode - app.Subdomain("mysubdomain.").Post("/decode", func(ctx iris.Context) {}) - // Method POST: http://localhost:8080/decode - app.Post("/decode", func(ctx iris.Context) { - var user User - ctx.ReadJSON(&user) - ctx.Writef("%s %s is %d years old and comes from %s", user.Firstname, user.Lastname, user.Age, user.City) - }) - - // Method GET: http://localhost:8080/encode - app.Get("/encode", func(ctx iris.Context) { - doe := User{ - Username: "Johndoe", - Firstname: "John", - Lastname: "Doe", - City: "Neither FBI knows!!!", - Age: 25, - } - - ctx.JSON(doe) - }) - - // Method GET: http://localhost:8080/profile/anytypeofstring - app.Get("/profile/{username:string}", profileByUsername) - - usersRoutes := app.Party("/users", logThisMiddleware) - { - // Method GET: http://localhost:8080/users/42 - usersRoutes.Get("/{id:int min(1)}", getUserByID) - // Method POST: http://localhost:8080/users/create - usersRoutes.Post("/create", createUser) - } - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("
    ") - for _, link := range []string{"/encode", "/profile/username", "/users/42"} { - ctx.HTML(`
  • %s
  • `, link, link) - } - ctx.HTML("
") - }) - - // Listen for incoming HTTP/1.x & HTTP/2 clients on localhost port 8080. - app.Listen(":8080", iris.WithCharset("utf-8")) -} - -func logThisMiddleware(ctx iris.Context) { - ctx.Application().Logger().Infof("Path: %s | IP: %s", ctx.Path(), ctx.RemoteAddr()) - - // .Next is required to move forward to the chain of handlers, - // if missing then it stops the execution at this handler. - ctx.Next() -} - -func profileByUsername(ctx iris.Context) { - // .Params are used to get dynamic path parameters. - username := ctx.Params().Get("username") - ctx.ViewData("Username", username) - // renders "./views/user/profile.html" - // with {{ .Username }} equals to the username dynamic path parameter. - ctx.View("user/profile.html") -} - -func getUserByID(ctx iris.Context) { - userID := ctx.Params().Get("id") // Or convert directly using: .Values().GetInt/GetInt64 etc... - // your own db fetch here instead of user :=... - user := User{Username: "username" + userID} - - ctx.XML(user) -} - -func createUser(ctx iris.Context) { - var user User - err := ctx.ReadForm(&user) - if err != nil { - ctx.Values().Set("error", "creating user, read and parse form failed. "+err.Error()) - ctx.StatusCode(iris.StatusInternalServerError) - return - } - // renders "./views/user/create_verification.html" - // with {{ . }} equals to the User object, i.e {{ .Username }} , {{ .Firstname}} etc... - ctx.ViewData("", user) - ctx.View("user/create_verification.html") -} diff --git a/_examples/routing/overview-2/views/user/create_verification.html b/_examples/routing/overview-2/views/user/create_verification.html deleted file mode 100644 index a1981380..00000000 --- a/_examples/routing/overview-2/views/user/create_verification.html +++ /dev/null @@ -1,22 +0,0 @@ - - Create verification - -

Create Verification

- - - - - - - - - - - - - - - -
UsernameFirstnameLastnameCityAge
{{ .Username }}{{ .Firstname }}{{ .Lastname }}{{ .City }}{{ .Age }}
- - diff --git a/_examples/routing/overview-2/views/user/profile.html b/_examples/routing/overview-2/views/user/profile.html deleted file mode 100644 index 7b3ceebc..00000000 --- a/_examples/routing/overview-2/views/user/profile.html +++ /dev/null @@ -1,7 +0,0 @@ - - Profile page - -

Profile

- {{ .Username }} - - diff --git a/_examples/routing/overview/main.go b/_examples/routing/overview/main.go deleted file mode 100644 index 2e327a2a..00000000 --- a/_examples/routing/overview/main.go +++ /dev/null @@ -1,192 +0,0 @@ -package main - -import ( - "os" - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/logger" -) - -func main() { - app := iris.New() - // Set Logger level to "debug", - // see your terminal and the created file. - app.Logger().SetLevel("debug") - - // Write logs to a file too. - f := newLogFile() - defer f.Close() - app.Logger().AddOutput(f) - - // Register a request logger middleware to the application. - app.Use(logger.New()) - - // GET: http://localhost:8080 - app.Get("/", info) - - // GET: http://localhost:8080/profile/anyusername - // - // Want to use a custom regex expression instead? - // Easy: app.Get("/profile/{username:string regexp(^[a-zA-Z ]+$)}") - app.Get("/profile/{username:string}", info) - - // If parameter type is missing then it's string which accepts anything, - // i.e: /{paramname} it's exactly the same as /{paramname:string}. - // The below is exactly the same as - // {username:string} - // - // GET: http://localhost:8080/profile/anyusername/backups/any/number/of/paths/here - app.Get("/profile/{username}/backups/{filepath:path}", info) - - // Favicon - - // GET: http://localhost:8080/favicon.ico - app.Favicon("./public/images/favicon.ico") - - // Static assets - - // GET: http://localhost:8080/assets/css/main.css - // maps to ./public/assets/css/main.css file at system location. - app.HandleDir("/assets", iris.Dir("./public/assets")) - - /* OR - - // GET: http://localhost:8080/css/main.css - // maps to ./public/assets/css/main.css file at system location. - app.HandleDir("/css", iris.Dir("./public/assets/css")) - - // GET: http://localhost:8080/css/bootstrap.min.css - // maps to ./public/assets/css/bootstrap.min.css file at system location. - app.HandleDir("/css", iris.Dir("./public/assets/css")) - - */ - - // Grouping - - usersRoutes := app.Party("/users") - // GET: http://localhost:8080/users/help - usersRoutes.Get("/help", func(ctx iris.Context) { - ctx.Writef("GET / -- fetch all users\n") - ctx.Writef("GET /$ID -- fetch a user by id\n") - ctx.Writef("POST / -- create new user\n") - ctx.Writef("PUT /$ID -- update an existing user\n") - ctx.Writef("DELETE /$ID -- delete an existing user\n") - }) - - // GET: http://localhost:8080/users - usersRoutes.Get("/", func(ctx iris.Context) { - ctx.Writef("get all users") - }) - - // GET: http://localhost:8080/users/42 - // **/users/42 and /users/help works after iris version 7.0.5** - usersRoutes.Get("/{id:uint64}", func(ctx iris.Context) { - id, _ := ctx.Params().GetUint64("id") - ctx.Writef("get user by id: %d", id) - }) - - // POST: http://localhost:8080/users - usersRoutes.Post("/", func(ctx iris.Context) { - username, password := ctx.PostValue("username"), ctx.PostValue("password") - ctx.Writef("create user for username= %s and password= %s", username, password) - }) - - // PUT: http://localhost:8080/users - usersRoutes.Put("/{id:uint64}", func(ctx iris.Context) { - id, _ := ctx.Params().GetUint64("id") // or .Get to get its string represatantion. - username := ctx.PostValue("username") - ctx.Writef("update user for id= %d and new username= %s", id, username) - }) - - // DELETE: http://localhost:8080/users/42 - usersRoutes.Delete("/{id:uint64}", func(ctx iris.Context) { - id, _ := ctx.Params().GetUint64("id") - ctx.Writef("delete user by id: %d", id) - }).Describe("deletes a user") - - // Subdomains, depends on the host, you have to edit the hosts or nginx/caddy's configuration if you use them. - // - // See more subdomains examples at _examples/routing/subdomains folder. - adminRoutes := app.Party("admin.") - - // GET: http://admin.localhost:8080 - adminRoutes.Get("/", info) - // GET: http://admin.localhost:8080/settings - adminRoutes.Get("/settings", info) - - // Wildcard/dynamic subdomain - dynamicSubdomainRoutes := app.Party("*.") - - // GET: http://any_thing_here.localhost:8080 - dynamicSubdomainRoutes.Get("/", info) - - app.Delete("/something", func(ctx iris.Context) { - name := ctx.URLParam("name") - ctx.Writef(name) - }) - - app.None("/secret", privateHandler) - app.Get("/public", execPrivateHandler) - - // GET: http://localhost:8080/ - // GET: http://localhost:8080/profile/anyusername - // GET: http://localhost:8080/profile/anyusername/backups/any/number/of/paths/here - - // GET: http://localhost:8080/users/help - // GET: http://localhost:8080/users - // GET: http://localhost:8080/users/42 - // POST: http://localhost:8080/users - // PUT: http://localhost:8080/users - // DELETE: http://localhost:8080/users/42 - // DELETE: http://localhost:8080/something?name=iris - - // GET: http://admin.localhost:8080 - // GET: http://admin.localhost:8080/settings - // GET: http://any_thing_here.localhost:8080 - app.Listen(":8080") -} - -func privateHandler(ctx iris.Context) { - ctx.WriteString(`This can only be executed programmatically through server's another route: -ctx.Exec(iris.MethodNone, "/secret")`) -} - -func execPrivateHandler(ctx iris.Context) { - ctx.Exec(iris.MethodNone, "/secret") -} - -func info(ctx iris.Context) { - method := ctx.Method() // the http method requested a server's resource. - subdomain := ctx.Subdomain() // the subdomain, if any. - - // the request path (without scheme and host). - path := ctx.Path() - // how to get all parameters, if we don't know - // the names: - paramsLen := ctx.Params().Len() - - ctx.Params().Visit(func(name string, value string) { - ctx.Writef("%s = %s\n", name, value) - }) - ctx.Writef("\nInfo\n\n") - ctx.Writef("Method: %s\nSubdomain: %s\nPath: %s\nParameters length: %d", method, subdomain, path, paramsLen) -} - -// get a filename based on the date, file logs works that way the most times -// but these are just a sugar. -func todayFilename() string { - today := time.Now().Format("Jan 02 2006") - return today + ".txt" -} - -func newLogFile() *os.File { - filename := todayFilename() - // open an output file, this will append to the today's file if server restarted. - f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) - if err != nil { - panic(err) - } - - return f -} diff --git a/_examples/routing/overview/public/assets/css/main.css b/_examples/routing/overview/public/assets/css/main.css deleted file mode 100644 index 7db3df1d..00000000 --- a/_examples/routing/overview/public/assets/css/main.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - background-color: black; -} diff --git a/_examples/routing/overview/public/images/favicon.ico b/_examples/routing/overview/public/images/favicon.ico deleted file mode 100644 index c370da518ec542579b7cc0d5d30f4778b4a96318..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 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/anything/any/path
: " + myrouteRequestPath) - }) - - // execute a route, similar to redirect but without redirect :) - app.Get("/execute_myroute", func(ctx iris.Context) { - ctx.Exec("GET", "/anything/any/path") // like it was called by the client. - }) - - // http://localhost:8080/reverse_myroute - // http://localhost:8080/execute_myroute - // http://localhost:8080/anything/any/path/here - // - // See view/template_html_4 example for more reverse routing examples - // using the reverse router component and the {{url}} and {{urlpath}} template functions. - app.Listen(":8080") -} diff --git a/_examples/routing/route-handlers-execution-rules/main.go b/_examples/routing/route-handlers-execution-rules/main.go deleted file mode 100644 index 5b503b7e..00000000 --- a/_examples/routing/route-handlers-execution-rules/main.go +++ /dev/null @@ -1,61 +0,0 @@ -/*Package main is a simple example of the behavior change of the execution flow of the handlers, -normally we need the `ctx.Next()` to call the next handler in a route's handler chain, -but with the `ExecutionRules` we can change this default behavior. -Please read below before continue. - -The `Party#SetExecutionRules` alters the execution flow of the route handlers. - -For example, if for some reason the desired result is the (done or all) handlers -to be executed no matter what, even if no `ctx.Next()` is called in the previous handlers: - -app.SetExecutionRules(iris.ExecutionRules { - Begin: iris.ExecutionOptions{Force: true}, # begin handlers(.Use) - Main: iris.ExecutionOptions{Force: true}, # main handler (.Handle/Get...) - Done: iris.ExecutionOptions{Force: true}, # done handlers (.Done) -}) - -Note that if `true` then the only remained way to "break" the handler chain -is by calling the `ctx.StopExecution()` (now that `ctx.Next()` doesn't even matter). - -These rules are per-party, so if a `Party` creates a child one then -the same rules will be applied to that as well. - -Reset of these rules to their defaults (before `Party#Handle`) can be done -with `Party#SetExecutionRules(iris.ExecutionRules{})`. - -*/ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - - app.SetExecutionRules(iris.ExecutionRules{ - // * From `Use[all]` to `Handle[last]` future route handlers, - // execute all (even if `ctx.Next()` is missing): - // Begin: true, - // - // * All `Handle` future route handlers, execute all: - // Main: true, - // - // * From `Handle[last]` to `Done[last]` future route handlers, execute all: - Done: iris.ExecutionOptions{Force: true}, - }) - app.Done(doneHandler) - - app.Get("/", mainHandler) - - // http://localhost:8080 - app.Listen(":8080") -} - -func mainHandler(ctx iris.Context) { - ctx.WriteString("From Main Handler\n") - // ctx.Next() is not required now that we have declared - // Done: iris.ExecutionOptions{Force: true}. -} - -func doneHandler(ctx iris.Context) { - ctx.WriteString("From Done Handler\n") -} diff --git a/_examples/routing/route-register-rule/main.go b/_examples/routing/route-register-rule/main.go deleted file mode 100644 index 31f5cb08..00000000 --- a/_examples/routing/route-register-rule/main.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := newApp() - // Navigate through https://github.com/kataras/iris/issues/1448 for details. - // - // GET: http://localhost:8080 - // POST, PUT, DELETE, CONNECT, HEAD, PATCH, OPTIONS, TRACE : http://localhost:8080 - app.Listen(":8080") -} - -func newApp() *iris.Application { - app := iris.New() - // Skip and do NOT override existing regitered route, continue normally. - // Applies to a Party and its children, in this case the whole application's routes. - app.SetRegisterRule(iris.RouteSkip) - - /* Read also: - // The default behavior, will override the getHandler to anyHandler on `app.Any` call. - app.SetRegistRule(iris.RouteOverride) - - // Stops the execution and fires an error before server boot. - app.SetRegisterRule(iris.RouteError) - - // If ctx.StopExecution or StopWithXXX then the next route will be executed - // (see mvc/authenticated-controller example too). - app.SetRegisterRule(iris.RouteOverlap) - */ - - app.Get("/", getHandler) - // app.Any does NOT override the previous GET route because of `iris.RouteSkip` rule. - app.Any("/", anyHandler) - - return app -} - -func getHandler(ctx iris.Context) { - ctx.Writef("From GET: %s", ctx.GetCurrentRoute().MainHandlerName()) -} - -func anyHandler(ctx iris.Context) { - ctx.Writef("From %s: %s", ctx.Method(), ctx.GetCurrentRoute().MainHandlerName()) -} diff --git a/_examples/routing/route-register-rule/main_test.go b/_examples/routing/route-register-rule/main_test.go deleted file mode 100644 index 9ac5ed9f..00000000 --- a/_examples/routing/route-register-rule/main_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/core/router" - "github.com/kataras/iris/v12/httptest" -) - -func TestRouteRegisterRuleExample(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - for _, method := range router.AllMethods { - tt := e.Request(method, "/").Expect().Status(httptest.StatusOK).Body() - if method == "GET" { - tt.Equal("From GET: iris/_examples/routing/route-register-rule.getHandler") - } else { - tt.Equal("From " + method + ": iris/_examples/routing/route-register-rule.anyHandler") - } - } -} diff --git a/_examples/routing/route-state/main.go b/_examples/routing/route-state/main.go deleted file mode 100644 index 6c362c11..00000000 --- a/_examples/routing/route-state/main.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - none := app.None("/invisible/{username}", func(ctx iris.Context) { - ctx.Writef("Hello %s with method: %s", ctx.Params().Get("username"), ctx.Method()) - - if from := ctx.Values().GetString("from"); from != "" { - ctx.Writef("\nI see that you're coming from %s", from) - } - }) - - app.Get("/change", func(ctx iris.Context) { - if none.IsOnline() { - none.Method = iris.MethodNone - } else { - none.Method = iris.MethodGet - } - - // refresh re-builds the router at serve-time in order to be notified for its new routes. - app.RefreshRouter() - }) - - app.Get("/execute", func(ctx iris.Context) { - if !none.IsOnline() { - ctx.Values().Set("from", "/execute with offline access") - ctx.Exec("NONE", "/invisible/iris") - return - } - - // same as navigating to "http://localhost:8080/invisible/iris" when /change has being invoked and route state changed - // from "offline" to "online" - ctx.Values().Set("from", "/execute") // values and session can be shared when calling Exec from a "foreign" context. - // ctx.Exec("NONE", "/invisible/iris") - // or after "/change": - ctx.Exec("GET", "/invisible/iris") - }) - - app.Listen(":8080") -} diff --git a/_examples/routing/sitemap/main.go b/_examples/routing/sitemap/main.go deleted file mode 100644 index 31b2a9f7..00000000 --- a/_examples/routing/sitemap/main.go +++ /dev/null @@ -1,38 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12" -) - -const startURL = "http://localhost:8080" - -func main() { - app := newApp() - - // http://localhost:8080/sitemap.xml - // Lists only online GET static routes. - // - // Reference: https://www.sitemaps.org/protocol.html - app.Listen(":8080", iris.WithSitemap(startURL)) -} - -func newApp() *iris.Application { - app := iris.New() - app.Logger().SetLevel("debug") - - lastModified, _ := time.Parse("2006-01-02T15:04:05-07:00", "2019-12-13T21:50:33+02:00") - app.Get("/home", handler).SetLastMod(lastModified).SetChangeFreq("hourly").SetPriority(1) - app.Get("/articles", handler).SetChangeFreq("daily") - app.Get("/path1", handler) - app.Get("/path2", handler) - - app.Post("/this-should-not-be-listed", handler) - app.Get("/this/{myparam}/should/not/be/listed", handler) - app.Get("/this-should-not-be-listed-offline", handler).SetStatusOffline() - - return app -} - -func handler(ctx iris.Context) { ctx.WriteString(ctx.Path()) } diff --git a/_examples/routing/sitemap/main_test.go b/_examples/routing/sitemap/main_test.go deleted file mode 100644 index 432fc9a5..00000000 --- a/_examples/routing/sitemap/main_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/httptest" -) - -func TestSitemap(t *testing.T) { - const expectedFullSitemapXML = `http://localhost:8080/home2019-12-13T21:50:33+02:00hourly1http://localhost:8080/articlesdailyhttp://localhost:8080/path1http://localhost:8080/path2` - - app := newApp() - app.Configure(iris.WithSitemap(startURL)) - - e := httptest.New(t, app) - e.GET("/sitemap.xml").Expect().Status(httptest.StatusOK).Body().Equal(expectedFullSitemapXML) -} diff --git a/_examples/routing/subdomains/multi/hosts b/_examples/routing/subdomains/multi/hosts deleted file mode 100644 index b862e00e..00000000 --- a/_examples/routing/subdomains/multi/hosts +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (c) 1993-2009 Microsoft Corp. -# -# This is a sample HOSTS file used by Microsoft TCP/IP for Windows. -# -# This file contains the mappings of IP addresses to host names. Each -# entry should be kept on an individual line. The IP address should -# be placed in the first column followed by the corresponding host name. -# The IP address and the host name should be separated by at least one -# space. -# -# Additionally, comments (such as these) may be inserted on individual -# lines or following the machine name denoted by a '#' symbol. -# -# For example: -# -# 102.54.94.97 rhino.acme.com # source server -# 38.25.63.10 x.acme.com # x client host - -# localhost name resolution is handled within DNS itself. -127.0.0.1 localhost -::1 localhost -#-iris-For development machine, you have to configure your dns also for online, search google how to do it if you don't know - -127.0.0.1 domain.local -127.0.0.1 system.domain.local -127.0.0.1 dashboard.domain.local - -#-END iris- diff --git a/_examples/routing/subdomains/multi/main.go b/_examples/routing/subdomains/multi/main.go deleted file mode 100644 index aa16296f..00000000 --- a/_examples/routing/subdomains/multi/main.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - /* - * Setup static files - */ - - app.HandleDir("/assets", iris.Dir("./public/assets")) - app.HandleDir("/upload_resources", iris.Dir("./public/upload_resources")) - - dashboard := app.Party("dashboard.") - { - dashboard.Get("/", func(ctx iris.Context) { - ctx.Writef("HEY FROM dashboard") - }) - } - system := app.Party("system.") - { - system.Get("/", func(ctx iris.Context) { - ctx.Writef("HEY FROM system") - }) - } - - app.Get("/", func(ctx iris.Context) { - ctx.Writef("HEY FROM frontend /") - }) - // http://domain.local:80 - // http://dashboard.local - // http://system.local - // Make sure you prepend the "http" in your browser - // because .local is a virtual domain we think to show case you - // that you can declare any syntactical correct name as a subdomain in iris. - app.Listen("domain.local:80") // for beginners: look ../hosts file -} diff --git a/_examples/routing/subdomains/multi/public/assets/images/test.ico b/_examples/routing/subdomains/multi/public/assets/images/test.ico deleted file mode 100644 index 961ef6dac80fa974d5bfeac74edcbf6797a7cd58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmZQzU<5(|0R|wcz>vYhz#zuJz@P!dKp~(AL>x#lFaYI*xgi+L9|pukV-}_kLpIJv zQ+|#q=Ijh@h8zryI&2*6Mw}e2K=x7#W`=p@tPB&(xtKCdBpB*V1sJMK1Q|Na`B@rG z1(?I#%q()8)#sI4h=)em>M&S2JM(3F>bI4eiMKQva!V##sW7LXidT?ggs-)JM3aWP$dz37yar#qcC!5ioZpDxhah$9!u!Umsr=<*gHaFE6Qf{E}`U;Z>jK8QYs-^)A;&anZC&_Xo@Bod1;D zNS767cxq0`x4WHTDigV~%XjPI3cIfb2EwTf4BBjS>OD72%(L5UE5OI?>Fp%Fw8iuC z#C-doZK>Ax`}6D{*19Q8j*j+_s86suRAescR+;S)Jg3I(X{Ec$iF{|Z(2hLk(;05M zj){I24FCUcXP92&*>Pfy-~akBgSnMS4pXYU)K@uqxpJq6Sl1R=%c}gpW5AG;=;l`x zX>~HyO@B*zkY$4tFxAGXi!&6ZxH9A=x?0Syb9+?msums@?Bts1q2Fp??ZD*eW+xqL zqswZcYXD5qT8v&^j)v|ow(jSQB_ snFam>g^)3(is2;kALvyWmh1tR867~(f#$;mpcn{0U|{%(q#mRX0B!x$?f?J) diff --git a/_examples/routing/subdomains/multi/public/upload_resources/favicon.ico b/_examples/routing/subdomains/multi/public/upload_resources/favicon.ico deleted file mode 100644 index c370da518ec542579b7cc0d5d30f4778b4a96318..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 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 http://www.mydomain.com - // http://mydomain.com/users -> http://www.mydomain.com/users - // http://mydomain.com/users/login -> http://www.mydomain.com/users/login - app.Listen(addr) -} - -func newApp() *iris.Application { - app := iris.New() - app.Get("/", func(ctx iris.Context) { - ctx.Writef("This will never be executed.") - }) - - www := app.Subdomain("www") // <- same as app.Party("www.") - www.Get("/", index) - - // www is an `iris.Party`, use it like you already know, like grouping routes. - www.PartyFunc("/users", func(p iris.Party) { // <- same as www.Party("/users").Get(...) - p.Get("/", usersIndex) - p.Get("/login", getLogin) - }) - - // redirects mydomain.com/%anypath% to www.mydomain.com/%anypath%. - // First argument is the 'from' and second is the 'to/target'. - app.SubdomainRedirect(app, www) - - // SubdomainRedirect works for multi-level subdomains as well: - // subsub := www.Subdomain("subsub") // subsub.www.mydomain.com - // subsub.Get("/", func(ctx iris.Context) { ctx.Writef("subdomain is: " + ctx.Subdomain()) }) - // app.SubdomainRedirect(subsub, www) - // - // If you need to redirect any subdomain to 'www' then: - // app.SubdomainRedirect(app.WildcardSubdomain(), www) - // If you need to redirect from a subdomain to the root domain then: - // app.SubdomainRedirect(app.Subdomain("mysubdomain"), app) - // - // Note that app.Party("mysubdomain.") and app.Subdomain("mysubdomain") - // is the same exactly thing, the difference is that the second can omit the last dot('.'). - - return app -} - -func index(ctx iris.Context) { - ctx.Writef("This is the www.mydomain.com endpoint.") -} - -func usersIndex(ctx iris.Context) { - ctx.Writef("This is the www.mydomain.com/users endpoint.") -} - -func getLogin(ctx iris.Context) { - ctx.Writef("This is the www.mydomain.com/users/login endpoint.") -} diff --git a/_examples/routing/subdomains/redirect/main_test.go b/_examples/routing/subdomains/redirect/main_test.go deleted file mode 100644 index d790c878..00000000 --- a/_examples/routing/subdomains/redirect/main_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "fmt" - "strings" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestSubdomainRedirectWWW(t *testing.T) { - app := newApp() - root := strings.TrimSuffix(addr, ":80") - - e := httptest.New(t, app) - - tests := []struct { - path string - response string - }{ - {"/", fmt.Sprintf("This is the www.%s endpoint.", root)}, - {"/users", fmt.Sprintf("This is the www.%s/users endpoint.", root)}, - {"/users/login", fmt.Sprintf("This is the www.%s/users/login endpoint.", root)}, - } - - for _, test := range tests { - e.GET(test.path).Expect().Status(httptest.StatusOK).Body().Equal(test.response) - } -} diff --git a/_examples/routing/subdomains/single/hosts b/_examples/routing/subdomains/single/hosts deleted file mode 100644 index e7f394a1..00000000 --- a/_examples/routing/subdomains/single/hosts +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) 1993-2009 Microsoft Corp. -# -# This is a sample HOSTS file used by Microsoft TCP/IP for Windows. -# -# This file contains the mappings of IP addresses to host names. Each -# entry should be kept on an individual line. The IP address should -# be placed in the first column followed by the corresponding host name. -# The IP address and the host name should be separated by at least one -# space. -# -# Additionally, comments (such as these) may be inserted on individual -# lines or following the machine name denoted by a '#' symbol. -# -# For example: -# -# 102.54.94.97 rhino.acme.com # source server -# 38.25.63.10 x.acme.com # x client host - -# localhost name resolution is handled within DNS itself. -127.0.0.1 localhost -::1 localhost -#-iris-For development machine, you have to configure your dns also for online, search google how to do it if you don't know - -127.0.0.1 mydomain.com -127.0.0.1 admin.mydomain.com - -#-END iris- diff --git a/_examples/routing/subdomains/single/main.go b/_examples/routing/subdomains/single/main.go deleted file mode 100644 index ef972c05..00000000 --- a/_examples/routing/subdomains/single/main.go +++ /dev/null @@ -1,44 +0,0 @@ -// Package main register static subdomains, simple as parties, check ./hosts if you use windows -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - // Subdomain method is just another Party. - admin := app.Subdomain("admin") - { - // admin.mydomain.com - admin.Get("/", func(c iris.Context) { - c.Writef("INDEX FROM admin.mydomain.com") - }) - // admin.mydomain.com/hey - admin.Get("/hey", func(c iris.Context) { - c.Writef("HEY FROM admin.mydomain.com/hey") - }) - // admin.mydomain.com/hey2 - admin.Get("/hey2", func(c iris.Context) { - c.Writef("HEY SECOND FROM admin.mydomain.com/hey") - }) - } - - // mydomain.com - app.Get("/", func(c iris.Context) { - c.Writef("INDEX FROM no-subdomain hey") - }) - - // mydomain.com/hey - app.Get("/hey", func(c iris.Context) { - c.Writef("HEY FROM no-subdomain hey") - }) - - // http://admin.mydomain.com - // http://admin.mydomain.com/hey - // http://admin.mydomain.com/hey2 - // http://mydomain.com - // http://mydomain.com/hey - app.Listen("mydomain.com:80") // for beginners: look ../hosts file -} diff --git a/_examples/routing/subdomains/wildcard/hosts b/_examples/routing/subdomains/wildcard/hosts deleted file mode 100644 index 3b3b5664..00000000 --- a/_examples/routing/subdomains/wildcard/hosts +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (c) 1993-2009 Microsoft Corp. -# -# This is a sample HOSTS file used by Microsoft TCP/IP for Windows. -# -# This file contains the mappings of IP addresses to host names. Each -# entry should be kept on an individual line. The IP address should -# be placed in the first column followed by the corresponding host name. -# The IP address and the host name should be separated by at least one -# space. -# -# Additionally, comments (such as these) may be inserted on individual -# lines or following the machine name denoted by a '#' symbol. -# -# For example: -# -# 102.54.94.97 rhino.acme.com # source server -# 38.25.63.10 x.acme.com # x client host - -# localhost name resolution is handled within DNS itself. -127.0.0.1 localhost -::1 localhost -#-iris-For development machine, you have to configure your dns also for online, search google how to do it if you don't know -127.0.0.1 mydomain.com -127.0.0.1 username1.mydomain.com -127.0.0.1 username2.mydomain.com -127.0.0.1 username3.mydomain.com -127.0.0.1 username4.mydomain.com -127.0.0.1 username5.mydomain.com - -#-END iris- diff --git a/_examples/routing/subdomains/wildcard/main.go b/_examples/routing/subdomains/wildcard/main.go deleted file mode 100644 index 2b78dfe8..00000000 --- a/_examples/routing/subdomains/wildcard/main.go +++ /dev/null @@ -1,71 +0,0 @@ -// Package main an example on how to catch dynamic subdomains - wildcard. -// On the first example we learnt how to create routes for static subdomains, subdomains you know that you will have. -// Here we will see an example how to catch unknown subdomains, dynamic subdomains, like username.mydomain.com:8080. -package main - -import ( - "github.com/kataras/iris/v12" -) - -// register a dynamic-wildcard subdomain to your server machine(dns/...) first, check ./hosts if you use windows. -// run this file and try to redirect: http://username1.mydomain.com:8080/ , http://username2.mydomain.com:8080/ , http://username1.mydomain.com/something, http://username1.mydomain.com/something/sadsadsa - -func main() { - app := iris.New() - - /* Keep note that you can use both type of subdomains (named and wildcard(*.) ) - admin.mydomain.com, and for other the Party(*.) but this is not this example's purpose - - admin := app.Party("admin.") - { - // admin.mydomain.com - admin.Get("/", func(ctx iris.Context) { - ctx.Writef("INDEX FROM admin.mydomain.com") - }) - // admin.mydomain.com/hey - admin.Get("/hey", func(ctx iris.Context) { - ctx.Writef("HEY FROM admin.mydomain.com/hey") - }) - // admin.mydomain.com/hey2 - admin.Get("/hey2", func(ctx iris.Context) { - ctx.Writef("HEY SECOND FROM admin.mydomain.com/hey") - }) - }*/ - - // no order, you can register subdomains at the end also. - dynamicSubdomains := app.Party("*.") - { - dynamicSubdomains.Get("/", dynamicSubdomainHandler) - - dynamicSubdomains.Get("/something", dynamicSubdomainHandler) - - dynamicSubdomains.Get("/something/{paramfirst}", dynamicSubdomainHandlerWithParam) - } - - app.Get("/", func(ctx iris.Context) { - ctx.Writef("Hello from mydomain.com path: %s", ctx.Path()) - }) - - app.Get("/hello", func(ctx iris.Context) { - ctx.Writef("Hello from mydomain.com path: %s", ctx.Path()) - }) - - // http://mydomain.com:8080 - // http://username1.mydomain.com:8080 - // http://username2.mydomain.com:8080/something - // http://username3.mydomain.com:8080/something/yourname - app.Listen("mydomain.com:8080") // for beginners: look ../hosts file -} - -func dynamicSubdomainHandler(ctx iris.Context) { - username := ctx.Subdomain() - ctx.Writef("Hello from dynamic subdomain path: %s, here you can handle the route for dynamic subdomains, handle the user: %s", ctx.Path(), username) - // if http://username4.mydomain.com:8080/ prints: - // Hello from dynamic subdomain path: /, here you can handle the route for dynamic subdomains, handle the user: username4 -} - -func dynamicSubdomainHandlerWithParam(ctx iris.Context) { - username := ctx.Subdomain() - ctx.Writef("Hello from dynamic subdomain path: %s, here you can handle the route for dynamic subdomains, handle the user: %s", ctx.Path(), username) - ctx.Writef("The paramfirst is: %s", ctx.Params().Get("paramfirst")) -} diff --git a/_examples/routing/subdomains/www/hosts b/_examples/routing/subdomains/www/hosts deleted file mode 100644 index ab304356..00000000 --- a/_examples/routing/subdomains/www/hosts +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 1993-2009 Microsoft Corp. -# -# This is a sample HOSTS file used by Microsoft TCP/IP for Windows. -# -# This file contains the mappings of IP addresses to host names. Each -# entry should be kept on an individual line. The IP address should -# be placed in the first column followed by the corresponding host name. -# The IP address and the host name should be separated by at least one -# space. -# -# Additionally, comments (such as these) may be inserted on individual -# lines or following the machine name denoted by a '#' symbol. -# -# For example: -# -# 102.54.94.97 rhino.acme.com # source server -# 38.25.63.10 x.acme.com # x client host - -# localhost name resolution is handled within DNS itself. -127.0.0.1 localhost -::1 localhost -#-iris-For development machine, you have to configure your dns also for online, search google how to do it if you don't know -127.0.0.1 mydomain.com -127.0.0.1 www.mydomain.com -#-END iris- diff --git a/_examples/routing/subdomains/www/main.go b/_examples/routing/subdomains/www/main.go deleted file mode 100644 index 280179a6..00000000 --- a/_examples/routing/subdomains/www/main.go +++ /dev/null @@ -1,79 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func newApp() *iris.Application { - app := iris.New() - - app.Get("/", info) - app.Get("/about", info) - app.Get("/contact", info) - - app.PartyFunc("/api/users", func(r iris.Party) { - r.Get("/", info) - r.Get("/{id:uint64}", info) - - r.Post("/", info) - - r.Put("/{id:uint64}", info) - }) /* <- same as: - usersAPI := app.Party("/api/users") - { // those brackets are just syntactic-sugar things. - // This method is rarely used but you can make use of it when you want - // scoped variables to that code block only. - usersAPI.Get/Post... - } - usersAPI.Get/Post... - */ - - www := app.Party("www.") - { - // Just to show how you can get all routes and copy them to another - // party or subdomain: - // Get all routes that are registered so far, including all "Parties" and subdomains: - currentRoutes := app.GetRoutes() - // Register them to the www subdomain/vhost as well: - for _, r := range currentRoutes { - www.Handle(r.Method, r.Tmpl().Src, r.Handlers...) - } - - // http://www.mydomain.com/hi - www.Get("/hi", func(ctx iris.Context) { - ctx.Writef("hi from www.mydomain.com") - }) - } - // See also the "subdomains/redirect" to register redirect router wrappers between subdomains, - // i.e mydomain.com to www.mydomain.com (like facebook does for SEO reasons(;)). - - return app -} - -func main() { - app := newApp() - // http://mydomain.com - // http://mydomain.com/about - // http://imydomain.com/contact - // http://mydomain.com/api/users - // http://mydomain.com/api/users/42 - - // http://www.mydomain.com - // http://www.mydomain.com/hi - // http://www.mydomain.com/about - // http://www.mydomain.com/contact - // http://www.mydomain.com/api/users - // http://www.mydomain.com/api/users/42 - if err := app.Listen("mydomain.com:80"); err != nil { - panic(err) - } -} - -func info(ctx iris.Context) { - method := ctx.Method() - subdomain := ctx.Subdomain() - path := ctx.Path() - - ctx.Writef("\nInfo\n\n") - ctx.Writef("Method: %s\nSubdomain: %s\nPath: %s", method, subdomain, path) -} diff --git a/_examples/routing/subdomains/www/main_test.go b/_examples/routing/subdomains/www/main_test.go deleted file mode 100644 index 10686065..00000000 --- a/_examples/routing/subdomains/www/main_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package main - -import ( - "fmt" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -type testRoute struct { - path string - method string - subdomain string -} - -func (r testRoute) response() string { - msg := fmt.Sprintf("\nInfo\n\nMethod: %s\nSubdomain: %s\nPath: %s", r.method, r.subdomain, r.path) - return msg -} - -func TestSubdomainWWW(t *testing.T) { - app := newApp() - - tests := []testRoute{ - // host - {"/", "GET", ""}, - {"/about", "GET", ""}, - {"/contact", "GET", ""}, - {"/api/users", "GET", ""}, - {"/api/users/42", "GET", ""}, - {"/api/users", "POST", ""}, - {"/api/users/42", "PUT", ""}, - // www sub domain - {"/", "GET", "www"}, - {"/about", "GET", "www"}, - {"/contact", "GET", "www"}, - {"/api/users", "GET", "www"}, - {"/api/users/42", "GET", "www"}, - {"/api/users", "POST", "www"}, - {"/api/users/42", "PUT", "www"}, - } - - host := "localhost:1111" - e := httptest.New(t, app, httptest.Debug(false)) - - for _, test := range tests { - - req := e.Request(test.method, test.path) - if subdomain := test.subdomain; subdomain != "" { - req.WithURL("http://" + subdomain + "." + host) - } - - req.Expect(). - Status(httptest.StatusOK). - Body().Equal(test.response()) - } -} diff --git a/_examples/routing/versioning/main.go b/_examples/routing/versioning/main.go deleted file mode 100644 index 3502173f..00000000 --- a/_examples/routing/versioning/main.go +++ /dev/null @@ -1,78 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/versioning" -) - -func main() { - app := iris.New() - - examplePerRoute(app) - examplePerParty(app) - - // Read the README.md before any action. - app.Listen(":8080") -} - -// How to test: -// Open Postman -// GET: localhost:8080/api/cats -// Headers[1] = Accept-Version: "1" and repeat with -// Headers[1] = Accept-Version: "2.5" -// or even "Accept": "application/json; version=2.5" -func examplePerRoute(app *iris.Application) { - app.Get("/api/cats", versioning.NewMatcher(versioning.Map{ - "1": catsVersionExactly1Handler, - ">= 2, < 3": catsV2Handler, - versioning.NotFound: versioning.NotFoundHandler, - })) -} - -// How to test: -// Open Postman -// GET: localhost:8080/api/users -// Headers[1] = Accept-Version: "1.9.9" and repeat with -// Headers[1] = Accept-Version: "2.5" -// -// POST: localhost:8080/api/users/new -// Headers[1] = Accept-Version: "1.8.3" -// -// POST: localhost:8080/api/users -// Headers[1] = Accept-Version: "2" -func examplePerParty(app *iris.Application) { - usersAPI := app.Party("/api/users") - // You can customize the way a version is extracting - // via middleware, for example: - // version url parameter, and, if it's missing we default it to "1". - usersAPI.Use(func(ctx iris.Context) { - versioning.SetVersion(ctx, ctx.URLParamDefault("version", "1")) - ctx.Next() - }) - - // version 1. - usersAPIV1 := versioning.NewGroup(usersAPI, ">= 1, < 2") - usersAPIV1.Get("/", func(ctx iris.Context) { - ctx.Writef("v1 resource: /api/users handler") - }) - usersAPIV1.Post("/new", func(ctx iris.Context) { - ctx.Writef("v1 resource: /api/users/new post handler") - }) - - // version 2. - usersAPIV2 := versioning.NewGroup(usersAPI, ">= 2, < 3") - usersAPIV2.Get("/", func(ctx iris.Context) { - ctx.Writef("v2 resource: /api/users handler") - }) - usersAPIV2.Post("/", func(ctx iris.Context) { - ctx.Writef("v2 resource: /api/users post handler") - }) -} - -func catsVersionExactly1Handler(ctx iris.Context) { - ctx.Writef("v1 exactly resource: /api/cats handler") -} - -func catsV2Handler(ctx iris.Context) { - ctx.Writef("v2 resource: /api/cats handler") -} diff --git a/_examples/routing/writing-a-middleware/globally/main.go b/_examples/routing/writing-a-middleware/globally/main.go deleted file mode 100644 index 2cd92e94..00000000 --- a/_examples/routing/writing-a-middleware/globally/main.go +++ /dev/null @@ -1,69 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - // register the "before" handler as the first handler which will be executed - // on all domain's routes. - // Or use the `UseGlobal` to register a middleware which will fire across subdomains. - // app.Use(before) - // register the "after" handler as the last handler which will be executed - // after all domain's routes' handler(s). - // - // Or use the `DoneGlobal` to append handlers that will be fired globally. - // app.Done(after) - - // register our routes. - app.Get("/", indexHandler) - app.Get("/contact", contactHandler) - - // Order of those calls doesn't matter, `UseGlobal` and `DoneGlobal` - // are applied to existing routes and future routes. - // - // Remember: the `Use` and `Done` are applied to the current party's and its children, - // so if we used the `app.Use/Done` before the routes registration - // it would work like UseGlobal/DoneGlobal in this case, because the `app` is the root party. - // - // See `app.Party/PartyFunc` for more. - app.UseGlobal(before) - app.DoneGlobal(after) - - app.Listen(":8080") -} - -func before(ctx iris.Context) { - shareInformation := "this is a sharable information between handlers" - - requestPath := ctx.Path() - println("Before the indexHandler or contactHandler: " + requestPath) - - ctx.Values().Set("info", shareInformation) - ctx.Next() -} - -func after(ctx iris.Context) { - println("After the indexHandler or contactHandler") -} - -func indexHandler(ctx iris.Context) { - println("Inside indexHandler") - - // take the info from the "before" handler. - info := ctx.Values().GetString("info") - - // write something to the client as a response. - ctx.HTML("

Response

") - ctx.HTML("
Info: " + info) - - ctx.Next() // execute the "after" handler registered via `DoneGlobal`. -} - -func contactHandler(ctx iris.Context) { - println("Inside contactHandler") - - // write something to the client as a response. - ctx.HTML("

Contact

") - - ctx.Next() // execute the "after" handler registered via `DoneGlobal`. -} diff --git a/_examples/routing/writing-a-middleware/per-route/main.go b/_examples/routing/writing-a-middleware/per-route/main.go deleted file mode 100644 index 223a019f..00000000 --- a/_examples/routing/writing-a-middleware/per-route/main.go +++ /dev/null @@ -1,69 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - // or app.Use(before) and app.Done(after). - app.Get("/", before, mainHandler, after) - - // Use registers a middleware(prepend handlers) to all party's, and its children that will be registered - // after. - // - // (`app` is the root children so those use and done handlers will be registered everywhere) - app.Use(func(ctx iris.Context) { - println(`before the party's routes and its children, -but this is not applied to the '/' route -because it's registered before the middleware, order matters.`) - ctx.Next() - }) - - app.Done(func(ctx iris.Context) { - println("this is executed always last, if the previous handler calls the `ctx.Next()`, it's the reverse of `.Use`") - message := ctx.Values().GetString("message") - println("message: " + message) - }) - - app.Get("/home", func(ctx iris.Context) { - ctx.HTML("

Home

") - ctx.Values().Set("message", "this is the home message, ip: "+ctx.RemoteAddr()) - ctx.Next() // call the done handlers. - }) - - child := app.Party("/child") - child.Get("/", func(ctx iris.Context) { - ctx.Writef(`this is the localhost:8080/child route. -All Use and Done handlers that are registered to the parent party, -are applied here as well.`) - ctx.Next() // call the done handlers. - }) - - app.Listen(":8080") -} - -func before(ctx iris.Context) { - shareInformation := "this is a sharable information between handlers" - - requestPath := ctx.Path() - println("Before the mainHandler: " + requestPath) - - ctx.Values().Set("info", shareInformation) - ctx.Next() // execute the next handler, in this case the main one. -} - -func after(ctx iris.Context) { - println("After the mainHandler") -} - -func mainHandler(ctx iris.Context) { - println("Inside mainHandler") - - // take the info from the "before" handler. - info := ctx.Values().GetString("info") - - // write something to the client as a response. - ctx.HTML("

Response

") - ctx.HTML("
Info: " + info) - - ctx.Next() // execute the "after". -} diff --git a/_examples/sessions/basic/main.go b/_examples/sessions/basic/main.go deleted file mode 100644 index 5827ed88..00000000 --- a/_examples/sessions/basic/main.go +++ /dev/null @@ -1,51 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - - "github.com/kataras/iris/v12/sessions" -) - -const cookieNameForSessionID = "session_id_cookie" - -func secret(ctx iris.Context) { - // Check if user is authenticated - if auth, _ := sessions.Get(ctx).GetBoolean("authenticated"); !auth { - ctx.StatusCode(iris.StatusForbidden) - return - } - - // Print secret message - ctx.WriteString("The cake is a lie!") -} - -func login(ctx iris.Context) { - session := sessions.Get(ctx) - - // Authentication goes here - // ... - - // Set user as authenticated - session.Set("authenticated", true) -} - -func logout(ctx iris.Context) { - session := sessions.Get(ctx) - - // Revoke users authentication - session.Set("authenticated", false) -} - -func main() { - app := iris.New() - sess := sessions.New(sessions.Config{Cookie: cookieNameForSessionID, AllowReclaim: true}) - app.Use(sess.Handler()) - // ^ or comment this line and use sess.Start(ctx) inside your handlers - // instead of sessions.Get(ctx). - - app.Get("/secret", secret) - app.Get("/login", login) - app.Get("/logout", logout) - - app.Listen(":8080") -} diff --git a/_examples/sessions/database/badger/main.go b/_examples/sessions/database/badger/main.go deleted file mode 100644 index d49c1dbb..00000000 --- a/_examples/sessions/database/badger/main.go +++ /dev/null @@ -1,56 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12" - - "github.com/kataras/iris/v12/sessions" - "github.com/kataras/iris/v12/sessions/sessiondb/badger" - - "github.com/kataras/iris/v12/_examples/sessions/overview/example" -) - -func main() { - db, err := badger.New("./data") - if err != nil { - panic(err) - } - - // close and unlock the database when control+C/cmd+C pressed - iris.RegisterOnInterrupt(func() { - db.Close() - }) - - defer db.Close() // close and unlock the database if application errored. - - // The default transcoder is the JSON one, - // based on the https://golang.org/pkg/encoding/json/#Unmarshal - // you can only retrieve numbers as float64 types: - // * bool, for booleans - // * float64, for numbers - // * string, for strings - // * []interface{}, for arrays - // * map[string]interface{}, for objects. - // If you want to save the data per go-specific types - // you should change the DefaultTranscoder to the GobTranscoder one: - // sessions.DefaultTranscoder = sessions.GobTranscoder{} - - sess := sessions.New(sessions.Config{ - Cookie: "sessionscookieid", - Expires: 1 * time.Minute, // <=0 means unlimited life. Defaults to 0. - AllowReclaim: true, - }) - - sess.OnDestroy(func(sid string) { - println(sid + " expired and destroyed from memory and its values from database") - }) - - // - // IMPORTANT: - // - sess.UseDatabase(db) - - app := example.NewApp(sess) - app.Listen(":8080") -} diff --git a/_examples/sessions/database/boltdb/main.go b/_examples/sessions/database/boltdb/main.go deleted file mode 100644 index 11bc9621..00000000 --- a/_examples/sessions/database/boltdb/main.go +++ /dev/null @@ -1,63 +0,0 @@ -package main - -import ( - "os" - "time" - - "github.com/kataras/iris/v12" - - "github.com/kataras/iris/v12/sessions" - "github.com/kataras/iris/v12/sessions/sessiondb/boltdb" - - "github.com/kataras/iris/v12/_examples/sessions/overview/example" -) - -func main() { - db, err := boltdb.New("./sessions.db", os.FileMode(0750)) - if err != nil { - panic(err) - } - - // close and unlobkc the database when control+C/cmd+C pressed - iris.RegisterOnInterrupt(func() { - db.Close() - }) - - defer db.Close() // close and unlock the database if application errored. - sess := sessions.New(sessions.Config{ - Cookie: "sessionscookieid", - Expires: 45 * time.Minute, // <=0 means unlimited life. Defaults to 0. - AllowReclaim: true, - }) - - // - // IMPORTANT: - // - sess.UseDatabase(db) - - // The default database's values encoder and decoder - // calls the value's `Marshal/Unmarshal` methods (if any) - // otherwise JSON is selected, - // the JSON format can be stored to any database and - // it supports both builtin language types(e.g. string, int) and custom struct values. - // Also, and the most important, the values can be - // retrieved/logged/monitored by a third-party program - // written in any other language as well. - // - // You can change this behavior by registering a custom `Transcoder`. - // Iris provides a `GobTranscoder` which is mostly suitable - // if your session values are going to be custom Go structs. - // Select this if you always retrieving values through Go. - // Don't forget to initialize a call of gob.Register when necessary. - // Read https://golang.org/pkg/encoding/gob/ for more. - // - // You can also implement your own `sessions.Transcoder` and use it, - // i.e: a transcoder which will allow(on Marshal: return its byte representation and nil error) - // or dissalow(on Marshal: return non nil error) certain types. - // - // gob.Register(example.BusinessModel{}) - // sessions.DefaultTranscoder = sessions.GobTranscoder{} - - app := example.NewApp(sess) - app.Listen(":8080") -} diff --git a/_examples/sessions/database/redis/Dockerfile b/_examples/sessions/database/redis/Dockerfile deleted file mode 100644 index a1d50355..00000000 --- a/_examples/sessions/database/redis/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM golang:latest AS builder -RUN apt-get update -WORKDIR /go/src/app -ENV GO111MODULE=on \ - CGO_ENABLED=0 \ - GOOS=linux \ - GOARCH=amd64 -# Caching go modules and build the binary. -COPY go.mod . -RUN go mod download -COPY . . -RUN go install - -FROM scratch -COPY --from=builder /go/bin/app . -ENTRYPOINT ["./app"] \ No newline at end of file diff --git a/_examples/sessions/database/redis/docker-compose.yml b/_examples/sessions/database/redis/docker-compose.yml deleted file mode 100644 index 324b7534..00000000 --- a/_examples/sessions/database/redis/docker-compose.yml +++ /dev/null @@ -1,24 +0,0 @@ -# docker-compose up [--build] -version: '3' - -services: - redis-server: - image: redis - app1: - build: . - depends_on: - - redis-server - ports: - - 8080:8080 - environment: - - PORT=8080 - - REDIS_ADDR=redis-server:6379 - app2: - build: . - depends_on: - - redis-server - ports: - - 9090:9090 - environment: - - PORT=9090 - - REDIS_ADDR=redis-server:6379 \ No newline at end of file diff --git a/_examples/sessions/database/redis/go.mod b/_examples/sessions/database/redis/go.mod deleted file mode 100644 index 549a5828..00000000 --- a/_examples/sessions/database/redis/go.mod +++ /dev/null @@ -1,6 +0,0 @@ -module app - -go 1.15 - -require github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd - diff --git a/_examples/sessions/database/redis/main.go b/_examples/sessions/database/redis/main.go deleted file mode 100644 index f8333dc7..00000000 --- a/_examples/sessions/database/redis/main.go +++ /dev/null @@ -1,77 +0,0 @@ -package main - -import ( - "fmt" - "os" - "strings" - "time" - - "github.com/kataras/iris/v12" - - "github.com/kataras/iris/v12/sessions" - "github.com/kataras/iris/v12/sessions/sessiondb/redis" - - "github.com/kataras/iris/v12/_examples/sessions/overview/example" -) - -// tested with redis version 3.0.503. -// for windows see: https://github.com/ServiceStack/redis-windows -func main() { - // These are the default values, - // you can replace them based on your running redis' server settings: - db := redis.New(redis.Config{ - Network: "tcp", - Addr: getenv("REDIS_ADDR", "127.0.0.1:6379"), - Timeout: time.Duration(30) * time.Second, - MaxActive: 10, - Password: "", - Database: "", - Prefix: "", - Delim: "-", - Driver: redis.Redigo(), // redis.Radix() can be used instead. - }) - - // Optionally configure the underline driver: - // driver := redis.Redigo() - // driver.MaxIdle = ... - // driver.IdleTimeout = ... - // driver.Wait = ... - // redis.Config {Driver: driver} - - // Close connection when control+C/cmd+C - iris.RegisterOnInterrupt(func() { - db.Close() - }) - - defer db.Close() // close the database connection if application errored. - - sess := sessions.New(sessions.Config{ - Cookie: "_session_id", - Expires: 0, // defaults to 0: unlimited life. Another good value is: 45 * time.Minute, - AllowReclaim: true, - CookieSecureTLS: true, - }) - - // - // IMPORTANT: - // - sess.UseDatabase(db) - - app := example.NewApp(sess) - - // TIP scaling-out Iris sessions using redis: - // $ docker-compose up - // http://localhost:8080/set/$key/$value - // The value will be available on all Iris servers as well. - // E.g. http://localhost:9090/get/$key and vice versa. - addr := fmt.Sprintf(":%s", getenv("PORT", "8080")) - app.Listen(addr) -} - -func getenv(key string, def string) string { - if v := os.Getenv(strings.ToUpper(key)); v != "" { - return v - } - - return def -} diff --git a/_examples/sessions/flash-messages/main.go b/_examples/sessions/flash-messages/main.go deleted file mode 100644 index acd2a5dd..00000000 --- a/_examples/sessions/flash-messages/main.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - - "github.com/kataras/iris/v12/sessions" -) - -func main() { - app := iris.New() - - sess := sessions.New(sessions.Config{Cookie: "_session_id", AllowReclaim: true}) - app.Use(sess.Handler()) - - app.Get("/set", func(ctx iris.Context) { - s := sessions.Get(ctx) - s.SetFlash("name", "iris") - ctx.Writef("Message set, is available for the next request") - }) - - app.Get("/get", func(ctx iris.Context) { - s := sessions.Get(ctx) - name := s.GetFlashString("name") - if name == "" { - ctx.Writef("Empty name!!") - return - } - ctx.Writef("Hello %s", name) - }) - - app.Get("/test", func(ctx iris.Context) { - s := sessions.Get(ctx) - name := s.GetFlashString("name") - if name == "" { - ctx.Writef("Empty name!!") - return - } - - ctx.Writef("Ok you are coming from /set ,the value of the name is %s", name) - ctx.Writef(", and again from the same context: %s", name) - }) - - app.Listen(":8080") -} diff --git a/_examples/sessions/overview/example/example.go b/_examples/sessions/overview/example/example.go deleted file mode 100644 index 64509b51..00000000 --- a/_examples/sessions/overview/example/example.go +++ /dev/null @@ -1,187 +0,0 @@ -package example - -import ( - "errors" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/sessions" -) - -// BusinessModel is just a Go struct value that we will use in our session example, -// never save sensitive information, like passwords, here. -type BusinessModel struct { - Name string -} - -// NewApp returns a new application for showcasing the sessions feature. -func NewApp(sess *sessions.Sessions) *iris.Application { - app := iris.New() - app.Use(sess.Handler()) // session is always non-nil inside handlers now. - - app.Get("/", func(ctx iris.Context) { - session := sessions.Get(ctx) // same as sess.Start(ctx, cookieOptions...) - if session.Len() == 0 { - ctx.HTML(`no session values stored yet. Navigate to: set page`) - return - } - - ctx.HTML("
    ") - session.Visit(func(key string, value interface{}) { - ctx.HTML("
  • %s = %v
  • ", key, value) - }) - - ctx.HTML("
") - }) - - // set session values. - app.Get("/set", func(ctx iris.Context) { - session := sessions.Get(ctx) - isNew := session.IsNew() - - session.Set("name", "iris") - - ctx.Writef("All ok session set to: %s [isNew=%t]", session.GetString("name"), isNew) - }) - - app.Get("/get", func(ctx iris.Context) { - session := sessions.Get(ctx) - - // get a specific value, as string, - // if not found then it returns just an empty string. - name := session.GetString("name") - - ctx.Writef("The name on the /set was: %s", name) - }) - - app.Get("/set-struct", func(ctx iris.Context) { - session := sessions.Get(ctx) - session.Set("struct", BusinessModel{Name: "John Doe"}) - - ctx.Writef("All ok session value of the 'struct' is: %v", session.Get("struct")) - }) - - app.Get("/get-struct", func(ctx iris.Context) { - session := sessions.Get(ctx) - ctx.Writef("Session value of the 'struct' is: %v", session.Get("struct")) - }) - - app.Get("/set/{key}/{value}", func(ctx iris.Context) { - session := sessions.Get(ctx) - - key := ctx.Params().Get("key") - value := ctx.Params().Get("value") - isNew := session.IsNew() - - session.Set(key, value) - - ctx.Writef("All ok session value of the '%s' is: %s [isNew=%t]", key, session.GetString(key), isNew) - }) - - app.Get("/get/{key}", func(ctx iris.Context) { - session := sessions.Get(ctx) - // get a specific key, as string, if no found returns just an empty string - key := ctx.Params().Get("key") - value := session.Get(key) - - ctx.Writef("The [%s:%T] on the /set was: %v", key, value, value) - }) - - app.Get("/set/{type}/{key}/{value}", func(ctx iris.Context) { - session := sessions.Get(ctx) - - key := ctx.Params().Get("key") - var value interface{} - - switch ctx.Params().Get("type") { - case "int": - value = ctx.Params().GetIntDefault("value", 0) - case "float64": - value = ctx.Params().GetFloat64Default("value", 0.0) - default: - value = ctx.Params().Get("value") - } - session.Set(key, value) - - value = session.Get(key) - ctx.Writef("Key: %s, Type: %T, Value: %v", key, value, value) - }) - - app.Get("/delete", func(ctx iris.Context) { - session := sessions.Get(ctx) - // delete a specific key - session.Delete("name") - }) - - app.Get("/clear", func(ctx iris.Context) { - session := sessions.Get(ctx) - // removes all entries. - session.Clear() - }) - - app.Get("/update", func(ctx iris.Context) { - session := sessions.Get(ctx) - // shifts the expiration based on the session's `Lifetime`. - if err := session.Man.ShiftExpiration(ctx); err != nil { - if errors.Is(err, sessions.ErrNotFound) { - ctx.StatusCode(iris.StatusNotFound) - } else if errors.Is(err, sessions.ErrNotImplemented) { - ctx.StatusCode(iris.StatusNotImplemented) - } else { - ctx.StatusCode(iris.StatusNotModified) - } - - ctx.Writef("%v", err) - ctx.Application().Logger().Error(err) - } - }) - - app.Get("/destroy", func(ctx iris.Context) { - session := sessions.Get(ctx) - // Man(anager)'s Destroy, removes the entire session data and cookie - session.Man.Destroy(ctx) - }) - - // Note about Destroy: - // - // You can destroy a session outside of a handler too, using the: - // sess.DestroyByID - // sess.DestroyAll - - // remember: slices and maps are muttable by-design - // The `SetImmutable` makes sure that they will be stored and received - // as immutable, so you can't change them directly by mistake. - // - // Use `SetImmutable` consistently, it's slower than `Set`. - // Read more about muttable and immutable go types: https://stackoverflow.com/a/8021081 - app.Get("/set-immutable", func(ctx iris.Context) { - session := sessions.Get(ctx) - - business := []BusinessModel{{Name: "Edward"}, {Name: "value 2"}} - session.SetImmutable("businessEdit", business) - businessGet := session.Get("businessEdit").([]BusinessModel) - - // try to change it, if we used `Set` instead of `SetImmutable` this - // change will affect the underline array of the session's value "businessEdit", but now it will not. - businessGet[0].Name = "Gabriel" - }) - - app.Get("/get-immutable", func(ctx iris.Context) { - valSlice := sessions.Get(ctx).Get("businessEdit") - if valSlice == nil { - ctx.HTML("please navigate to the /set-immutable first") - return - } - - firstModel := valSlice.([]BusinessModel)[0] - // businessGet[0].Name is equal to Edward initially - if firstModel.Name != "Edward" { - panic("Report this as a bug, immutable data cannot be changed from the caller without re-SetImmutable") - } - - ctx.Writef("[]businessModel[0].Name remains: %s", firstModel.Name) - - // the name should remains "Edward" - }) - - return app -} diff --git a/_examples/sessions/overview/main.go b/_examples/sessions/overview/main.go deleted file mode 100644 index d04462ae..00000000 --- a/_examples/sessions/overview/main.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12/_examples/sessions/overview/example" - "github.com/kataras/iris/v12/sessions" -) - -func main() { - sess := sessions.New(sessions.Config{ - // Cookie string, the session's client cookie name, for example: "_session_id" - // - // Defaults to "irissessionid" - Cookie: "_session_id", - // it's time.Duration, from the time cookie is created, how long it can be alive? - // 0 means no expire, unlimited life. - // -1 means expire when browser closes - // or set a value, like 2 hours: - Expires: time.Hour * 2, - // if you want to invalid cookies on different subdomains - // of the same host, then enable it. - // Defaults to false. - DisableSubdomainPersistence: false, - // Allow getting the session value stored by the request from the same request. - AllowReclaim: true, - /* - SessionIDGenerator: func(ctx iris.Context) string { - id:= ctx.GetHeader("X-Session-Id") - if id == "" { - id = // [generate ID here and set the header] - ctx.Header("X-Session-Id", id) - } - - return id - }, - */ - }) - - app := example.NewApp(sess) - app.Listen(":8080") -} diff --git a/_examples/sessions/securecookie/main.go b/_examples/sessions/securecookie/main.go deleted file mode 100644 index b2686626..00000000 --- a/_examples/sessions/securecookie/main.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -// developers can use any library to add a custom cookie encoder/decoder. -// At this example we use the gorilla's securecookie package: -// $ go get github.com/gorilla/securecookie -// $ go run main.go - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/sessions" - - "github.com/kataras/iris/v12/_examples/sessions/overview/example" - - "github.com/gorilla/securecookie" -) - -func newApp() *iris.Application { - app := iris.New() - - cookieName := "_session_id" - // AES only supports key sizes of 16, 24 or 32 bytes. - // You either need to provide exactly that amount or you derive the key from what you type in. - hashKey := securecookie.GenerateRandomKey(64) - blockKey := securecookie.GenerateRandomKey(32) - s := securecookie.New(hashKey, blockKey) - - mySessions := sessions.New(sessions.Config{ - Cookie: cookieName, - Encoding: s, - AllowReclaim: true, - }) - - app = example.NewApp(mySessions) - return app -} - -func main() { - app := newApp() - app.Listen(":8080") -} diff --git a/_examples/sessions/securecookie/main_test.go b/_examples/sessions/securecookie/main_test.go deleted file mode 100644 index 775c698d..00000000 --- a/_examples/sessions/securecookie/main_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/httptest" -) - -func TestSessionsEncodeDecode(t *testing.T) { - app := newApp() - e := httptest.New(t, app, httptest.URL("http://example.com")) - - es := e.GET("/set").Expect() - es.Status(iris.StatusOK) - es.Cookies().NotEmpty() - es.Body().Equal("All ok session set to: iris [isNew=true]") - - e.GET("/get").Expect().Status(iris.StatusOK).Body().Equal("The name on the /set was: iris") - // delete and re-get - e.GET("/delete").Expect().Status(iris.StatusOK) - e.GET("/get").Expect().Status(iris.StatusOK).Body().Equal("The name on the /set was: ") - // set, clear and re-get - e.GET("/set").Expect().Body().Equal("All ok session set to: iris [isNew=false]") - e.GET("/clear").Expect().Status(iris.StatusOK) - e.GET("/get").Expect().Status(iris.StatusOK).Body().Equal("The name on the /set was: ") -} diff --git a/_examples/testing/httptest/main.go b/_examples/testing/httptest/main.go deleted file mode 100644 index c86fc7fc..00000000 --- a/_examples/testing/httptest/main.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/basicauth" -) - -func newApp() *iris.Application { - app := iris.New() - - authConfig := basicauth.Config{ - Users: map[string]string{"myusername": "mypassword"}, - } - - authentication := basicauth.New(authConfig) - - app.Get("/", func(ctx iris.Context) { ctx.Redirect("/admin") }) - - // to party - - needAuth := app.Party("/admin", authentication) - { - //http://localhost:8080/admin - needAuth.Get("/", h) - // http://localhost:8080/admin/profile - needAuth.Get("/profile", h) - - // http://localhost:8080/admin/settings - needAuth.Get("/settings", h) - } - - return app -} - -func h(ctx iris.Context) { - username, password, _ := ctx.Request().BasicAuth() - // third parameter it will be always true because the middleware - // makes sure for that, otherwise this handler will not be executed. - - ctx.Writef("%s %s:%s", ctx.Path(), username, password) -} - -func main() { - app := newApp() - app.Listen(":8080") -} diff --git a/_examples/testing/httptest/main_test.go b/_examples/testing/httptest/main_test.go deleted file mode 100644 index 9c3723bc..00000000 --- a/_examples/testing/httptest/main_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/httptest" -) - -// $ go test -v -func TestNewApp(t *testing.T) { - app := newApp() - e := httptest.New(t, app) - - // redirects to /admin without basic auth - e.GET("/").Expect().Status(httptest.StatusUnauthorized) - // without basic auth - e.GET("/admin").Expect().Status(httptest.StatusUnauthorized) - - // with valid basic auth - e.GET("/admin").WithBasicAuth("myusername", "mypassword").Expect(). - Status(httptest.StatusOK).Body().Equal("/admin myusername:mypassword") - e.GET("/admin/profile").WithBasicAuth("myusername", "mypassword").Expect(). - Status(httptest.StatusOK).Body().Equal("/admin/profile myusername:mypassword") - e.GET("/admin/settings").WithBasicAuth("myusername", "mypassword").Expect(). - Status(httptest.StatusOK).Body().Equal("/admin/settings myusername:mypassword") - - // with invalid basic auth - e.GET("/admin/settings").WithBasicAuth("invalidusername", "invalidpassword"). - Expect().Status(httptest.StatusUnauthorized) -} - -func TestHandlerUsingNetHTTP(t *testing.T) { - handler := func(ctx iris.Context) { - ctx.WriteString("Hello, World!") - } - - // A shortcut for net/http/httptest.NewRecorder/NewRequest. - w := httptest.NewRecorder() - r := httptest.NewRequest("GET", "/", nil) - - httptest.Do(w, r, handler) - if expected, got := "Hello, World!", w.Body.String(); expected != got { - t.Fatalf("expected body: %s but got: %s", expected, got) - } -} diff --git a/_examples/url-shortener/README.md b/_examples/url-shortener/README.md deleted file mode 100644 index 842caed1..00000000 --- a/_examples/url-shortener/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## A URL Shortener Service using Go, Iris and Bolt - -Hackernoon Article: https://medium.com/hackernoon/a-url-shortener-service-using-go-iris-and-bolt-4182f0b00ae7 \ No newline at end of file diff --git a/_examples/url-shortener/factory.go b/_examples/url-shortener/factory.go deleted file mode 100644 index d3e71952..00000000 --- a/_examples/url-shortener/factory.go +++ /dev/null @@ -1,52 +0,0 @@ -package main - -import ( - "net/url" - - "github.com/google/uuid" -) - -// Generator the type to generate keys(short urls) -type Generator func() string - -// DefaultGenerator is the defautl url generator -var DefaultGenerator = func() string { - id, _ := uuid.NewRandom() - return id.String() -} - -// Factory is responsible to generate keys(short urls) -type Factory struct { - store Store - generator Generator -} - -// NewFactory receives a generator and a store and returns a new url Factory. -func NewFactory(generator Generator, store Store) *Factory { - return &Factory{ - store: store, - generator: generator, - } -} - -// Gen generates the key. -func (f *Factory) Gen(uri string) (key string, err error) { - // we don't return the parsed url because #hash are converted to uri-compatible - // and we don't want to encode/decode all the time, there is no need for that, - // we save the url as the user expects if the uri validation passed. - _, err = url.ParseRequestURI(uri) - if err != nil { - return "", err - } - - key = f.generator() - // Make sure that the key is unique - for { - if v := f.store.Get(key); v == "" { - break - } - key = f.generator() - } - - return key, nil -} diff --git a/_examples/url-shortener/main.go b/_examples/url-shortener/main.go deleted file mode 100644 index 5e140d6f..00000000 --- a/_examples/url-shortener/main.go +++ /dev/null @@ -1,114 +0,0 @@ -// Package main shows how you can create a simple URL Shortener. -// -// Article: https://medium.com/@kataras/a-url-shortener-service-using-go-iris-and-bolt-4182f0b00ae7 -// -// $ go get go.etcd.io/bbolt/... -// $ go get github.com/google/uuid -// $ cd $GOPATH/src/github.com/kataras/iris/_examples/url-shortener -// $ go build -// $ ./url-shortener -package main - -import ( - "html/template" - - "github.com/kataras/iris/v12" -) - -func main() { - // assign a variable to the DB so we can use its features later. - db := NewDB("shortener.db") - // Pass that db to our app, in order to be able to test the whole app with a different database later on. - app := newApp(db) - - // release the "db" connection when server goes off. - iris.RegisterOnInterrupt(db.Close) - - app.Listen(":8080") -} - -func newApp(db *DB) *iris.Application { - app := iris.Default() // or app := iris.New() - - // create our factory, which is the manager for the object creation. - // between our web app and the db. - factory := NewFactory(DefaultGenerator, db) - - // serve the "./templates" directory's "*.html" files with the HTML std view engine. - tmpl := iris.HTML("./templates", ".html").Reload(true) - // register any template func(s) here. - // - // Look ./templates/index.html#L16 - tmpl.AddFunc("IsPositive", func(n int) bool { - if n > 0 { - return true - } - return false - }) - - app.RegisterView(tmpl) - - // Serve static files (css) - app.HandleDir("/static", iris.Dir("./resources")) - - indexHandler := func(ctx iris.Context) { - ctx.ViewData("URL_COUNT", db.Len()) - ctx.View("index.html") - } - app.Get("/", indexHandler) - - // find and execute a short url by its key - // used on http://localhost:8080/u/dsaoj41u321dsa - execShortURL := func(ctx iris.Context, key string) { - if key == "" { - ctx.StatusCode(iris.StatusBadRequest) - return - } - - value := db.Get(key) - if value == "" { - ctx.StatusCode(iris.StatusNotFound) - ctx.Writef("Short URL for key: '%s' not found", key) - return - } - - ctx.Redirect(value, iris.StatusTemporaryRedirect) - } - app.Get("/u/{shortkey}", func(ctx iris.Context) { - execShortURL(ctx, ctx.Params().Get("shortkey")) - }) - - app.Post("/shorten", func(ctx iris.Context) { - formValue := ctx.FormValue("url") - if formValue == "" { - ctx.ViewData("FORM_RESULT", "You need to a enter a URL") - ctx.StatusCode(iris.StatusLengthRequired) - } else { - key, err := factory.Gen(formValue) - if err != nil { - ctx.ViewData("FORM_RESULT", "Invalid URL") - ctx.StatusCode(iris.StatusBadRequest) - } else { - if err = db.Set(key, formValue); err != nil { - ctx.ViewData("FORM_RESULT", "Internal error while saving the URL") - app.Logger().Infof("while saving URL: " + err.Error()) - ctx.StatusCode(iris.StatusInternalServerError) - } else { - ctx.StatusCode(iris.StatusOK) - shortenURL := "http://" + app.ConfigurationReadOnly().GetVHost() + "/u/" + key - ctx.ViewData("FORM_RESULT", - template.HTML("
"+shortenURL+" 
")) - } - } - } - - indexHandler(ctx) // no redirect, we need the FORM_RESULT. - }) - - app.Post("/clear_cache", func(ctx iris.Context) { - db.Clear() - ctx.Redirect("/") - }) - - return app -} diff --git a/_examples/url-shortener/main_test.go b/_examples/url-shortener/main_test.go deleted file mode 100644 index 75270e0f..00000000 --- a/_examples/url-shortener/main_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package main - -import ( - "io/ioutil" - "os" - "testing" - "time" - - "github.com/kataras/iris/v12/httptest" -) - -// TestURLShortener tests the simple tasks of our url shortener application. -// Note that it's a pure test. -// The rest possible checks is up to you, take it as as an exercise! -func TestURLShortener(t *testing.T) { - // temp db file - f, err := ioutil.TempFile("", "shortener") - if err != nil { - t.Fatalf("creating temp file for database failed: %v", err) - } - - db := NewDB(f.Name()) - app := newApp(db) - - e := httptest.New(t, app) - originalURL := "https://google.com" - - // save - e.POST("/shorten"). - WithFormField("url", originalURL).Expect(). - Status(httptest.StatusOK).Body().Contains("

-
-
-    
-    Golang URL Shortener
-    
-
-
-
-    

Golang URL Shortener

-

{{ .FORM_RESULT}}

-
- - -
- {{ if IsPositive .URL_COUNT }} -

{{ .URL_COUNT }} URLs shortened

- {{ end }} - -
- -
- - - \ No newline at end of file diff --git a/_examples/view/context-view-data/main.go b/_examples/view/context-view-data/main.go deleted file mode 100644 index 01e3ed88..00000000 --- a/_examples/view/context-view-data/main.go +++ /dev/null @@ -1,55 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12" -) - -const ( - DefaultTitle = "My Awesome Site" - DefaultLayout = "layouts/layout.html" -) - -func main() { - app := iris.New() - // output startup banner and error logs on os.Stdout - - // set the view engine target to ./templates folder - app.RegisterView(iris.HTML("./templates", ".html").Reload(true)) - - app.Use(func(ctx iris.Context) { - // set the title, current time and a layout in order to be used if and when the next handler(s) calls the .Render function - ctx.ViewData("Title", DefaultTitle) - now := time.Now().Format(ctx.Application().ConfigurationReadOnly().GetTimeFormat()) - ctx.ViewData("CurrentTime", now) - ctx.ViewLayout(DefaultLayout) - - ctx.Next() - }) - - app.Get("/", func(ctx iris.Context) { - ctx.ViewData("BodyMessage", "a sample text here... set by the route handler") - if err := ctx.View("index.html"); err != nil { - ctx.Application().Logger().Infof(err.Error()) - } - }) - - app.Get("/about", func(ctx iris.Context) { - ctx.ViewData("Title", "My About Page") - ctx.ViewData("BodyMessage", "about text here... set by the route handler") - - // same file, just to keep things simple. - if err := ctx.View("index.html"); err != nil { - ctx.Application().Logger().Infof(err.Error()) - } - }) - - // http://localhost:8080 - // http://localhost:8080/about - app.Listen(":8080") -} - -// Notes: ViewData("", myCustomStruct{}) will set this myCustomStruct value as a root binding data, -// so any View("other", "otherValue") will probably fail. -// To clear the binding data: ctx.Set(ctx.Application().ConfigurationReadOnly().GetViewDataContextKey(), nil) diff --git a/_examples/view/context-view-data/templates/index.html b/_examples/view/context-view-data/templates/index.html deleted file mode 100644 index a102b262..00000000 --- a/_examples/view/context-view-data/templates/index.html +++ /dev/null @@ -1,8 +0,0 @@ -

- Title: {{.Title}} -

-

{{.BodyMessage}}

- -
- -Current time: {{.CurrentTime}} \ No newline at end of file diff --git a/_examples/view/context-view-data/templates/layouts/layout.html b/_examples/view/context-view-data/templates/layouts/layout.html deleted file mode 100644 index a4833774..00000000 --- a/_examples/view/context-view-data/templates/layouts/layout.html +++ /dev/null @@ -1,10 +0,0 @@ - - -My WebsiteLayout - - - - - {{ yield }} - - diff --git a/_examples/view/context-view-engine/main.go b/_examples/view/context-view-engine/main.go deleted file mode 100644 index ddc6d90f..00000000 --- a/_examples/view/context-view-engine/main.go +++ /dev/null @@ -1,65 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - // Register a root view engine, as usual, - // will be used to render files through Context.View method - // when no Party or Handler-specific view engine is available. - app.RegisterView(iris.Blocks("./views/public", ".html")) - - // http://localhost:8080 - app.Get("/", index) - - // Register a view engine per group of routes. - adminGroup := app.Party("/admin") - adminGroup.RegisterView(iris.Blocks("./views/admin", ".html")) - - // http://localhost:8080/admin - adminGroup.Get("/", admin) - - // Register a view engine on-fly for the current chain of handlers. - views := iris.Blocks("./views/on-fly", ".html") - if err := views.Load(); err != nil { - app.Logger().Fatal(err) - } - - // http://localhost:8080/on-fly - app.Get("/on-fly", setViews(views), onFly) - - app.Listen(":8080") -} - -func index(ctx iris.Context) { - data := iris.Map{ - "Title": "Public Index Title", - } - - ctx.ViewLayout("main") - ctx.View("index", data) -} - -func admin(ctx iris.Context) { - data := iris.Map{ - "Title": "Admin Panel", - } - - ctx.ViewLayout("main") - ctx.View("index", data) -} - -func setViews(views iris.ViewEngine) iris.Handler { - return func(ctx iris.Context) { - ctx.ViewEngine(views) - ctx.Next() - } -} - -func onFly(ctx iris.Context) { - data := iris.Map{ - "Message": "View engine changed through 'setViews' custom middleware.", - } - - ctx.View("index", data) -} diff --git a/_examples/view/context-view-engine/views/admin/index.html b/_examples/view/context-view-engine/views/admin/index.html deleted file mode 100644 index f537f535..00000000 --- a/_examples/view/context-view-engine/views/admin/index.html +++ /dev/null @@ -1,3 +0,0 @@ -{{ define "content" }} -

Hello, Admin!

-{{ end }} \ No newline at end of file diff --git a/_examples/view/context-view-engine/views/admin/layouts/main.html b/_examples/view/context-view-engine/views/admin/layouts/main.html deleted file mode 100644 index d83d5062..00000000 --- a/_examples/view/context-view-engine/views/admin/layouts/main.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - {{ .Title }} - - - {{ template "content" .}} - - -

Copyright © 2020 Admin

- - \ No newline at end of file diff --git a/_examples/view/context-view-engine/views/on-fly/index.html b/_examples/view/context-view-engine/views/on-fly/index.html deleted file mode 100644 index 4b3fd536..00000000 --- a/_examples/view/context-view-engine/views/on-fly/index.html +++ /dev/null @@ -1,2 +0,0 @@ -

On-fly

-

{{.Message}}

\ No newline at end of file diff --git a/_examples/view/context-view-engine/views/public/500.html b/_examples/view/context-view-engine/views/public/500.html deleted file mode 100644 index 37c58b58..00000000 --- a/_examples/view/context-view-engine/views/public/500.html +++ /dev/null @@ -1,12 +0,0 @@ - -{{ define "content" }} -

Internal Server Error

-{{ end }} - -{{ define "message" }} -

{{.Message}}

-{{ end }} \ No newline at end of file diff --git a/_examples/view/context-view-engine/views/public/index.html b/_examples/view/context-view-engine/views/public/index.html deleted file mode 100644 index b11758cf..00000000 --- a/_examples/view/context-view-engine/views/public/index.html +++ /dev/null @@ -1 +0,0 @@ -

Index Body

\ No newline at end of file diff --git a/_examples/view/context-view-engine/views/public/layouts/error.html b/_examples/view/context-view-engine/views/public/layouts/error.html deleted file mode 100644 index 48598789..00000000 --- a/_examples/view/context-view-engine/views/public/layouts/error.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.Code}} - - - {{ template "content" .}} - - {{block "message" .}}{{end}} - - \ No newline at end of file diff --git a/_examples/view/context-view-engine/views/public/layouts/main.html b/_examples/view/context-view-engine/views/public/layouts/main.html deleted file mode 100644 index 5b5a509f..00000000 --- a/_examples/view/context-view-engine/views/public/layouts/main.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{ if .Title }}{{ .Title }}{{ else }}Default Main Title{{ end }} - - - {{ template "content" . }} - -
{{ partial "partials/footer" .}}
- - \ No newline at end of file diff --git a/_examples/view/context-view-engine/views/public/partials/footer.html b/_examples/view/context-view-engine/views/public/partials/footer.html deleted file mode 100644 index 61ee8461..00000000 --- a/_examples/view/context-view-engine/views/public/partials/footer.html +++ /dev/null @@ -1 +0,0 @@ -

Footer Partial

\ No newline at end of file diff --git a/_examples/view/embedding-templates-into-app/bindata.go b/_examples/view/embedding-templates-into-app/bindata.go deleted file mode 100644 index e2a2821b..00000000 --- a/_examples/view/embedding-templates-into-app/bindata.go +++ /dev/null @@ -1,319 +0,0 @@ -// Code generated for package main by go-bindata DO NOT EDIT. (@generated) -// sources: -// templates/layouts/layout.html -// templates/layouts/mylayout.html -// templates/page1.html -// templates/partials/page1_partial1.html -package main - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(data []byte, name string) ([]byte, error) { - gz, err := gzip.NewReader(bytes.NewBuffer(data)) - if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) - } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -// Name return file name -func (fi bindataFileInfo) Name() string { - return fi.name -} - -// Size return file size -func (fi bindataFileInfo) Size() int64 { - return fi.size -} - -// Mode return file mode -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} - -// Mode return file modify time -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} - -// IsDir return file whether a directory -func (fi bindataFileInfo) IsDir() bool { - return fi.mode&os.ModeDir != 0 -} - -// Sys return file is sys mode -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -var _templatesLayoutsLayoutHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x34\xce\xc1\xa9\xc3\x30\x0c\x06\xe0\xf3\x33\x78\x07\xbd\x01\x8c\xc9\x5d\x78\x82\x9e\x4a\x17\x70\x6a\x51\x19\x94\xa4\x38\xca\xc1\x84\xec\x5e\xec\xba\x27\x49\xf0\x89\xff\x47\xd6\x45\x82\x35\xc8\x14\x53\x9b\x9a\x55\x28\xdc\x62\xdd\x0e\x45\xff\xbd\xac\xb1\x06\xfd\x4f\xcc\x5b\xaa\xc1\x9a\x3f\xe4\x29\x3c\x38\xef\x90\x77\x50\x26\x78\xc9\x36\x47\x01\x19\xaf\x3c\x75\x34\x17\xf0\x7d\xf9\x77\x0e\xee\xb4\x26\x2a\x5d\x3f\x8f\x52\x68\x55\x50\x5a\xde\x12\x95\x80\xa9\x10\x38\xd7\xec\x79\x42\xcd\x24\x09\xae\xab\x05\x8f\x40\xf4\xa3\xeb\x27\x00\x00\xff\xff\x68\xca\x16\xc2\xb4\x00\x00\x00") - -func templatesLayoutsLayoutHtmlBytes() ([]byte, error) { - return bindataRead( - _templatesLayoutsLayoutHtml, - "templates/layouts/layout.html", - ) -} - -func templatesLayoutsLayoutHtml() (*asset, error) { - bytes, err := templatesLayoutsLayoutHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "templates/layouts/layout.html", size: 180, mode: os.FileMode(438), modTime: time.Unix(1565946441, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _templatesLayoutsMylayoutHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x34\x8f\x4d\x6a\xc5\x30\x0c\x84\xd7\x35\xf8\x0e\xd3\x03\x18\x93\xbd\xf1\x09\xba\x2a\xbd\x80\x53\xab\xc8\xe0\x9f\xe2\x28\x0b\x13\x72\xf7\x47\x9c\xbc\x95\x46\x62\x46\x7c\xe3\x58\x4a\xf6\x5a\x39\xa6\x10\xaf\x29\x49\x32\xf9\x32\xf0\x15\x46\xdb\xc5\xd9\xfb\xa0\x95\x56\xce\xbe\x4d\x6b\x8b\xc3\x6b\xf5\xe1\x78\xf1\x3f\x9c\x36\xa4\x0d\xc2\x84\x3c\x33\xf8\x6b\x7d\xae\xb6\x0c\x8b\x50\xe3\x14\x4d\x98\x3a\x7a\xdb\x85\x36\xb4\x9a\x87\xb3\xbc\xcc\x27\x6b\x87\x9d\xe2\xd3\x18\x7c\x53\x8d\x74\xc7\x7f\xf7\xde\xa9\x0a\x84\xca\x7f\x0e\x42\x60\xea\x04\x63\x2e\xef\x71\x60\x24\xca\x11\xe7\x79\x81\x3d\x40\xce\x3e\x75\x5e\x01\x00\x00\xff\xff\x64\xea\xc5\x1d\xd7\x00\x00\x00") - -func templatesLayoutsMylayoutHtmlBytes() ([]byte, error) { - return bindataRead( - _templatesLayoutsMylayoutHtml, - "templates/layouts/mylayout.html", - ) -} - -func templatesLayoutsMylayoutHtml() (*asset, error) { - bytes, err := templatesLayoutsMylayoutHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "templates/layouts/mylayout.html", size: 215, mode: os.FileMode(438), modTime: time.Unix(1565946441, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _templatesPage1Html = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x3c\xca\x41\xaa\xc2\x30\x10\x00\xd0\xf5\x2f\xf4\x0e\xc3\xec\xbf\x25\x5b\x8d\x3d\x83\x37\x90\x69\x33\xa4\xa1\x63\x53\x26\x69\x40\x42\xee\x2e\xa2\xb8\x7c\xf0\xac\x0b\x05\x52\x7e\x0a\x5f\x71\xa2\x79\xf5\x1a\x8f\xcd\xfd\xcf\x51\xa2\x9e\x61\x12\x9a\xd7\x0b\xfc\x74\x30\x8e\x7d\xd7\x77\x7f\x76\x31\xe3\x8d\x3c\x83\x81\x5a\xc1\x2b\x73\x06\x0c\x1a\x12\x38\x2e\x2c\x71\x67\xc5\xd6\xec\xb0\x98\xcf\xaf\x15\x94\x37\xc7\x0a\xb8\x93\xe6\x40\x92\x86\x9d\x3c\x9b\xfb\x97\xe6\xb4\xe4\x87\x60\x6b\xef\x6e\x07\x17\xca\xd8\x77\xaf\x00\x00\x00\xff\xff\x47\x41\x4a\x5c\x9d\x00\x00\x00") - -func templatesPage1HtmlBytes() ([]byte, error) { - return bindataRead( - _templatesPage1Html, - "templates/page1.html", - ) -} - -func templatesPage1Html() (*asset, error) { - bytes, err := templatesPage1HtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "templates/page1.html", size: 157, mode: os.FileMode(438), modTime: time.Unix(1565946441, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _templatesPartialsPage1_partial1Html = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb2\x49\xc9\x2c\x53\x28\x2e\xa9\xcc\x49\xb5\x55\x4a\x4a\x4c\xce\x4e\x2f\xca\x2f\xcd\x4b\xd1\x4d\xce\xcf\xc9\x2f\xb2\x52\x28\xcf\xc8\x2c\x49\xb5\x56\x80\xf2\x8a\x52\x53\x94\xec\x78\xb9\x38\x6d\x32\x0c\xed\x02\x12\xd3\x53\x15\x0c\xd5\x8b\x15\x02\x12\x8b\x4a\x32\x13\x73\x14\x0c\x6d\xf4\x33\x0c\xed\x78\xb9\x6c\xf4\x53\x32\xcb\xec\x78\xb9\x00\x01\x00\x00\xff\xff\xa2\xa6\x60\xb6\x59\x00\x00\x00") - -func templatesPartialsPage1_partial1HtmlBytes() ([]byte, error) { - return bindataRead( - _templatesPartialsPage1_partial1Html, - "templates/partials/page1_partial1.html", - ) -} - -func templatesPartialsPage1_partial1Html() (*asset, error) { - bytes, err := templatesPartialsPage1_partial1HtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "templates/partials/page1_partial1.html", size: 89, mode: os.FileMode(438), modTime: time.Unix(1565946441, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "templates/layouts/layout.html": templatesLayoutsLayoutHtml, - "templates/layouts/mylayout.html": templatesLayoutsMylayoutHtml, - "templates/page1.html": templatesPage1Html, - "templates/partials/page1_partial1.html": templatesPartialsPage1_partial1Html, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "templates": {nil, map[string]*bintree{ - "layouts": {nil, map[string]*bintree{ - "layout.html": {templatesLayoutsLayoutHtml, map[string]*bintree{}}, - "mylayout.html": {templatesLayoutsMylayoutHtml, map[string]*bintree{}}, - }}, - "page1.html": {templatesPage1Html, map[string]*bintree{}}, - "partials": {nil, map[string]*bintree{ - "page1_partial1.html": {templatesPartialsPage1_partial1Html, map[string]*bintree{}}, - }}, - }}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} diff --git a/_examples/view/embedding-templates-into-app/main.go b/_examples/view/embedding-templates-into-app/main.go deleted file mode 100644 index da087a86..00000000 --- a/_examples/view/embedding-templates-into-app/main.go +++ /dev/null @@ -1,61 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - tmpl := iris.HTML("./templates", ".html") - tmpl.Layout("layouts/layout.html") - tmpl.AddFunc("greet", func(s string) string { - return "Greetings " + s + "!" - }) - - // $ go get -u github.com/go-bindata/go-bindata/v3/go-bindata - // $ go-bindata ./templates/... - // $ go run . - // html files are not used, you can delete the folder and run the example. - tmpl.Binary(Asset, AssetNames) // <-- IMPORTANT - - app.RegisterView(tmpl) - - app.Get("/", func(ctx iris.Context) { - if err := ctx.View("page1.html"); err != nil { - ctx.StatusCode(iris.StatusInternalServerError) - ctx.Writef(err.Error()) - } - }) - - // remove the layout for a specific route - app.Get("/nolayout", func(ctx iris.Context) { - ctx.ViewLayout(iris.NoLayout) - if err := ctx.View("page1.html"); err != nil { - ctx.StatusCode(iris.StatusInternalServerError) - ctx.Writef(err.Error()) - } - }) - - // set a layout for a party, .Layout should be BEFORE any Get or other Handle party's method - my := app.Party("/my").Layout("layouts/mylayout.html") - { // both of these will use the layouts/mylayout.html as their layout. - my.Get("/", func(ctx iris.Context) { - ctx.View("page1.html") - }) - my.Get("/other", func(ctx iris.Context) { - ctx.View("page1.html") - }) - } - - // http://localhost:8080 - // http://localhost:8080/nolayout - // http://localhost:8080/my - // http://localhost:8080/my/other - app.Listen(":8080") -} - -// Note for new Gophers: -// `go build` is used instead of `go run main.go` as the example comments says -// otherwise you will get compile errors, this is a Go thing; -// because you have multiple files in the `package main`. diff --git a/_examples/view/embedding-templates-into-app/templates/layouts/layout.html b/_examples/view/embedding-templates-into-app/templates/layouts/layout.html deleted file mode 100644 index eb543f0e..00000000 --- a/_examples/view/embedding-templates-into-app/templates/layouts/layout.html +++ /dev/null @@ -1,12 +0,0 @@ - - -Layout - - - -

This is the global layout

-
- - {{ yield }} - - diff --git a/_examples/view/embedding-templates-into-app/templates/layouts/mylayout.html b/_examples/view/embedding-templates-into-app/templates/layouts/mylayout.html deleted file mode 100644 index d87575d3..00000000 --- a/_examples/view/embedding-templates-into-app/templates/layouts/mylayout.html +++ /dev/null @@ -1,12 +0,0 @@ - - -my Layout - - - -

This is the layout for the /my/ and /my/other routes only

-
- - {{ yield }} - - diff --git a/_examples/view/embedding-templates-into-app/templates/page1.html b/_examples/view/embedding-templates-into-app/templates/page1.html deleted file mode 100644 index 22bd16a1..00000000 --- a/_examples/view/embedding-templates-into-app/templates/page1.html +++ /dev/null @@ -1,7 +0,0 @@ -
- -

Page 1 {{ greet "iris developer"}}

- - {{ render "partials/page1_partial1.html"}} - -
diff --git a/_examples/view/embedding-templates-into-app/templates/partials/page1_partial1.html b/_examples/view/embedding-templates-into-app/templates/partials/page1_partial1.html deleted file mode 100644 index 8af006d2..00000000 --- a/_examples/view/embedding-templates-into-app/templates/partials/page1_partial1.html +++ /dev/null @@ -1,3 +0,0 @@ -
-

Page 1's Partial 1

-
diff --git a/_examples/view/herotemplate/README.md b/_examples/view/herotemplate/README.md deleted file mode 100644 index ff71e067..00000000 --- a/_examples/view/herotemplate/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Hero Template Example - -This folder contains the iris version of the original hero's example: https://github.com/shiyanhui/hero/tree/master/examples/app. - -Iris is 100% compatible with `net/http` so you don't have to change anything else -except the handler input from the original example. - -The only inline handler's changes were: - -From: - -```go -if _, err := w.Write(buffer.Bytes()); err != nil { -// and -template.UserListToWriter(userList, w) -``` -To: -```go -if _, err := ctx.Write(buffer.Bytes()); err != nil { -// and -template.UserListToWriter(userList, ctx) -``` - -So easy. - -Read more at: https://github.com/shiyanhui/hero \ No newline at end of file diff --git a/_examples/view/herotemplate/app.go b/_examples/view/herotemplate/app.go deleted file mode 100644 index 62f7a53a..00000000 --- a/_examples/view/herotemplate/app.go +++ /dev/null @@ -1,52 +0,0 @@ -package main - -import ( - "bytes" - - "github.com/kataras/iris/v12/_examples/view/herotemplate/template" - - "github.com/kataras/iris/v12" -) - -// $ go get -u github.com/shiyanhui/hero/hero -// $ go run app.go -// -// Read more at https://github.com/shiyanhui/hero/hero - -func main() { - app := iris.New() - - app.Get("/users", func(ctx iris.Context) { - ctx.CompressWriter(true) - ctx.ContentType("text/html") - - userList := []string{ - "Alice", - "Bob", - "Tom", - } - - // Had better use buffer sync.Pool. - // Hero(github.com/shiyanhui/hero/hero) exports GetBuffer and PutBuffer for this. - // - // buffer := hero.GetBuffer() - // defer hero.PutBuffer(buffer) - // buffer := new(bytes.Buffer) - // template.UserList(userList, buffer) - // ctx.Write(buffer.Bytes()) - - // iris context implements the io.Writer: - // _, err := template.UserListToWriter(userList, ctx) - // OR: - buffer := new(bytes.Buffer) - template.UserList(userList, buffer) - - _, err := ctx.Write(buffer.Bytes()) - if err != nil { - ctx.StopWithError(iris.StatusInternalServerError, err) - return - } - }) - - app.Listen(":8080") -} diff --git a/_examples/view/herotemplate/template/index.html b/_examples/view/herotemplate/template/index.html deleted file mode 100644 index c39ba0e7..00000000 --- a/_examples/view/herotemplate/template/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - <%@ body { %> - <% } %> - - diff --git a/_examples/view/herotemplate/template/index.html.go b/_examples/view/herotemplate/template/index.html.go deleted file mode 100644 index da8b5842..00000000 --- a/_examples/view/herotemplate/template/index.html.go +++ /dev/null @@ -1,3 +0,0 @@ -// Code generated by hero. -// DO NOT EDIT! -package template diff --git a/_examples/view/herotemplate/template/user.html b/_examples/view/herotemplate/template/user.html deleted file mode 100644 index 812fd4c5..00000000 --- a/_examples/view/herotemplate/template/user.html +++ /dev/null @@ -1,3 +0,0 @@ -
  • - <%= user %> -
  • diff --git a/_examples/view/herotemplate/template/user.html.go b/_examples/view/herotemplate/template/user.html.go deleted file mode 100644 index da8b5842..00000000 --- a/_examples/view/herotemplate/template/user.html.go +++ /dev/null @@ -1,3 +0,0 @@ -// Code generated by hero. -// DO NOT EDIT! -package template diff --git a/_examples/view/herotemplate/template/userlist.html b/_examples/view/herotemplate/template/userlist.html deleted file mode 100644 index afb27d71..00000000 --- a/_examples/view/herotemplate/template/userlist.html +++ /dev/null @@ -1,11 +0,0 @@ -<%: func UserList(userList []string, buffer *bytes.Buffer) %> - -<%~ "index.html" %> - -<%@ body { %> - <% for _, user := range userList { %> -
      - <%+ "user.html" %> -
    - <% } %> -<% } %> diff --git a/_examples/view/herotemplate/template/userlist.html.go b/_examples/view/herotemplate/template/userlist.html.go deleted file mode 100644 index d8d62324..00000000 --- a/_examples/view/herotemplate/template/userlist.html.go +++ /dev/null @@ -1,40 +0,0 @@ -// Code generated by hero. -// DO NOT EDIT! -package template - -import ( - "bytes" - - "github.com/shiyanhui/hero" -) - -func UserList(userList []string, buffer *bytes.Buffer) { - buffer.WriteString(` - - - - - - - `) - for _, user := range userList { - buffer.WriteString(` -
      - `) - buffer.WriteString(`
    • - `) - hero.EscapeHTML(user, buffer) - buffer.WriteString(` -
    • -`) - - buffer.WriteString(` -
    - `) - } - - buffer.WriteString(` - - -`) -} diff --git a/_examples/view/herotemplate/template/userlistwriter.html b/_examples/view/herotemplate/template/userlistwriter.html deleted file mode 100644 index 59e68609..00000000 --- a/_examples/view/herotemplate/template/userlistwriter.html +++ /dev/null @@ -1,11 +0,0 @@ -<%: func UserListToWriter(userList []string, w io.Writer) (int, error)%> - -<%~ "index.html" %> - -<%@ body { %> - <% for _, user := range userList { %> -
      - <%+ "user.html" %> -
    - <% } %> -<% } %> diff --git a/_examples/view/herotemplate/template/userlistwriter.html.go b/_examples/view/herotemplate/template/userlistwriter.html.go deleted file mode 100644 index f6df2ed5..00000000 --- a/_examples/view/herotemplate/template/userlistwriter.html.go +++ /dev/null @@ -1,43 +0,0 @@ -// Code generated by hero. -// DO NOT EDIT! -package template - -import ( - "io" - - "github.com/shiyanhui/hero" -) - -func UserListToWriter(userList []string, w io.Writer) (int, error) { - _buffer := hero.GetBuffer() - defer hero.PutBuffer(_buffer) - _buffer.WriteString(` - - - - - - - `) - for _, user := range userList { - _buffer.WriteString(` -
      - `) - _buffer.WriteString(`
    • - `) - hero.EscapeHTML(user, _buffer) - _buffer.WriteString(` -
    • -`) - - _buffer.WriteString(` -
    - `) - } - - _buffer.WriteString(` - - -`) - return w.Write(_buffer.Bytes()) -} diff --git a/_examples/view/overview/main.go b/_examples/view/overview/main.go deleted file mode 100644 index 8aeaabf1..00000000 --- a/_examples/view/overview/main.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - - // with default template funcs: - // - // - {{ urlpath "mynamedroute" "pathParameter_ifneeded" }} - // - {{ render "header.html" }} - // - {{ render_r "header.html" }} // partial relative path to current page - // - {{ yield }} - // - {{ current }} - app.RegisterView(iris.HTML("./templates", ".html")) - app.Get("/", func(ctx iris.Context) { - ctx.CompressWriter(true) // enable compression based on Accept-Encoding (e.g. "gzip"). - ctx.ViewData("Name", "iris") // the .Name inside the ./templates/hi.html. - ctx.View("hi.html") // render the template with the file name relative to the './templates'. - }) - - // http://localhost:8080/ - app.Listen(":8080") -} - -/* -Note: - -In case you're wondering, the code behind the view engines derives from the "github.com/kataras/iris/v12/view" package, -access to the engines' variables can be granded by "github.com/kataras/iris/v12" package too. - - iris.HTML(...) is a shortcut of view.HTML(...) - iris.Django(...) >> >> view.Django(...) - iris.Pug(...) >> >> view.Pug(...) - iris.Handlebars(...) >> >> view.Handlebars(...) - iris.Amber(...) >> >> view.Amber(...) -*/ diff --git a/_examples/view/overview/templates/hi.html b/_examples/view/overview/templates/hi.html deleted file mode 100644 index aab59aa2..00000000 --- a/_examples/view/overview/templates/hi.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - Hi iris - - - -

    Hi {{.Name}}

    - - - \ No newline at end of file diff --git a/_examples/view/quicktemplate/README.md b/_examples/view/quicktemplate/README.md deleted file mode 100644 index 3d3a6f9b..00000000 --- a/_examples/view/quicktemplate/README.md +++ /dev/null @@ -1,19 +0,0 @@ -First of all, install [quicktemplate](https://github.com/valyala/quicktemplate) package and [quicktemplate compiler](https://github.com/valyala/quicktemplate/tree/master/qtc) - -```sh -go get -u github.com/valyala/quicktemplate -go get -u github.com/valyala/quicktemplate/qtc -``` - -The example has the Go code compiled already for you, therefore: -```sh -go run main.go # http://localhost:8080 -``` - -However there is an instruction below, full documentation can be found at https://github.com/valyala/quicktemplate. - -Save your template files into `templates` folder under the extension *.qtpl, open your terminal and run `qtc` inside this folder. - -If all went ok, `*.qtpl.go` files must appear in the `templates` folder. These files contain the Go code for all `*.qtpl` files. - -> Remember, each time you change a a `/templates/*.qtpl` file you have to run the `qtc` command and re-build your application. \ No newline at end of file diff --git a/_examples/view/quicktemplate/controllers/execute_template.go b/_examples/view/quicktemplate/controllers/execute_template.go deleted file mode 100644 index 6baf71a4..00000000 --- a/_examples/view/quicktemplate/controllers/execute_template.go +++ /dev/null @@ -1,14 +0,0 @@ -package controllers - -import ( - "github.com/kataras/iris/v12/_examples/view/quicktemplate/templates" - - "github.com/kataras/iris/v12" -) - -// ExecuteTemplate renders a "tmpl" partial template to the `Context.ResponseWriter`. -func ExecuteTemplate(ctx iris.Context, tmpl templates.Partial) { - ctx.CompressWriter(true) - ctx.ContentType("text/html") - templates.WriteTemplate(ctx, tmpl) -} diff --git a/_examples/view/quicktemplate/controllers/hello.go b/_examples/view/quicktemplate/controllers/hello.go deleted file mode 100644 index 009742a4..00000000 --- a/_examples/view/quicktemplate/controllers/hello.go +++ /dev/null @@ -1,30 +0,0 @@ -package controllers - -import ( - "github.com/kataras/iris/v12/_examples/view/quicktemplate/templates" - - "github.com/kataras/iris/v12" -) - -// Hello renders our ../templates/hello.qtpl file using the compiled ../templates/hello.qtpl.go file. -func Hello(ctx iris.Context) { - // vars := make(map[string]interface{}) - // vars["message"] = "Hello World!" - // vars["name"] = ctx.Params().Get("name") - // [...] - // &templates.Hello{ Vars: vars } - // [...] - - // However, as an alternative, we recommend that you should the `ctx.ViewData(key, value)` - // in order to be able modify the `templates.Hello#Vars` from a middleware(other handlers) as well. - ctx.ViewData("message", "Hello World!") - ctx.ViewData("name", ctx.Params().Get("name")) - - // set view data to the `Vars` template's field - tmpl := &templates.Hello{ - Vars: ctx.GetViewData(), - } - - // render the template - ExecuteTemplate(ctx, tmpl) -} diff --git a/_examples/view/quicktemplate/controllers/index.go b/_examples/view/quicktemplate/controllers/index.go deleted file mode 100644 index 56cf6717..00000000 --- a/_examples/view/quicktemplate/controllers/index.go +++ /dev/null @@ -1,15 +0,0 @@ -package controllers - -import ( - "github.com/kataras/iris/v12/_examples/view/quicktemplate/templates" - - "github.com/kataras/iris/v12" -) - -// Index renders our ../templates/index.qtpl file using the compiled ../templates/index.qtpl.go file. -func Index(ctx iris.Context) { - tmpl := &templates.Index{} - - // render the template - ExecuteTemplate(ctx, tmpl) -} diff --git a/_examples/view/quicktemplate/main.go b/_examples/view/quicktemplate/main.go deleted file mode 100644 index 7a63ab0d..00000000 --- a/_examples/view/quicktemplate/main.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12/_examples/view/quicktemplate/controllers" - - "github.com/kataras/iris/v12" -) - -func newApp() *iris.Application { - app := iris.New() - app.Get("/", controllers.Index) - app.Get("/{name}", controllers.Hello) - - return app -} - -func main() { - app := newApp() - // http://localhost:8080 - // http://localhost:8080/yourname - app.Listen(":8080") -} diff --git a/_examples/view/quicktemplate/main_test.go b/_examples/view/quicktemplate/main_test.go deleted file mode 100644 index 5fcf9411..00000000 --- a/_examples/view/quicktemplate/main_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package main - -import ( - "fmt" - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestResponseWriterQuicktemplate(t *testing.T) { - baseRawBody := ` - - - Quicktemplate integration with Iris - - -
    - Header contents here... -
    - -
    - -

    %s

    -
    - %s -
    - -
    - - -
    - Footer contents here... -
    - -` - - expectedIndexRawBody := fmt.Sprintf(baseRawBody, "Index Page", "This is our index page's body.") - name := "yourname" - expectedHelloRawBody := fmt.Sprintf(baseRawBody, "Hello World!", "Hello "+name+"!") - - app := newApp() - - e := httptest.New(t, app) - - e.GET("/").Expect().Status(httptest.StatusOK).Body().Equal(expectedIndexRawBody) - e.GET("/" + name).Expect().Status(httptest.StatusOK).Body().Equal(expectedHelloRawBody) -} diff --git a/_examples/view/quicktemplate/models/.gitkeep b/_examples/view/quicktemplate/models/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/_examples/view/quicktemplate/templates/base.qtpl b/_examples/view/quicktemplate/templates/base.qtpl deleted file mode 100644 index 4e3fd923..00000000 --- a/_examples/view/quicktemplate/templates/base.qtpl +++ /dev/null @@ -1,36 +0,0 @@ -This is our templates' base implementation. - -{% interface -Partial { - Body() -} -%} - - -Template writes a template implementing the Partial interface. -{% func Template(p Partial) %} - - - Quicktemplate integration with Iris - - -
    - Header contents here... -
    - -
    - {%= p.Body() %} -
    - - -
    - Footer contents here... -
    - -{% endfunc %} - - -Base template implementation. Other pages may inherit from it if they need -overriding only certain Partial methods. -{% code type Base struct {} %} -{% func (b *Base) Body() %}This is the base body{% endfunc %} diff --git a/_examples/view/quicktemplate/templates/base.qtpl.go b/_examples/view/quicktemplate/templates/base.qtpl.go deleted file mode 100644 index d1e988f1..00000000 --- a/_examples/view/quicktemplate/templates/base.qtpl.go +++ /dev/null @@ -1,147 +0,0 @@ -// This file is automatically generated by qtc from "base.qtpl". -// See https://github.com/valyala/quicktemplate for details. - -// This is our templates' base implementation. -// - -//line base.qtpl:3 - -package templates - -//line base.qtpl:3 - -import ( - qtio422016 "io" - - qt422016 "github.com/valyala/quicktemplate" -) - -//line base.qtpl:3 - -var ( - _ = qtio422016.Copy - _ = qt422016.AcquireByteBuffer -) - -//line base.qtpl:4 - -type Partial interface { - //line base.qtpl:4 - Body() string - //line base.qtpl:4 - StreamBody(qw422016 *qt422016.Writer) - //line base.qtpl:4 - WriteBody(qq422016 qtio422016.Writer) -//line base.qtpl:4 - -} - -// Template writes a template implementing the Partial interface. - -//line base.qtpl:11 - -func StreamTemplate(qw422016 *qt422016.Writer, p Partial) { - //line base.qtpl:11 - qw422016.N().S(` - - - Quicktemplate integration with Iris - - -
    - Header contents here... -
    - -
    - `) - //line base.qtpl:22 - p.StreamBody(qw422016) - //line base.qtpl:22 - qw422016.N().S(` -
    - - -
    - Footer contents here... -
    - -`) -//line base.qtpl:30 - -} - -//line base.qtpl:30 - -func WriteTemplate(qq422016 qtio422016.Writer, p Partial) { - //line base.qtpl:30 - qw422016 := qt422016.AcquireWriter(qq422016) - //line base.qtpl:30 - StreamTemplate(qw422016, p) - //line base.qtpl:30 - qt422016.ReleaseWriter(qw422016) -//line base.qtpl:30 - -} - -//line base.qtpl:30 - -func Template(p Partial) string { - //line base.qtpl:30 - qb422016 := qt422016.AcquireByteBuffer() - //line base.qtpl:30 - WriteTemplate(qb422016, p) - //line base.qtpl:30 - qs422016 := string(qb422016.B) - //line base.qtpl:30 - qt422016.ReleaseByteBuffer(qb422016) - //line base.qtpl:30 - return qs422016 -//line base.qtpl:30 - -} - -// Base template implementation. Other pages may inherit from it if they need -// overriding only certain Partial methods. - -//line base.qtpl:35 - -type Base struct{} - -//line base.qtpl:36 - -func (b *Base) StreamBody(qw422016 *qt422016.Writer) { -//line base.qtpl:36 - - qw422016.N().S(`This is the base body`) -} - -//line base.qtpl:36 -//line base.qtpl:36 - -func (b *Base) WriteBody(qq422016 qtio422016.Writer) { - //line base.qtpl:36 - qw422016 := qt422016.AcquireWriter(qq422016) - //line base.qtpl:36 - b.StreamBody(qw422016) - //line base.qtpl:36 - qt422016.ReleaseWriter(qw422016) -//line base.qtpl:36 - -} - -//line base.qtpl:36 - -func (b *Base) Body() string { - //line base.qtpl:36 - qb422016 := qt422016.AcquireByteBuffer() - //line base.qtpl:36 - b.WriteBody(qb422016) - //line base.qtpl:36 - qs422016 := string(qb422016.B) - //line base.qtpl:36 - qt422016.ReleaseByteBuffer(qb422016) - //line base.qtpl:36 - return qs422016 -//line base.qtpl:36 - -} diff --git a/_examples/view/quicktemplate/templates/hello.qtpl b/_examples/view/quicktemplate/templates/hello.qtpl deleted file mode 100644 index 9752cc8d..00000000 --- a/_examples/view/quicktemplate/templates/hello.qtpl +++ /dev/null @@ -1,14 +0,0 @@ -Hello template, implements the Partial's methods. - -{% code -type Hello struct { - Vars map[string]interface{} -} -%} - -{% func (h *Hello) Body() %} -

    {%v h.Vars["message"] %}

    -
    - Hello {%v h.Vars["name"] %}! -
    -{% endfunc %} diff --git a/_examples/view/quicktemplate/templates/hello.qtpl.go b/_examples/view/quicktemplate/templates/hello.qtpl.go deleted file mode 100644 index 61db387a..00000000 --- a/_examples/view/quicktemplate/templates/hello.qtpl.go +++ /dev/null @@ -1,82 +0,0 @@ -// This file is automatically generated by qtc from "hello.qtpl". -// See https://github.com/valyala/quicktemplate for details. - -// Hello template, implements the Partial's methods. -// - -//line hello.qtpl:3 - -package templates - -//line hello.qtpl:3 - -import ( - qtio422016 "io" - - qt422016 "github.com/valyala/quicktemplate" -) - -//line hello.qtpl:3 - -var ( - _ = qtio422016.Copy - _ = qt422016.AcquireByteBuffer -) - -//line hello.qtpl:4 - -type Hello struct { - Vars map[string]interface{} -} - -//line hello.qtpl:9 - -func (h *Hello) StreamBody(qw422016 *qt422016.Writer) { - //line hello.qtpl:9 - qw422016.N().S(` -

    `) - //line hello.qtpl:10 - qw422016.E().V(h.Vars["message"]) - //line hello.qtpl:10 - qw422016.N().S(`

    -
    - Hello `) - //line hello.qtpl:12 - qw422016.E().V(h.Vars["name"]) - //line hello.qtpl:12 - qw422016.N().S(`! -
    -`) -//line hello.qtpl:14 - -} - -//line hello.qtpl:14 - -func (h *Hello) WriteBody(qq422016 qtio422016.Writer) { - //line hello.qtpl:14 - qw422016 := qt422016.AcquireWriter(qq422016) - //line hello.qtpl:14 - h.StreamBody(qw422016) - //line hello.qtpl:14 - qt422016.ReleaseWriter(qw422016) -//line hello.qtpl:14 - -} - -//line hello.qtpl:14 - -func (h *Hello) Body() string { - //line hello.qtpl:14 - qb422016 := qt422016.AcquireByteBuffer() - //line hello.qtpl:14 - h.WriteBody(qb422016) - //line hello.qtpl:14 - qs422016 := string(qb422016.B) - //line hello.qtpl:14 - qt422016.ReleaseByteBuffer(qb422016) - //line hello.qtpl:14 - return qs422016 -//line hello.qtpl:14 - -} diff --git a/_examples/view/quicktemplate/templates/index.qtpl b/_examples/view/quicktemplate/templates/index.qtpl deleted file mode 100644 index f2551297..00000000 --- a/_examples/view/quicktemplate/templates/index.qtpl +++ /dev/null @@ -1,12 +0,0 @@ -Index template, implements the Partial's methods. - -{% code -type Index struct {} -%} - -{% func (i *Index) Body() %} -

    Index Page

    -
    - This is our index page's body. -
    -{% endfunc %} diff --git a/_examples/view/quicktemplate/templates/index.qtpl.go b/_examples/view/quicktemplate/templates/index.qtpl.go deleted file mode 100644 index 18b4824d..00000000 --- a/_examples/view/quicktemplate/templates/index.qtpl.go +++ /dev/null @@ -1,72 +0,0 @@ -// This file is automatically generated by qtc from "index.qtpl". -// See https://github.com/valyala/quicktemplate for details. - -// Index template, implements the Partial's methods. -// - -//line index.qtpl:3 - -package templates - -//line index.qtpl:3 - -import ( - qtio422016 "io" - - qt422016 "github.com/valyala/quicktemplate" -) - -//line index.qtpl:3 - -var ( - _ = qtio422016.Copy - _ = qt422016.AcquireByteBuffer -) - -//line index.qtpl:4 - -type Index struct{} - -//line index.qtpl:7 - -func (i *Index) StreamBody(qw422016 *qt422016.Writer) { - //line index.qtpl:7 - qw422016.N().S(` -

    Index Page

    -
    - This is our index page's body. -
    -`) -//line index.qtpl:12 - -} - -//line index.qtpl:12 - -func (i *Index) WriteBody(qq422016 qtio422016.Writer) { - //line index.qtpl:12 - qw422016 := qt422016.AcquireWriter(qq422016) - //line index.qtpl:12 - i.StreamBody(qw422016) - //line index.qtpl:12 - qt422016.ReleaseWriter(qw422016) -//line index.qtpl:12 - -} - -//line index.qtpl:12 - -func (i *Index) Body() string { - //line index.qtpl:12 - qb422016 := qt422016.AcquireByteBuffer() - //line index.qtpl:12 - i.WriteBody(qb422016) - //line index.qtpl:12 - qs422016 := string(qb422016.B) - //line index.qtpl:12 - qt422016.ReleaseByteBuffer(qb422016) - //line index.qtpl:12 - return qs422016 -//line index.qtpl:12 - -} diff --git a/_examples/view/template_ace_0/main.go b/_examples/view/template_ace_0/main.go deleted file mode 100644 index fcf6619b..00000000 --- a/_examples/view/template_ace_0/main.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - - // Read about its markup syntax at: https://github.com/yosssi/ace - tmpl := iris.Ace("./views", ".ace") - // tmpl.Layout("layouts/main.ace") -> global layout for all pages. - - app.RegisterView(tmpl) - - app.Get("/", func(ctx iris.Context) { - ctx.View("index.ace", iris.Map{ - "Title": "Title of The Page", - }) - }) - - app.Get("/layout", func(ctx iris.Context) { - ctx.ViewLayout("layouts/main.ace") // layout for that response. - ctx.View("index.ace", iris.Map{ - "Title": "Title of the main Page", - }) - }) - - // otherGroup := app.Party("/other").Layout("layouts/other.ace") -> layout for that party. - // otherGroup.Get("/", func(ctx iris.Context) { ctx.View("index.ace", [...]) }) - - app.Listen(":8080") -} diff --git a/_examples/view/template_ace_0/views/index.ace b/_examples/view/template_ace_0/views/index.ace deleted file mode 100644 index 776cc11f..00000000 --- a/_examples/view/template_ace_0/views/index.ace +++ /dev/null @@ -1,5 +0,0 @@ -= include partials/header.ace . - -h2 {{.Title}} - -= include partials/footer.ace . \ No newline at end of file diff --git a/_examples/view/template_ace_0/views/layouts/main.ace b/_examples/view/template_ace_0/views/layouts/main.ace deleted file mode 100644 index b3997c7c..00000000 --- a/_examples/view/template_ace_0/views/layouts/main.ace +++ /dev/null @@ -1,6 +0,0 @@ -= doctype html -html - head - title Main Page - body - {{ yield }} \ No newline at end of file diff --git a/_examples/view/template_ace_0/views/partials/footer.ace b/_examples/view/template_ace_0/views/partials/footer.ace deleted file mode 100644 index 99261685..00000000 --- a/_examples/view/template_ace_0/views/partials/footer.ace +++ /dev/null @@ -1 +0,0 @@ -h1 Partial Footer \ No newline at end of file diff --git a/_examples/view/template_ace_0/views/partials/header.ace b/_examples/view/template_ace_0/views/partials/header.ace deleted file mode 100644 index dca23ac2..00000000 --- a/_examples/view/template_ace_0/views/partials/header.ace +++ /dev/null @@ -1 +0,0 @@ -h1 Partial Header \ No newline at end of file diff --git a/_examples/view/template_blocks_0/main.go b/_examples/view/template_blocks_0/main.go deleted file mode 100644 index 8e46a506..00000000 --- a/_examples/view/template_blocks_0/main.go +++ /dev/null @@ -1,35 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - // Read about its syntax at: https://github.com/kataras/blocks - app.RegisterView(iris.Blocks("./views", ".html").Reload(true)) - - app.Get("/", index) - app.Get("/500", internalServerError) - - app.Listen(":8080") -} - -func index(ctx iris.Context) { - data := iris.Map{ - "Title": "Page Title", - } - - ctx.ViewLayout("main") - ctx.View("index", data) -} - -func internalServerError(ctx iris.Context) { - ctx.StatusCode(iris.StatusInternalServerError) - - data := iris.Map{ - "Code": iris.StatusInternalServerError, - "Message": "Internal Server Error", - } - - ctx.ViewLayout("error") - ctx.View("500", data) -} diff --git a/_examples/view/template_blocks_0/views/500.html b/_examples/view/template_blocks_0/views/500.html deleted file mode 100644 index 37c58b58..00000000 --- a/_examples/view/template_blocks_0/views/500.html +++ /dev/null @@ -1,12 +0,0 @@ - -{{ define "content" }} -

    Internal Server Error

    -{{ end }} - -{{ define "message" }} -

    {{.Message}}

    -{{ end }} \ No newline at end of file diff --git a/_examples/view/template_blocks_0/views/index.html b/_examples/view/template_blocks_0/views/index.html deleted file mode 100644 index b11758cf..00000000 --- a/_examples/view/template_blocks_0/views/index.html +++ /dev/null @@ -1 +0,0 @@ -

    Index Body

    \ No newline at end of file diff --git a/_examples/view/template_blocks_0/views/layouts/error.html b/_examples/view/template_blocks_0/views/layouts/error.html deleted file mode 100644 index 48598789..00000000 --- a/_examples/view/template_blocks_0/views/layouts/error.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.Code}} - - - {{ template "content" .}} - - {{block "message" .}}{{end}} - - \ No newline at end of file diff --git a/_examples/view/template_blocks_0/views/layouts/main.html b/_examples/view/template_blocks_0/views/layouts/main.html deleted file mode 100644 index 5b5a509f..00000000 --- a/_examples/view/template_blocks_0/views/layouts/main.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{ if .Title }}{{ .Title }}{{ else }}Default Main Title{{ end }} - - - {{ template "content" . }} - -
    {{ partial "partials/footer" .}}
    - - \ No newline at end of file diff --git a/_examples/view/template_blocks_0/views/partials/footer.html b/_examples/view/template_blocks_0/views/partials/footer.html deleted file mode 100644 index 61ee8461..00000000 --- a/_examples/view/template_blocks_0/views/partials/footer.html +++ /dev/null @@ -1 +0,0 @@ -

    Footer Partial

    \ No newline at end of file diff --git a/_examples/view/template_blocks_1_embedded/bindata.go b/_examples/view/template_blocks_1_embedded/bindata.go deleted file mode 100644 index 465eb47c..00000000 --- a/_examples/view/template_blocks_1_embedded/bindata.go +++ /dev/null @@ -1,343 +0,0 @@ -// Code generated by go-bindata. (@generated) DO NOT EDIT. - -//Package main generated by go-bindata.// sources: -// ../template_blocks_0/views/500.html -// ../template_blocks_0/views/index.html -// ../template_blocks_0/views/layouts/error.html -// ../template_blocks_0/views/layouts/main.html -// ../template_blocks_0/views/partials/footer.html -package main - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(data []byte, name string) ([]byte, error) { - gz, err := gzip.NewReader(bytes.NewBuffer(data)) - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -// Name return file name -func (fi bindataFileInfo) Name() string { - return fi.name -} - -// Size return file size -func (fi bindataFileInfo) Size() int64 { - return fi.size -} - -// Mode return file mode -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} - -// ModTime return file modify time -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} - -// IsDir return file whether a directory -func (fi bindataFileInfo) IsDir() bool { - return fi.mode&os.ModeDir != 0 -} - -// Sys return file is sys mode -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -var _views500Html = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\x8f\xb1\x4e\xf3\x30\x14\x85\xf7\x48\x79\x87\xfb\x67\xe9\x8f\xd4\xa4\xea\x5a\x42\x37\x06\x06\xa6\x22\x21\x46\xc7\x3e\xad\x2d\x9c\x7b\x23\xdb\x49\x89\xa2\xbc\x3b\x6a\x5a\x04\x2c\xac\xf7\x7e\xe7\x3b\x3a\xf5\xbf\xb2\xa4\x37\xe9\x49\x2b\x26\x83\xa3\x63\x50\x2b\x01\x94\xac\x62\x12\x06\x35\x5e\xf4\x7b\x95\x67\x2f\x16\x17\x40\xf5\x3e\x2d\x77\x17\xa9\xd0\xc2\x09\x9c\x0a\x3a\x5b\xa7\x2d\x45\x2b\xbd\x37\xd4\x5c\xd2\xa0\x56\x39\xa6\x84\xb6\xf3\x2a\x61\x15\xa9\x11\x33\x56\x79\x76\x90\x35\x61\x00\x93\x3b\x92\x4b\xab\x48\xad\x8b\xd1\xf1\x89\xfe\x47\x80\x1c\x1b\x7c\x54\x36\xb5\xfe\x6e\x7d\x7d\x2b\x63\x60\x48\xf5\x49\x5a\x95\x9c\x56\xde\x8f\xd4\x8c\x4b\xc3\xe0\x70\x26\xf0\xc9\x31\xaa\x3c\x7b\xb5\x60\x1a\xa5\x27\x06\x0c\x25\xf9\x63\xce\x7a\xe1\xac\x1a\x70\xe1\x9a\x1b\x13\x3b\x68\x77\x74\x7a\x97\x67\x65\xb9\xcf\xb3\x69\xfa\x52\x7c\x0f\x9d\xe7\x3c\xab\xed\x76\xff\xc4\x09\x81\x95\xa7\x03\xc2\x80\x40\x8f\x21\x48\xa8\x37\x76\x7b\xcd\x81\xcd\x82\xfe\x92\xb4\x88\x51\x9d\x70\x93\x74\x14\xd3\xe8\xf1\x50\x68\xf1\x12\x76\x01\xe6\xbe\xd8\x4f\x53\xf5\x7c\xa5\xe6\xb9\xde\x74\x3f\x65\x9f\x01\x00\x00\xff\xff\xb3\xfa\x91\xbd\xaa\x01\x00\x00") - -func views500HtmlBytes() ([]byte, error) { - return bindataRead( - _views500Html, - "views/500.html", - ) -} - -func views500Html() (*asset, error) { - bytes, err := views500HtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "views/500.html", size: 426, mode: os.FileMode(438), modTime: time.Unix(1596515591, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _viewsIndexHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb2\xc9\x30\xb4\xf3\xcc\x4b\x49\xad\x50\x70\xca\x4f\xa9\xb4\xd1\xcf\x30\xb4\x03\x04\x00\x00\xff\xff\xcc\x4b\x98\x69\x13\x00\x00\x00") - -func viewsIndexHtmlBytes() ([]byte, error) { - return bindataRead( - _viewsIndexHtml, - "views/index.html", - ) -} - -func viewsIndexHtml() (*asset, error) { - bytes, err := viewsIndexHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "views/index.html", size: 19, mode: os.FileMode(438), modTime: time.Unix(1596514225, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _viewsLayoutsErrorHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x90\xbf\x4e\xf3\x40\x10\xc4\x7b\x4b\x7e\x87\xfd\xb6\xfe\x6c\x43\x47\x71\xe7\x26\x40\x0b\x45\x28\x28\x37\x77\xa3\xf8\xc4\xfd\x89\xe2\x55\x22\x74\xf2\xbb\xa3\x18\x83\x44\xb5\xda\x99\x9f\x66\x57\x63\xfe\x3d\xbe\xec\xf6\xef\xaf\x4f\x34\x69\x8a\x63\xdb\x98\xdb\xa4\x28\xf9\x68\x19\x99\x57\x05\xe2\xc7\xb6\x21\x22\x32\x09\x2a\xe4\x26\x39\xcf\x50\xcb\x6f\xfb\xe7\xee\x81\xff\x78\x59\x12\x2c\x5f\x02\xae\xa7\x72\x56\x26\x57\xb2\x22\xab\xe5\x6b\xf0\x3a\x59\x8f\x4b\x70\xe8\xd6\xe5\x3f\x85\x1c\x34\x48\xec\x66\x27\x11\xf6\xbe\xbf\xfb\xcd\xd2\xa0\x11\x63\xad\xfd\xae\x78\x2c\x8b\x19\xbe\x85\xb6\x31\xc3\xf6\x8e\x39\x14\xff\xb9\xe1\xb5\x92\x22\x9d\xa2\x28\x88\xb7\x8b\x4c\xfd\xb2\xb4\xcd\x0f\x70\x88\xc5\x7d\x10\x27\xcc\xb3\x1c\xb1\x9a\xb5\x22\xfb\x1b\x63\x86\x2d\xcb\x0c\x6b\x0b\x5f\x01\x00\x00\xff\xff\xbe\xb7\x11\x67\x15\x01\x00\x00") - -func viewsLayoutsErrorHtmlBytes() ([]byte, error) { - return bindataRead( - _viewsLayoutsErrorHtml, - "views/layouts/error.html", - ) -} - -func viewsLayoutsErrorHtml() (*asset, error) { - bytes, err := viewsLayoutsErrorHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "views/layouts/error.html", size: 277, mode: os.FileMode(438), modTime: time.Unix(1596514340, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _viewsLayoutsMainHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x90\xb1\x4e\xf4\x30\x10\x84\xfb\x48\x79\x87\xf9\x5d\xff\x49\xa0\xa3\xb0\xd3\x70\xd0\x21\x28\x42\x41\xb9\x24\x1b\x62\xc9\x71\xa2\x64\xb9\x13\xb2\xfc\xee\xc8\x39\x0b\xe9\x2a\xcf\xfa\xb3\x66\xc6\xab\xff\x9d\x5e\x1f\xbb\x8f\xb7\x27\x4c\x32\xbb\xb6\x2c\x74\x3a\xe1\xc8\x7f\x19\xc5\x5e\x1d\x37\x4c\x43\x5b\x16\x00\xa0\x67\x16\x42\x3f\xd1\xb6\xb3\x18\xf5\xde\x3d\x57\x0f\xea\x86\x79\x9a\xd9\xa8\xb3\xe5\xcb\xba\x6c\xa2\xd0\x2f\x5e\xd8\x8b\x51\x17\x3b\xc8\x64\x06\x3e\xdb\x9e\xab\x63\xf8\x0f\xeb\xad\x58\x72\xd5\xde\x93\x63\x73\x5f\xdf\xfd\x79\x89\x15\xc7\x6d\x08\xb0\x23\xea\x2e\x0d\x88\x31\x84\x1b\xcd\x6e\x4f\xea\xc4\x23\x7d\x3b\xc1\x0b\x59\x8f\x03\x27\xe6\x07\xc4\xa8\x9b\xab\x4f\x59\xe8\x26\xff\x42\x7f\x2e\xc3\x4f\x4e\x09\x01\xc2\xf3\xea\x48\x18\x2a\x17\x55\xa8\x11\x63\x59\x94\x85\x1e\x97\x45\x78\x4b\x25\x56\xda\x52\x4f\xa8\x2c\xf6\xe6\xca\x14\xea\x14\x92\x1f\xa6\x94\xec\xae\x9b\x63\x9d\xbf\x01\x00\x00\xff\xff\x44\x95\x63\x98\x5e\x01\x00\x00") - -func viewsLayoutsMainHtmlBytes() ([]byte, error) { - return bindataRead( - _viewsLayoutsMainHtml, - "views/layouts/main.html", - ) -} - -func viewsLayoutsMainHtml() (*asset, error) { - bytes, err := viewsLayoutsMainHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "views/layouts/main.html", size: 350, mode: os.FileMode(438), modTime: time.Unix(1596514155, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _viewsPartialsFooterHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb2\xc9\x30\xb6\x73\xcb\xcf\x2f\x49\x2d\x52\x08\x48\x2c\x2a\xc9\x4c\xcc\xb1\xd1\xcf\x30\xb6\x03\x04\x00\x00\xff\xff\x08\xe6\xe9\xf8\x17\x00\x00\x00") - -func viewsPartialsFooterHtmlBytes() ([]byte, error) { - return bindataRead( - _viewsPartialsFooterHtml, - "views/partials/footer.html", - ) -} - -func viewsPartialsFooterHtml() (*asset, error) { - bytes, err := viewsPartialsFooterHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "views/partials/footer.html", size: 23, mode: os.FileMode(438), modTime: time.Unix(1596514093, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "views/500.html": views500Html, - "views/index.html": viewsIndexHtml, - "views/layouts/error.html": viewsLayoutsErrorHtml, - "views/layouts/main.html": viewsLayoutsMainHtml, - "views/partials/footer.html": viewsPartialsFooterHtml, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "views": {nil, map[string]*bintree{ - "500.html": {views500Html, map[string]*bintree{}}, - "index.html": {viewsIndexHtml, map[string]*bintree{}}, - "layouts": {nil, map[string]*bintree{ - "error.html": {viewsLayoutsErrorHtml, map[string]*bintree{}}, - "main.html": {viewsLayoutsMainHtml, map[string]*bintree{}}, - }}, - "partials": {nil, map[string]*bintree{ - "footer.html": {viewsPartialsFooterHtml, map[string]*bintree{}}, - }}, - }}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} diff --git a/_examples/view/template_blocks_1_embedded/main.go b/_examples/view/template_blocks_1_embedded/main.go deleted file mode 100644 index 020a2235..00000000 --- a/_examples/view/template_blocks_1_embedded/main.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -// $ go get -u github.com/go-bindata/go-bindata/v3/go-bindata -// $ go-bindata -prefix "../template_blocks_0" ../template_blocks_0/views/... -// $ go run . -// # OR go-bindata -prefix "../template_blocks_0/views" ../template_blocks_0/views/... with iris.Blocks("").Binary(...) -// System files are not used, you can optionally delete the folder and run the example now. - -func main() { - app := iris.New() - app.RegisterView(iris.Blocks("./views", ".html").Binary(Asset, AssetNames)) - - app.Get("/", index) - app.Get("/500", internalServerError) - - app.Listen(":8080") -} - -func index(ctx iris.Context) { - data := iris.Map{ - "Title": "Page Title", - } - - ctx.ViewLayout("main") - ctx.View("index", data) -} - -func internalServerError(ctx iris.Context) { - ctx.StatusCode(iris.StatusInternalServerError) - - data := iris.Map{ - "Code": iris.StatusInternalServerError, - "Message": "Internal Server Error", - } - - ctx.ViewLayout("error") - ctx.View("500", data) -} diff --git a/_examples/view/template_django_0/main.go b/_examples/view/template_django_0/main.go deleted file mode 100644 index 72dc256d..00000000 --- a/_examples/view/template_django_0/main.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12" - - // optionally, registers filters like `timesince`. - _ "github.com/iris-contrib/pongo2-addons" -) - -var startTime = time.Now() - -func main() { - app := iris.New() - - tmpl := iris.Django("./templates", ".html") - tmpl.Reload(true) // reload templates on each request (development mode) - tmpl.AddFunc("greet", func(s string) string { // {{greet(name)}} - return "Greetings " + s + "!" - }) - - // tmpl.RegisterFilter("myFilter", myFilter) // {{"simple input for filter"|myFilter}} - app.RegisterView(tmpl) - - app.Get("/", hi) - - // http://localhost:8080 - app.Listen(":8080") -} - -func hi(ctx iris.Context) { - // ctx.ViewData("title", "Hi Page") - // ctx.ViewData("name", "iris") - // ctx.ViewData("serverStartTime", startTime) - // or if you set all view data in the same handler you can use the - // iris.Map/pongo2.Context/map[string]interface{}, look below: - - ctx.View("hi.html", iris.Map{ - "title": "Hi Page", - "name": "iris", - "serverStartTime": startTime, - }) -} diff --git a/_examples/view/template_django_0/templates/hi.html b/_examples/view/template_django_0/templates/hi.html deleted file mode 100644 index 945782e4..00000000 --- a/_examples/view/template_django_0/templates/hi.html +++ /dev/null @@ -1,12 +0,0 @@ - - -{{title}} - - -

    Hi {{name|capfirst}}

    - -

    {{greet(name)}}

    - -

    Server started about {{serverStartTime|timesince}}. Refresh the page to see different result

    - - diff --git a/_examples/view/template_html_0/main.go b/_examples/view/template_html_0/main.go deleted file mode 100644 index ead5ec56..00000000 --- a/_examples/view/template_html_0/main.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() // defaults to these - - tmpl := iris.HTML("./templates", ".html") - tmpl.Reload(true) // reload templates on each request (development mode) - // default template funcs are: - // - // - {{ urlpath "mynamedroute" "pathParameter_ifneeded" }} - // - {{ render "header.html" }} - // - {{ render_r "header.html" }} // partial relative path to current page - // - {{ yield }} - // - {{ current }} - tmpl.AddFunc("greet", func(s string) string { - return "Greetings " + s + "!" - }) - app.RegisterView(tmpl) - - app.Get("/", hi) - - // http://localhost:8080 - app.Listen(":8080", iris.WithCharset("utf-8")) // defaults to that but you can change it. -} - -func hi(ctx iris.Context) { - ctx.ViewData("Title", "Hi Page") - ctx.ViewData("Name", "iris") // {{.Name}} will render: iris - // ctx.ViewData("", myCcustomStruct{}) - ctx.View("hi.html") -} - -/* -Note: - -In case you're wondering, the code behind the view engines derives from the "github.com/kataras/iris/v12/view" package, -access to the engines' variables can be granded by "github.com/kataras/iris/v12" package too. - - iris.HTML(...) is a shortcut of view.HTML(...) - iris.Django(...) >> >> view.Django(...) - iris.Pug(...) >> >> view.Pug(...) - iris.Handlebars(...) >> >> view.Handlebars(...) - iris.Amber(...) >> >> view.Amber(...) -*/ diff --git a/_examples/view/template_html_0/templates/hi.html b/_examples/view/template_html_0/templates/hi.html deleted file mode 100644 index fe355ba1..00000000 --- a/_examples/view/template_html_0/templates/hi.html +++ /dev/null @@ -1,8 +0,0 @@ - - -{{.Title}} - - -

    Hi {{.Name}}

    - - diff --git a/_examples/view/template_html_1/main.go b/_examples/view/template_html_1/main.go deleted file mode 100644 index a2a3b45a..00000000 --- a/_examples/view/template_html_1/main.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -type mypage struct { - Title string - Message string -} - -func main() { - app := iris.New() - - app.RegisterView(iris.HTML("./templates", ".html").Layout("layout.html")) - // TIP: append .Reload(true) to reload the templates on each request. - - app.Get("/", func(ctx iris.Context) { - ctx.CompressWriter(true) - ctx.ViewData("", mypage{"My Page title", "Hello world!"}) - ctx.View("mypage.html") - // Note that: you can pass "layout" : "otherLayout.html" to bypass the config's Layout property - // or view.NoLayout to disable layout on this render action. - // third is an optional parameter - }) - - // http://localhost:8080 - app.Listen(":8080") -} diff --git a/_examples/view/template_html_1/templates/layout.html b/_examples/view/template_html_1/templates/layout.html deleted file mode 100644 index 96f0c753..00000000 --- a/_examples/view/template_html_1/templates/layout.html +++ /dev/null @@ -1,11 +0,0 @@ - - -My Layout - - - -

    [layout] Body content is below...

    - - {{ yield }} - - diff --git a/_examples/view/template_html_1/templates/mypage.html b/_examples/view/template_html_1/templates/mypage.html deleted file mode 100644 index 0f85c0ab..00000000 --- a/_examples/view/template_html_1/templates/mypage.html +++ /dev/null @@ -1,4 +0,0 @@ -

    - Title: {{.Title}} -

    -

    Message: {{.Message}}

    \ No newline at end of file diff --git a/_examples/view/template_html_2/README.md b/_examples/view/template_html_2/README.md deleted file mode 100644 index f4f5ac99..00000000 --- a/_examples/view/template_html_2/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## Info - -This folder examines the {{render "dir/templatefilename" .}} functionality to manually render any template inside any template diff --git a/_examples/view/template_html_2/main.go b/_examples/view/template_html_2/main.go deleted file mode 100644 index 270b99ba..00000000 --- a/_examples/view/template_html_2/main.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - tmpl := iris.HTML("./templates", ".html") - tmpl.Layout("layouts/layout.html") - tmpl.AddFunc("greet", func(s string) string { - return "Greetings " + s + "!" - }) - - app.RegisterView(tmpl) - - app.Get("/", func(ctx iris.Context) { - if err := ctx.View("page1.html"); err != nil { - ctx.StatusCode(iris.StatusInternalServerError) - ctx.Writef(err.Error()) - } - }) - - // remove the layout for a specific route - app.Get("/nolayout", func(ctx iris.Context) { - ctx.ViewLayout(iris.NoLayout) - if err := ctx.View("page1.html"); err != nil { - ctx.StatusCode(iris.StatusInternalServerError) - ctx.Writef(err.Error()) - } - }) - - // set a layout for a party, .Layout should be BEFORE any Get or other Handle party's method - my := app.Party("/my").Layout("layouts/mylayout.html") - { // both of these will use the layouts/mylayout.html as their layout. - my.Get("/", func(ctx iris.Context) { - ctx.View("page1.html") - }) - my.Get("/other", func(ctx iris.Context) { - ctx.View("page1.html") - }) - } - - // http://localhost:8080 - // http://localhost:8080/nolayout - // http://localhost:8080/my - // http://localhost:8080/my/other - app.Listen(":8080") -} diff --git a/_examples/view/template_html_2/templates/layouts/layout.html b/_examples/view/template_html_2/templates/layouts/layout.html deleted file mode 100644 index eb543f0e..00000000 --- a/_examples/view/template_html_2/templates/layouts/layout.html +++ /dev/null @@ -1,12 +0,0 @@ - - -Layout - - - -

    This is the global layout

    -
    - - {{ yield }} - - diff --git a/_examples/view/template_html_2/templates/layouts/mylayout.html b/_examples/view/template_html_2/templates/layouts/mylayout.html deleted file mode 100644 index d87575d3..00000000 --- a/_examples/view/template_html_2/templates/layouts/mylayout.html +++ /dev/null @@ -1,12 +0,0 @@ - - -my Layout - - - -

    This is the layout for the /my/ and /my/other routes only

    -
    - - {{ yield }} - - diff --git a/_examples/view/template_html_2/templates/page1.html b/_examples/view/template_html_2/templates/page1.html deleted file mode 100644 index 8c1d8ed6..00000000 --- a/_examples/view/template_html_2/templates/page1.html +++ /dev/null @@ -1,7 +0,0 @@ -
    - -

    Page 1 {{ greet "iris developer"}}

    - - {{ render "partials/page1_partial1.html" }} - -
    diff --git a/_examples/view/template_html_2/templates/partials/page1_partial1.html b/_examples/view/template_html_2/templates/partials/page1_partial1.html deleted file mode 100644 index 8af006d2..00000000 --- a/_examples/view/template_html_2/templates/partials/page1_partial1.html +++ /dev/null @@ -1,3 +0,0 @@ -
    -

    Page 1's Partial 1

    -
    diff --git a/_examples/view/template_html_3/main.go b/_examples/view/template_html_3/main.go deleted file mode 100644 index c9fcb381..00000000 --- a/_examples/view/template_html_3/main.go +++ /dev/null @@ -1,66 +0,0 @@ -// Package main an example on how to naming your routes & use the custom 'url path' HTML Template Engine, same for other template engines. -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - app.RegisterView(iris.HTML("./templates", ".html").Reload(true)) - - mypathRoute := app.Get("/mypath", writePathHandler) - mypathRoute.Name = "my-page1" - - mypath2Route := app.Get("/mypath2/{paramfirst}/{paramsecond}", writePathHandler) - mypath2Route.Name = "my-page2" - - mypath3Route := app.Get("/mypath3/{paramfirst}/statichere/{paramsecond}", writePathHandler) - mypath3Route.Name = "my-page3" - - mypath4Route := app.Get("/mypath4/{paramfirst}/statichere/{paramsecond}/{otherparam}/{something:path}", writePathHandler) - // same as: app.Get("/mypath4/:paramfirst/statichere/:paramsecond/:otherparam/*something", writePathHandler) - mypath4Route.Name = "my-page4" - - // same with Handle/Func - mypath5Route := app.Handle("GET", "/mypath5/{paramfirst}/statichere/{paramsecond}/{otherparam}/anything/{something:path}", writePathHandler) - mypath5Route.Name = "my-page5" - - mypath6Route := app.Get("/mypath6/{paramfirst}/{paramsecond}/statichere/{paramThirdAfterStatic}", writePathHandler) - mypath6Route.Name = "my-page6" - - app.Get("/", func(ctx iris.Context) { - // for /mypath6... - paramsAsArray := []string{"theParam1", "theParam2", "paramThirdAfterStatic"} - ctx.ViewData("ParamsAsArray", paramsAsArray) - if err := ctx.View("page.html"); err != nil { - panic(err) - } - }) - - app.Get("/redirect/{namedRoute}", func(ctx iris.Context) { - routeName := ctx.Params().Get("namedRoute") - r := app.GetRoute(routeName) - if r == nil { - ctx.StatusCode(404) - ctx.Writef("Route with name %s not found", routeName) - return - } - - println("The path of " + routeName + "is: " + r.Path) - // if routeName == "my-page1" - // prints: The path of of my-page1 is: /mypath - // if it's a path which takes named parameters - // then use "r.ResolvePath(paramValuesHere)" - ctx.Redirect(r.Path) - // http://localhost:8080/redirect/my-page1 will redirect to -> http://localhost:8080/mypath - }) - - // http://localhost:8080 - // http://localhost:8080/redirect/my-page1 - app.Listen(":8080") -} - -func writePathHandler(ctx iris.Context) { - ctx.Writef("Hello from %s.", ctx.Path()) -} diff --git a/_examples/view/template_html_3/templates/page.html b/_examples/view/template_html_3/templates/page.html deleted file mode 100644 index 8835b3d0..00000000 --- a/_examples/view/template_html_3/templates/page.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - template_html_3 - - - - - -
    /mypath -
    -
    - - /mypath2/{paramfirst}/{paramsecond} -
    -
    - - /mypath3/{paramfirst}/statichere/{paramsecond} -
    -
    - - - /mypath4/{paramfirst}/statichere/{paramsecond}/{otherparam}/{something:path} -
    -
    - - - /mypath5/{paramfirst}/statichere/{paramsecond}/{otherparam}/anything/{anything:path} -
    -
    - - - /mypath6/{paramfirst}/{paramsecond}/statichere/{paramThirdAfterStatic} - - - - \ No newline at end of file diff --git a/_examples/view/template_html_4/hosts b/_examples/view/template_html_4/hosts deleted file mode 100644 index 36bb689b..00000000 --- a/_examples/view/template_html_4/hosts +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 1993-2009 Microsoft Corp. -# -# This is a sample HOSTS file used by Microsoft TCP/IP for Windows. -# -# This file contains the mappings of IP addresses to host names. Each -# entry should be kept on an individual line. The IP address should -# be placed in the first column followed by the corresponding host name. -# The IP address and the host name should be separated by at least one -# space. -# -# Additionally, comments (such as these) may be inserted on individual -# lines or following the machine name denoted by a '#' symbol. -# -# For example: -# -# 102.54.94.97 rhino.acme.com # source server -# 38.25.63.10 x.acme.com # x client host - -# localhost name resolution is handled within DNS itself. -127.0.0.1 localhost -::1 localhost -#-iris-For development machine, you have to configure your dns also for online, search google how to do it if you don't know - -127.0.0.1 username1.127.0.0.1 -127.0.0.1 username2.127.0.0.1 -127.0.0.1 username3.127.0.0.1 -127.0.0.1 username4.127.0.0.1 -127.0.0.1 username5.127.0.0.1 -# note that you can always use custom subdomains -#-END iris- - -# Windows: Drive:/Windows/system32/drivers/etc/hosts, on Linux: /etc/hosts \ No newline at end of file diff --git a/_examples/view/template_html_4/main.go b/_examples/view/template_html_4/main.go deleted file mode 100644 index ef0b97b8..00000000 --- a/_examples/view/template_html_4/main.go +++ /dev/null @@ -1,76 +0,0 @@ -// Package main an example on how to naming your routes & use the custom 'url' HTML Template Engine, same for other template engines. -package main - -import ( - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/core/router" -) - -const ( - host = "127.0.0.1:8080" -) - -func main() { - app := iris.New() - - // create a custom path reverser, iris let you define your own host and scheme - // which is useful when you have nginx or caddy in front of iris. - rv := router.NewRoutePathReverser(app, router.WithHost(host), router.WithScheme("http")) - // locate and define our templates as usual. - templates := iris.HTML("./templates", ".html") - // add a custom func of "url" and pass the rv.URL as its template function body, - // so {{url "routename" "paramsOrSubdomainAsFirstArgument"}} will work inside our templates. - templates.AddFunc("url", rv.URL) - - app.RegisterView(templates) - - // wildcard subdomain, will catch username1.... username2.... username3... username4.... username5... - // that our below links are providing via page.html's first argument which is the subdomain. - - subdomain := app.Party("*.") - - mypathRoute := subdomain.Get("/mypath", emptyHandler) - mypathRoute.Name = "my-page1" - - mypath2Route := subdomain.Get("/mypath2/{paramfirst}/{paramsecond}", emptyHandler) - mypath2Route.Name = "my-page2" - - mypath3Route := subdomain.Get("/mypath3/{paramfirst}/statichere/{paramsecond}", emptyHandler) - mypath3Route.Name = "my-page3" - - mypath4Route := subdomain.Get("/mypath4/{paramfirst}/statichere/{paramsecond}/{otherparam}/{something:path}", emptyHandler) - mypath4Route.Name = "my-page4" - - mypath5Route := subdomain.Handle("GET", "/mypath5/{paramfirst}/statichere/{paramsecond}/{otherparam}/anything/{something:path}", emptyHandler) - mypath5Route.Name = "my-page5" - - mypath6Route := subdomain.Get("/mypath6/{paramfirst}/{paramsecond}/staticParam/{paramThirdAfterStatic}", emptyHandler) - mypath6Route.Name = "my-page6" - - app.Get("/", func(ctx iris.Context) { - // for username5./mypath6... - paramsAsArray := []string{"username5", "theParam1", "theParam2", "paramThirdAfterStatic"} - ctx.ViewData("ParamsAsArray", paramsAsArray) - if err := ctx.View("page.html"); err != nil { - panic(err) - } - }) - - // simple path so you can test it without host mapping and subdomains, - // at view it make uses of {{urlpath ...}} - // in order to showcase you that you can use it - // if you don't want the entire scheme and host to be part of the url. - app.Get("/mypath7/{paramfirst}/{paramsecond}/static/{paramthird}", emptyHandler).Name = "my-page7" - - // http://127.0.0.1:8080 - app.Listen(host) -} - -func emptyHandler(ctx iris.Context) { - ctx.Writef("Hello from subdomain: %s , you're in path: %s", ctx.Subdomain(), ctx.Path()) -} - -// Note: -// If you got an empty string on {{ url }} or {{ urlpath }} it means that -// args length are not aligned with the route's parameters length -// or the route didn't found by the passed name. diff --git a/_examples/view/template_html_4/templates/page.html b/_examples/view/template_html_4/templates/page.html deleted file mode 100644 index 9e35dc37..00000000 --- a/_examples/view/template_html_4/templates/page.html +++ /dev/null @@ -1,43 +0,0 @@ - - -username1.127.0.0.1:8080/mypath -
    -
    - - - username2.127.0.0.1:8080/mypath2/{paramfirst}/{paramsecond} - -
    -
    - - - username3.127.0.0.1:8080/mypath3/{paramfirst}/statichere/{paramsecond} - -
    -
    - - - username4.127.0.0.1:8080/mypath4/{paramfirst}/statichere/{paramsecond}/{otherParam}/{something:path} - -
    -
    - - - username5.127.0.0.1:8080/mypath5/{paramfirst}/statichere/{paramsecond}/{otherparam}/anything/{something:path} - -
    -
    - - - username5.127.0.0.1:8080/mypath6/{paramfirst}/{paramsecond}/staticParam/{paramThirdAfterStatic} - -
    -
    - - - mypath7/{paramfirst}/{paramsecond}/static/{paramthird} - -
    -
    - diff --git a/_examples/view/template_html_5/main.go b/_examples/view/template_html_5/main.go deleted file mode 100644 index 7e79e0b2..00000000 --- a/_examples/view/template_html_5/main.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - app.RegisterView(iris.HTML("./views", ".html").Layout("layout.html")) - // TIP: append .Reload(true) to reload the templates on each request. - - app.Get("/home", func(ctx iris.Context) { - ctx.ViewData("title", "Home page") - ctx.View("home.html") - // Note that: you can pass "layout" : "otherLayout.html" to bypass the config's Layout property - // or view.NoLayout to disable layout on this render action. - // third is an optional parameter - }) - - app.Get("/about", func(ctx iris.Context) { - ctx.View("about.html") - }) - - app.Get("/user/index", func(ctx iris.Context) { - ctx.View("user/index.html") - }) - - // http://localhost:8080 - app.Listen(":8080") -} diff --git a/_examples/view/template_html_5/views/about.html b/_examples/view/template_html_5/views/about.html deleted file mode 100644 index a2642992..00000000 --- a/_examples/view/template_html_5/views/about.html +++ /dev/null @@ -1,15 +0,0 @@ -{{ define "about-head"}} - about page - -{{ end }} - -{{ define "about-body"}} - extend body content in layout. -{{ end }} -
    - Hello about page -
    \ No newline at end of file diff --git a/_examples/view/template_html_5/views/home.html b/_examples/view/template_html_5/views/home.html deleted file mode 100644 index 36599009..00000000 --- a/_examples/view/template_html_5/views/home.html +++ /dev/null @@ -1,11 +0,0 @@ -{{ define "home-head"}} - {{.title}} - -{{ end }} -
    - Hello home page -
    \ No newline at end of file diff --git a/_examples/view/template_html_5/views/layout.html b/_examples/view/template_html_5/views/layout.html deleted file mode 100644 index c374205f..00000000 --- a/_examples/view/template_html_5/views/layout.html +++ /dev/null @@ -1,11 +0,0 @@ - - -{{ part "head" }} - - -

    [layout] Body content is below...

    - {{ part "body" }} - - {{ yield }} - - diff --git a/_examples/view/template_html_5/views/user/index.html b/_examples/view/template_html_5/views/user/index.html deleted file mode 100644 index 6c73fb2e..00000000 --- a/_examples/view/template_html_5/views/user/index.html +++ /dev/null @@ -1,10 +0,0 @@ -{{ define "user/index-head"}} - -{{ end }} -
    - Hello user index page -
    \ No newline at end of file diff --git a/_examples/view/template_jet_0/README.md b/_examples/view/template_jet_0/README.md deleted file mode 100644 index 627e5b3e..00000000 --- a/_examples/view/template_jet_0/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Jet Engine Example - -This example is a fork of to work with Iris, so you can notice the differences side by side. - -Read more at: https://github.com/CloudyKit/jet/blob/master/docs/syntax.md - -> The Iris Jet View Engine fixes some bugs that the underline [jet template parser](https://github.com/CloudyKit/jet) currently has. - - -Continue by learning how you can [serve embedded templates](../template_jet_1_embedded). \ No newline at end of file diff --git a/_examples/view/template_jet_0/main.go b/_examples/view/template_jet_0/main.go deleted file mode 100644 index a7cb43c8..00000000 --- a/_examples/view/template_jet_0/main.go +++ /dev/null @@ -1,146 +0,0 @@ -// Package main shows how to use jet template parser with ease using the Iris built-in Jet view engine. -// This example is customized fork of https://github.com/CloudyKit/jet/tree/master/examples/todos, so you can -// notice the differences side by side. -package main - -import ( - "bytes" - "encoding/base64" - "fmt" - "os" - "reflect" - "strings" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/view" -) - -type tTODO struct { - Text string - Done bool -} - -type doneTODOs struct { - list map[string]*tTODO - keys []string - len int - i int -} - -func (dt *doneTODOs) New(todos map[string]*tTODO) *doneTODOs { - dt.len = len(todos) - for k := range todos { - dt.keys = append(dt.keys, k) - } - dt.list = todos - return dt -} - -// Range satisfies the jet.Ranger interface and only returns TODOs that are done, -// even when the list contains TODOs that are not done. -func (dt *doneTODOs) Range() (reflect.Value, reflect.Value, bool) { - for dt.i < dt.len { - key := dt.keys[dt.i] - dt.i++ - if dt.list[key].Done { - return reflect.ValueOf(key), reflect.ValueOf(dt.list[key]), false - } - } - return reflect.Value{}, reflect.Value{}, true -} - -// Note: jet version 4 requires this. -func (dt *doneTODOs) ProvidesIndex() bool { return true } - -func (dt *doneTODOs) Render(r *view.JetRuntime) { - r.Write([]byte(fmt.Sprintf("custom renderer"))) -} - -// Render implements jet.Renderer interface -func (t *tTODO) Render(r *view.JetRuntime) { - done := "yes" - if !t.Done { - done = "no" - } - r.Write([]byte(fmt.Sprintf("TODO: %s (done: %s)", t.Text, done))) -} - -func main() { - // - // Type aliases: - // view.JetRuntimeVars = jet.VarMap - // view.JetRuntime = jet.Runtime - // view.JetArguments = jet.Arguments - // - // Iris also gives you the ability to put runtime variables - // from middlewares as well, by: - // view.AddJetRuntimeVars(ctx, vars) - // or tmpl.AddRuntimeVars(ctx, vars) - app := iris.New() - tmpl := iris.Jet("./views", ".jet") // <-- - tmpl.Reload(true) // remove in production. - tmpl.AddFunc("base64", func(a view.JetArguments) reflect.Value { - a.RequireNumOfArguments("base64", 1, 1) - - buffer := bytes.NewBuffer(nil) - fmt.Fprint(buffer, a.Get(0)) - - return reflect.ValueOf(base64.URLEncoding.EncodeToString(buffer.Bytes())) - }) - app.RegisterView(tmpl) // <-- - - todos := map[string]*tTODO{ - "example-todo-1": {Text: "Add an show todo page to the example project", Done: true}, - "example-todo-2": {Text: "Add an add todo page to the example project"}, - "example-todo-3": {Text: "Add an update todo page to the example project"}, - "example-todo-4": {Text: "Add an delete todo page to the example project", Done: true}, - } - - app.Get("/", func(ctx iris.Context) { - err := ctx.View("todos/index.jet", todos) // <-- - // Note that the `ctx.View` already logs the error if logger level is allowing it and returns the error. - if err != nil { - ctx.StopWithText(iris.StatusInternalServerError, "Templates not rendered!") - } - }) - - app.Get("/todo", func(ctx iris.Context) { - id := ctx.URLParam("id") - todo, ok := todos[id] - if !ok { - ctx.Redirect("/") - return - } - - ctx.View("todos/show.jet", todo) - }) - app.Get("/all-done", func(ctx iris.Context) { - // vars := make(view.JetRuntimeVars) - // vars.Set("showingAllDone", true) - // vars.Set("title", "Todos - All Done") - // view.AddJetRuntimeVars(ctx, vars) - // ctx.View("todos/index.jet", (&doneTODOs{}).New(todos)) - // - // OR - - ctx.ViewData("showingAllDone", true) - ctx.ViewData("title", "Todos - All Done") - - // Use ctx.ViewData("_jet", jetData) - // if using as middleware and you want - // to pre-set the value or even change it later on from another next middleware. - // ctx.ViewData("_jet", (&doneTODOs{}).New(todos)) - // and ctx.View("todos/index.jet") - // OR - ctx.View("todos/index.jet", (&doneTODOs{}).New(todos)) - }) - - port := os.Getenv("PORT") - if len(port) == 0 { - port = ":8080" - } else if !strings.HasPrefix(":", port) { - port = ":" + port - } - - app.Listen(port) -} diff --git a/_examples/view/template_jet_0/views/layouts/application.jet b/_examples/view/template_jet_0/views/layouts/application.jet deleted file mode 100644 index 9fce2365..00000000 --- a/_examples/view/template_jet_0/views/layouts/application.jet +++ /dev/null @@ -1,10 +0,0 @@ - - - - - {{ isset(title) ? title : "" }} - - - {{block documentBody()}}{{end}} - - diff --git a/_examples/view/template_jet_0/views/todos/index.jet b/_examples/view/template_jet_0/views/todos/index.jet deleted file mode 100644 index 5b700e28..00000000 --- a/_examples/view/template_jet_0/views/todos/index.jet +++ /dev/null @@ -1,30 +0,0 @@ -{{extends "../layouts/application.jet"}} - -{{block button(label, href="javascript:void(0)")}} - {{ label }} -{{end}} - -{{block ul()}} -
      - {{yield content}} -
    -{{end}} - -{{block documentBody()}} -

    List of TODOs

    - - {{if isset(showingAllDone) && showingAllDone}} -

    Showing only TODOs that are done

    - {{else}} -

    Show only TODOs that are done

    - {{end}} - - {{yield ul() content}} - {{range id, value := .}} -
  • - {{ value.Text }} - {{yield button(label="UP", href="/update/?id="+base64(id))}} - {{yield button(href="/delete/?id="+id, label="DL")}} -
  • - {{end}} - {{end}} -{{end}} diff --git a/_examples/view/template_jet_0/views/todos/show.jet b/_examples/view/template_jet_0/views/todos/show.jet deleted file mode 100644 index cc37722e..00000000 --- a/_examples/view/template_jet_0/views/todos/show.jet +++ /dev/null @@ -1,9 +0,0 @@ -{{extends "../layouts/application.jet"}} - -{{block documentBody()}} -

    Show TODO

    -

    This uses a custom renderer by implementing the Renderer interface. -

    - {{.}} -

    -{{end}} diff --git a/_examples/view/template_jet_1_embedded/README.md b/_examples/view/template_jet_1_embedded/README.md deleted file mode 100644 index bb78ada6..00000000 --- a/_examples/view/template_jet_1_embedded/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Jet Engine Example (Embedded) - -Take a look at the [../template_jet_0](../template_jet_0)'s README first. - -This example teaches you how to use jet templates embedded in your applications with ease using the Iris built-in Jet view engine. - -This example is a customized fork of https://github.com/CloudyKit/jet/tree/master/examples/asset_packaging, so you can -notice the differences side by side. For example, you don't have to use any external package inside your application, -Iris manually builds the template loader for binary data when Asset and AssetNames are available through tools like the [go-bindata](github.com/go-bindata/go-bindata). - -Note that you can still use any custom loaders through the `JetEngine.SetLoader` -which overrides any previous loaders like `JetEngine.Binary` we use on this example. - -## How to run - -```sh -$ go get -u github.com/go-bindata/go-bindata/v3/go-bindata -$ go-bindata ./views/... -$ go build -$ ./template_jet_0_embedded -``` - -Repeat the above steps on any `./views` changes. - -> html files are not used, only binary data. You can move or delete the `./views` folder. diff --git a/_examples/view/template_jet_1_embedded/bindata.go b/_examples/view/template_jet_1_embedded/bindata.go deleted file mode 100644 index 11989e7b..00000000 --- a/_examples/view/template_jet_1_embedded/bindata.go +++ /dev/null @@ -1,308 +0,0 @@ -// Code generated by go-bindata. DO NOT EDIT. -// sources: -// views/includes/_partial.jet -// views/includes/blocks.jet -// views/index.jet -// views/layouts/application.jet -package main - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(data []byte, name string) ([]byte, error) { - gz, err := gzip.NewReader(bytes.NewBuffer(data)) - if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) - } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -func (fi bindataFileInfo) Name() string { - return fi.name -} -func (fi bindataFileInfo) Size() int64 { - return fi.size -} -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} -func (fi bindataFileInfo) IsDir() bool { - return false -} -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -var _viewsIncludes_partialJet = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb2\x29\xb0\xf3\xcc\x4b\xce\x29\x4d\x49\x4d\x51\x28\x48\x2c\x2a\xc9\x4c\xcc\xb1\xd1\x2f\xb0\xe3\xe5\x02\x04\x00\x00\xff\xff\x90\x62\x4f\xfb\x19\x00\x00\x00") - -func viewsIncludes_partialJetBytes() ([]byte, error) { - return bindataRead( - _viewsIncludes_partialJet, - "views/includes/_partial.jet", - ) -} - -func viewsIncludes_partialJet() (*asset, error) { - bytes, err := viewsIncludes_partialJetBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "views/includes/_partial.jet", size: 25, mode: os.FileMode(438), modTime: time.Unix(1565946441, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _viewsIncludesBlocksJet = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xaa\xae\x4e\xca\xc9\x4f\xce\x56\xc8\x4d\xcd\x2b\xd5\xd0\xac\xad\xe5\xe5\x52\x50\xb0\x29\xb0\x0b\xc9\x48\x05\x0b\x29\x40\x64\xcb\x13\x8b\x15\x32\xf3\xca\xf2\xb3\x53\x53\xf4\x6c\xf4\x0b\xec\x78\xb9\xaa\xab\x53\xf3\x52\x40\xca\x01\x01\x00\x00\xff\xff\xa0\xd9\xd9\x5d\x41\x00\x00\x00") - -func viewsIncludesBlocksJetBytes() ([]byte, error) { - return bindataRead( - _viewsIncludesBlocksJet, - "views/includes/blocks.jet", - ) -} - -func viewsIncludesBlocksJet() (*asset, error) { - bytes, err := viewsIncludesBlocksJetBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "views/includes/blocks.jet", size: 65, mode: os.FileMode(438), modTime: time.Unix(1565946441, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _viewsIndexJet = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\x90\xb1\x6a\xf3\x30\x14\x85\xf7\x1f\xfe\x77\x38\xf5\xd2\x74\xa9\xc9\x5a\x8c\x87\x42\x86\x2e\x5d\xfa\x00\x45\xb6\x6e\xb0\x1a\x59\x57\xf8\x5e\xd7\x36\x22\xef\x5e\x2c\x9b\x10\xda\xed\x48\xe7\x3b\xe8\x43\x29\xd1\xac\x14\xac\xa0\xf0\x66\xe1\x51\xa5\x34\x31\x7a\xd7\x1a\x75\x1c\x9e\xbf\x48\x8b\xeb\xf5\xff\xbf\x94\x5c\x1f\x79\x50\x14\x2e\xb4\x7e\xb4\x24\x65\xe3\xb9\xbd\xc8\x8d\x58\x99\x7c\x05\xcb\xed\xd8\x53\xd0\x57\xb6\xcb\xe1\x69\xed\x80\xaa\x3b\xd6\xa7\xbe\x21\x6b\xc9\x82\x66\xd3\x47\x4f\x55\xd9\x1d\xeb\x75\x08\x54\xc1\x7c\xd7\x6b\x00\x52\x5a\x1c\x79\x8b\x9e\xc2\x78\x5b\x97\x5b\xbf\xe6\x94\x76\x83\x3b\x95\xcf\x68\x06\x75\xc6\xdf\xc9\x64\xf0\x8c\x87\x9d\x79\x3b\x9f\x66\x27\x2a\x87\xc2\x32\xc9\x3b\x6b\x3e\x66\x7e\x7f\x03\xa8\x62\xfd\xd1\xf1\x24\xe8\x78\xfa\x33\xc4\xc4\xc3\x45\x5e\xf0\x7b\x8e\xc9\x08\x02\x2b\x76\xde\xa2\xa1\xd6\x8c\x42\x70\x9a\xe1\xf0\xa8\xa0\x4c\x57\x65\xac\x37\x31\x0a\x76\xfb\xd4\x3d\xfc\x04\x00\x00\xff\xff\x28\x5a\x9d\x42\x85\x01\x00\x00") - -func viewsIndexJetBytes() ([]byte, error) { - return bindataRead( - _viewsIndexJet, - "views/index.jet", - ) -} - -func viewsIndexJet() (*asset, error) { - bytes, err := viewsIndexJetBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "views/index.jet", size: 389, mode: os.FileMode(438), modTime: time.Unix(1594059793, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _viewsLayoutsApplicationJet = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x3c\x8e\xbd\xae\xc2\x30\x0c\x85\xf7\x4a\x7d\x07\xdf\x4c\x97\x01\x75\x65\x70\x3b\x00\x65\x85\xa1\x0c\x8c\x69\x6d\x11\x44\x7e\x10\x18\x89\x2a\xca\xbb\x23\xda\xc0\x64\xcb\x3e\xdf\xa7\x83\x7f\xdb\xfd\xa6\x3b\x1d\x5a\x30\xe2\x6c\x53\x16\xf8\x99\x60\xb5\x3f\xd7\x8a\xbd\x6a\xca\x02\x00\x0d\x6b\x9a\x36\x00\x74\x2c\x1a\x06\xa3\xef\x0f\x96\x5a\x1d\xbb\xdd\x72\xa5\xbe\x3f\xb9\x88\xe5\xa6\x75\x3d\x13\x31\x01\xbf\xb4\xbb\x59\xc6\x6a\xbe\x4f\xaa\xea\xe7\xc2\x3e\xd0\x98\xc9\x18\x7b\x1b\x86\x2b\x50\x18\x9e\x8e\xbd\xac\x03\x8d\xff\x8b\x94\x62\x64\x4f\x29\xcd\x64\xce\x63\x95\xab\xbe\x03\x00\x00\xff\xff\xee\xc2\x94\xa4\xbc\x00\x00\x00") - -func viewsLayoutsApplicationJetBytes() ([]byte, error) { - return bindataRead( - _viewsLayoutsApplicationJet, - "views/layouts/application.jet", - ) -} - -func viewsLayoutsApplicationJet() (*asset, error) { - bytes, err := viewsLayoutsApplicationJetBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "views/layouts/application.jet", size: 188, mode: os.FileMode(438), modTime: time.Unix(1565946441, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "views/includes/_partial.jet": viewsIncludes_partialJet, - "views/includes/blocks.jet": viewsIncludesBlocksJet, - "views/index.jet": viewsIndexJet, - "views/layouts/application.jet": viewsLayoutsApplicationJet, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "views": {nil, map[string]*bintree{ - "includes": {nil, map[string]*bintree{ - "_partial.jet": {viewsIncludes_partialJet, map[string]*bintree{}}, - "blocks.jet": {viewsIncludesBlocksJet, map[string]*bintree{}}, - }}, - "index.jet": {viewsIndexJet, map[string]*bintree{}}, - "layouts": {nil, map[string]*bintree{ - "application.jet": {viewsLayoutsApplicationJet, map[string]*bintree{}}, - }}, - }}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} diff --git a/_examples/view/template_jet_1_embedded/main.go b/_examples/view/template_jet_1_embedded/main.go deleted file mode 100644 index 028fb7be..00000000 --- a/_examples/view/template_jet_1_embedded/main.go +++ /dev/null @@ -1,34 +0,0 @@ -// Package main shows how to use jet templates embedded in your application with ease using the Iris built-in Jet view engine. -// This example is a customized fork of https://github.com/CloudyKit/jet/tree/master/examples/asset_packaging, so you can -// notice the differences side by side. For example, you don't have to use any external package inside your application, -// Iris manually builds the template loader for binary data when Asset and AssetNames are available via tools like the go-bindata. -package main - -import ( - "os" - "strings" - - "github.com/kataras/iris/v12" -) - -// $ go get -u github.com/go-bindata/go-bindata/v3/go-bindata -// $ go-bindata ./views/... -// $ go run . -func main() { - app := iris.New() - tmpl := iris.Jet("./views", ".jet").Binary(Asset, AssetNames) - app.RegisterView(tmpl) - - app.Get("/", func(ctx iris.Context) { - ctx.View("index.jet") - }) - - port := os.Getenv("PORT") - if len(port) == 0 { - port = ":8080" - } else if !strings.HasPrefix(":", port) { - port = ":" + port - } - - app.Listen(port) -} diff --git a/_examples/view/template_jet_1_embedded/views/includes/_partial.jet b/_examples/view/template_jet_1_embedded/views/includes/_partial.jet deleted file mode 100644 index 3ebaa7af..00000000 --- a/_examples/view/template_jet_1_embedded/views/includes/_partial.jet +++ /dev/null @@ -1 +0,0 @@ -

    Included partial

    diff --git a/_examples/view/template_jet_1_embedded/views/includes/blocks.jet b/_examples/view/template_jet_1_embedded/views/includes/blocks.jet deleted file mode 100644 index 14c074ea..00000000 --- a/_examples/view/template_jet_1_embedded/views/includes/blocks.jet +++ /dev/null @@ -1,3 +0,0 @@ -{{block menu()}} -

    The menu block was invoked.

    -{{end}} diff --git a/_examples/view/template_jet_1_embedded/views/index.jet b/_examples/view/template_jet_1_embedded/views/index.jet deleted file mode 100644 index 670f11a7..00000000 --- a/_examples/view/template_jet_1_embedded/views/index.jet +++ /dev/null @@ -1,16 +0,0 @@ -{{extends "layouts/application.jet"}} -{{import "includes/blocks.jet"}} - -{{block documentBody()}} -

    Embedded example

    - - - - {{include "includes/_partial.jet"}} - - {{if !includeIfExists("doesNotExist.jet")}} -

    Shows how !includeIfExists works: doesNotExist.jet was not included because it doesn't exist.

    - {{end}} -{{end}} diff --git a/_examples/view/template_jet_1_embedded/views/layouts/application.jet b/_examples/view/template_jet_1_embedded/views/layouts/application.jet deleted file mode 100644 index 16117b71..00000000 --- a/_examples/view/template_jet_1_embedded/views/layouts/application.jet +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Embedded example - - - {{block documentBody()}}{{end}} - - diff --git a/_examples/view/template_jet_2/main.go b/_examples/view/template_jet_2/main.go deleted file mode 100644 index db872d2b..00000000 --- a/_examples/view/template_jet_2/main.go +++ /dev/null @@ -1,70 +0,0 @@ -// Package main an example on how to naming your routes & use the custom 'url path' Jet Template Engine. -package main - -import ( - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - app.RegisterView(iris.Jet("./views", ".jet").Reload(true)) - - mypathRoute := app.Get("/mypath", writePathHandler) - mypathRoute.Name = "my-page1" - - mypath2Route := app.Get("/mypath2/{paramfirst}/{paramsecond}", writePathHandler) - mypath2Route.Name = "my-page2" - - mypath3Route := app.Get("/mypath3/{paramfirst}/statichere/{paramsecond}", writePathHandler) - mypath3Route.Name = "my-page3" - - mypath4Route := app.Get("/mypath4/{paramfirst}/statichere/{paramsecond}/{otherparam}/{something:path}", writePathHandler) - // same as: app.Get("/mypath4/:paramfirst/statichere/:paramsecond/:otherparam/*something", writePathHandler) - mypath4Route.Name = "my-page4" - - // same with Handle/Func - mypath5Route := app.Handle("GET", "/mypath5/{paramfirst:int}/statichere/{paramsecond}/{otherparam}/anything/{something:path}", writePathHandlerPage5) - mypath5Route.Name = "my-page5" - - mypath6Route := app.Get("/mypath6/{paramfirst}/{paramsecond}/statichere/{paramThirdAfterStatic}", writePathHandler) - mypath6Route.Name = "my-page6" - - app.Get("/", func(ctx iris.Context) { - // for /mypath6... - paramsAsArray := []string{"theParam1", "theParam2", "paramThirdAfterStatic"} - ctx.ViewData("ParamsAsArray", paramsAsArray) - if err := ctx.View("page.jet"); err != nil { - panic(err) - } - }) - - app.Get("/redirect/{namedRoute}", func(ctx iris.Context) { - routeName := ctx.Params().Get("namedRoute") - r := app.GetRoute(routeName) - if r == nil { - ctx.StatusCode(iris.StatusNotFound) - ctx.Writef("Route with name %s not found", routeName) - return - } - - println("The path of " + routeName + "is: " + r.Path) - // if routeName == "my-page1" - // prints: The path of of my-page1 is: /mypath - // if it's a path which takes named parameters - // then use "r.ResolvePath(paramValuesHere)" - ctx.Redirect(r.Path) - // http://localhost:8080/redirect/my-page1 will redirect to -> http://localhost:8080/mypath - }) - - // http://localhost:8080 - // http://localhost:8080/redirect/my-page1 - app.Listen(":8080") -} - -func writePathHandler(ctx iris.Context) { - ctx.Writef("Hello from %s.", ctx.Path()) -} - -func writePathHandlerPage5(ctx iris.Context) { - ctx.Writef("Hello from %s.\nparamfirst(int)=%d", ctx.Path(), ctx.Params().GetIntDefault("paramfirst", 0)) -} diff --git a/_examples/view/template_jet_2/views/page.jet b/_examples/view/template_jet_2/views/page.jet deleted file mode 100644 index c7268d9d..00000000 --- a/_examples/view/template_jet_2/views/page.jet +++ /dev/null @@ -1,24 +0,0 @@ -/mypath -
    -
    -/mypath2/{paramfirst}/{paramsecond} -
    -
    - -/mypath3/{paramfirst}/statichere/{paramsecond} -
    -
    - - - /mypath4/{paramfirst}/statichere/{paramsecond}/{otherparam}/{something:path} -
    -
    - - - /mypath5/{paramfirst}/statichere/{paramsecond}/{otherparam}/anything/{anything:path} -
    -
    - - - /mypath6/{paramfirst}/{paramsecond}/statichere/{paramThirdAfterStatic} - diff --git a/_examples/view/template_jet_3/main.go b/_examples/view/template_jet_3/main.go deleted file mode 100644 index 6928243e..00000000 --- a/_examples/view/template_jet_3/main.go +++ /dev/null @@ -1,55 +0,0 @@ -package main - -import ( - "fmt" - "reflect" - "strings" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/view" -) - -// https://github.com/kataras/iris/issues/1443 - -func main() { - - tmpl := iris.Jet("./views", ".jet") - tmpl.Reload(true) - - val := reflect.ValueOf(ViewBuiler{}) - fns := val.Type() - for i := 0; i < fns.NumMethod(); i++ { - method := fns.Method(i) - tmpl.AddFunc(strings.ToLower(method.Name), val.Method(i).Interface()) - } - - app := iris.New() - app.RegisterView(tmpl) - - app.Get("/", func(ctx iris.Context) { - ctx.View("index.jet") - }) - - app.Listen(":8080") -} - -type ViewBuiler struct { -} - -func (ViewBuiler) Asset(a view.JetArguments) reflect.Value { - path := a.Get(0).String() - // fmt.Println(os.Getenv("APP_URL")) - return reflect.ValueOf(path) -} - -func (ViewBuiler) Style(a view.JetArguments) reflect.Value { - path := a.Get(0).String() - s := fmt.Sprintf(` `, path) - return reflect.ValueOf(s) -} - -func (ViewBuiler) Script(a view.JetArguments) reflect.Value { - path := a.Get(0).String() - s := fmt.Sprintf(``, path) - return reflect.ValueOf(s) -} diff --git a/_examples/view/template_jet_3/views/index.jet b/_examples/view/template_jet_3/views/index.jet deleted file mode 100644 index bfb1e3fa..00000000 --- a/_examples/view/template_jet_3/views/index.jet +++ /dev/null @@ -1,5 +0,0 @@ -{{ asset("./myasset.mp3")}} -
    -{{ style("my-stle.css")}} -
    -{{ script("my-script.js")}} \ No newline at end of file diff --git a/_examples/view/template_pug_0/main.go b/_examples/view/template_pug_0/main.go deleted file mode 100644 index a7d38186..00000000 --- a/_examples/view/template_pug_0/main.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - - tmpl := iris.Pug("./templates", ".pug") - tmpl.Reload(true) // reload templates on each request (development mode) - tmpl.AddFunc("greet", func(s string) string { // add your template func here. - return "Greetings " + s + "!" - }) - - app.RegisterView(tmpl) - - app.Get("/", index) - - // http://localhost:8080 - app.Listen(":8080") -} - -func index(ctx iris.Context) { - ctx.ViewData("pageTitle", "My Index Page") - ctx.ViewData("youAreUsingJade", true) - // Q: why need extension .pug? - // A: Because you can register more than one view engine per Iris application. - ctx.View("index.pug") -} diff --git a/_examples/view/template_pug_0/templates/index.pug b/_examples/view/template_pug_0/templates/index.pug deleted file mode 100644 index e0f39238..00000000 --- a/_examples/view/template_pug_0/templates/index.pug +++ /dev/null @@ -1,25 +0,0 @@ -mixin withGo - | Generating Go html/template output. - -doctype html -html(lang="en") - head - title= .pageTitle - script(type='text/javascript'). - if (foo) { - bar(1 + 5) - } - body - h1 Jade - template engine - #container.col - if .youAreUsingJade - p {{ greet "iris user" }} - p You are amazing! - else - p Get on it! - p. - Jade is #[a(terse)] and simple - templating language with a - #[strong focus] on performance - and powerful features. - + withGo \ No newline at end of file diff --git a/_examples/view/template_pug_1/main.go b/_examples/view/template_pug_1/main.go deleted file mode 100644 index 27c50f06..00000000 --- a/_examples/view/template_pug_1/main.go +++ /dev/null @@ -1,42 +0,0 @@ -// Package main shows an example of pug actions based on https://github.com/Joker/jade/tree/master/example/actions -package main - -import "github.com/kataras/iris/v12" - -type Person struct { - Name string - Age int - Emails []string - Jobs []*Job -} - -type Job struct { - Employer string - Role string -} - -func main() { - app := iris.New() - - tmpl := iris.Pug("./templates", ".pug") - app.RegisterView(tmpl) - - app.Get("/", index) - - // http://localhost:8080 - app.Listen(":8080") -} - -func index(ctx iris.Context) { - job1 := Job{Employer: "Monash B", Role: "Honorary"} - job2 := Job{Employer: "Box Hill", Role: "Head of HE"} - - person := Person{ - Name: "jan", - Age: 50, - Emails: []string{"jan@newmarch.name", "jan.newmarch@gmail.com"}, - Jobs: []*Job{&job1, &job2}, - } - - ctx.View("index.pug", person) -} diff --git a/_examples/view/template_pug_1/templates/index.pug b/_examples/view/template_pug_1/templates/index.pug deleted file mode 100644 index c6b21de2..00000000 --- a/_examples/view/template_pug_1/templates/index.pug +++ /dev/null @@ -1,20 +0,0 @@ -doctype html -html(lang="en") - head - meta(charset="utf-8") - title Title - body - p ads - ul - li The name is {{.Name}}. - li The age is {{.Age}}. - - each _,_ in .Emails - div An email is {{.}} - - | {{ with .Jobs }} - each _,_ in . - div - An employer is {{.Employer}} - and the role is {{.Role}} - | {{ end }} \ No newline at end of file diff --git a/_examples/view/template_pug_2/main.go b/_examples/view/template_pug_2/main.go deleted file mode 100644 index 28186b14..00000000 --- a/_examples/view/template_pug_2/main.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "html/template" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - - tmpl := iris.Pug("./templates", ".pug") - tmpl.Reload(true) // reload templates on each request (development mode) - tmpl.AddFunc("bold", func(s string) (template.HTML, error) { // add your template func here. - return template.HTML("" + s + ""), nil - }) - - app.RegisterView(tmpl) - - app.Get("/", index) - - // http://localhost:8080 - app.Listen(":8080") -} - -func index(ctx iris.Context) { - ctx.View("index.pug") -} diff --git a/_examples/view/template_pug_2/templates/footer.pug b/_examples/view/template_pug_2/templates/footer.pug deleted file mode 100644 index b7f58893..00000000 --- a/_examples/view/template_pug_2/templates/footer.pug +++ /dev/null @@ -1,2 +0,0 @@ -#footer - p Copyright (c) foobar \ No newline at end of file diff --git a/_examples/view/template_pug_2/templates/header.pug b/_examples/view/template_pug_2/templates/header.pug deleted file mode 100644 index a3f081ea..00000000 --- a/_examples/view/template_pug_2/templates/header.pug +++ /dev/null @@ -1,4 +0,0 @@ -head - title My Site - \ No newline at end of file diff --git a/_examples/view/template_pug_2/templates/index.pug b/_examples/view/template_pug_2/templates/index.pug deleted file mode 100644 index ee11d9b4..00000000 --- a/_examples/view/template_pug_2/templates/index.pug +++ /dev/null @@ -1,7 +0,0 @@ -doctype html -html - include header.pug - body - h1 My Site - p {{ bold "Welcome to my super lame site."}} - include footer.pug \ No newline at end of file diff --git a/_examples/view/template_pug_3/bindata.go b/_examples/view/template_pug_3/bindata.go deleted file mode 100644 index fb9d699a..00000000 --- a/_examples/view/template_pug_3/bindata.go +++ /dev/null @@ -1,269 +0,0 @@ -// Code generated for package main by go-bindata DO NOT EDIT. (@generated) -// sources: -// templates/index.pug -// templates/layout.pug -package main - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(data []byte, name string) ([]byte, error) { - gz, err := gzip.NewReader(bytes.NewBuffer(data)) - if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) - } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -// Name return file name -func (fi bindataFileInfo) Name() string { - return fi.name -} - -// Size return file size -func (fi bindataFileInfo) Size() int64 { - return fi.size -} - -// Mode return file mode -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} - -// Mode return file modify time -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} - -// IsDir return file whether a directory -func (fi bindataFileInfo) IsDir() bool { - return fi.mode&os.ModeDir != 0 -} - -// Sys return file is sys mode -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -var _templatesIndexPug = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\xad\x28\x49\xcd\x4b\x29\x56\xc8\x49\xac\xcc\x2f\x2d\xd1\x2b\x28\x4d\xe7\xe5\xe2\xe5\x4a\xca\xc9\x4f\xce\x56\x28\xc9\x2c\xc9\x49\xe5\xe5\x52\x80\x30\x14\x1c\x8b\x4a\x32\x93\x73\x52\x15\x42\x20\xc2\x30\x55\xc9\xf9\x79\x25\xa9\x79\x25\x20\x75\x19\x86\x0a\xbe\x95\x30\x75\x80\x00\x00\x00\xff\xff\xa6\xfd\x18\x8c\x5a\x00\x00\x00") - -func templatesIndexPugBytes() ([]byte, error) { - return bindataRead( - _templatesIndexPug, - "templates/index.pug", - ) -} - -func templatesIndexPug() (*asset, error) { - bytes, err := templatesIndexPugBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "templates/index.pug", size: 90, mode: os.FileMode(438), modTime: time.Unix(1581790962, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _templatesLayoutPug = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4a\xc9\x4f\x2e\xa9\x2c\x48\x55\xc8\x28\xc9\xcd\xe1\xe5\x82\x90\x0a\x0a\x19\xa9\x89\x29\x20\x5a\x41\x21\x29\x27\x3f\x39\x5b\xa1\x24\xb3\x24\x27\x15\x22\xa0\x00\xe1\x28\xb8\xa4\xa6\x25\x96\xe6\x94\x20\xa4\x92\xf2\x53\x2a\x91\xf5\x24\xe7\xe7\x95\xa4\xe6\x95\x00\x02\x00\x00\xff\xff\x5f\xa5\x93\xf9\x61\x00\x00\x00") - -func templatesLayoutPugBytes() ([]byte, error) { - return bindataRead( - _templatesLayoutPug, - "templates/layout.pug", - ) -} - -func templatesLayoutPug() (*asset, error) { - bytes, err := templatesLayoutPugBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "templates/layout.pug", size: 97, mode: os.FileMode(438), modTime: time.Unix(1581790962, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "templates/index.pug": templatesIndexPug, - "templates/layout.pug": templatesLayoutPug, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "templates": {nil, map[string]*bintree{ - "index.pug": {templatesIndexPug, map[string]*bintree{}}, - "layout.pug": {templatesLayoutPug, map[string]*bintree{}}, - }}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} diff --git a/_examples/view/template_pug_3/main.go b/_examples/view/template_pug_3/main.go deleted file mode 100644 index 68b05f42..00000000 --- a/_examples/view/template_pug_3/main.go +++ /dev/null @@ -1,23 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -// $ go get -u github.com/go-bindata/go-bindata/v3/go-bindata -// $ go-bindata ./templates/... -// $ go build -func main() { - app := iris.New() - - tmpl := iris.Pug("./templates", ".pug").Binary(Asset, AssetNames) - - app.RegisterView(tmpl) - - app.Get("/", index) - - // http://localhost:8080 - app.Listen(":8080") -} - -func index(ctx iris.Context) { - ctx.View("index.pug") -} diff --git a/_examples/view/template_pug_3/templates/index.pug b/_examples/view/template_pug_3/templates/index.pug deleted file mode 100644 index f061806c..00000000 --- a/_examples/view/template_pug_3/templates/index.pug +++ /dev/null @@ -1,7 +0,0 @@ -extends layout.pug - -block title - title Article Title - -block content - h1 My Article \ No newline at end of file diff --git a/_examples/view/template_pug_3/templates/layout.pug b/_examples/view/template_pug_3/templates/layout.pug deleted file mode 100644 index ebd199f3..00000000 --- a/_examples/view/template_pug_3/templates/layout.pug +++ /dev/null @@ -1,7 +0,0 @@ -doctype html -html - head - block title - title Default title - body - block content \ No newline at end of file diff --git a/_examples/view/write-to/main.go b/_examples/view/write-to/main.go deleted file mode 100644 index 438c101f..00000000 --- a/_examples/view/write-to/main.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - "os" - - "github.com/kataras/iris/v12" -) - -type mailData struct { - Title string - Body string - RefTitle string - RefLink string -} - -func main() { - app := iris.New() - app.Logger().SetLevel("debug") - app.RegisterView(iris.HTML("./views", ".html")) - - // you need to call `app.Build` manually before using the `app.View` func, - // so templates are built in that state. - app.Build() - - // Or a string-buffered writer to use its body to send an e-mail - // for sending e-mails you can use the https://github.com/kataras/go-mailer - // or any other third-party package you like. - // - // The template's parsed result will be written to that writer. - writer := os.Stdout - err := app.View(writer, "email/simple.html", "shared/email.html", mailData{ - Title: "This is my e-mail title", - Body: "This is my e-mail body", - RefTitle: "Iris web framework", - RefLink: "https://iris-go.com", - }) - if err != nil { - app.Logger().Errorf("error from app.View: %v", err) - } - - app.Listen(":8080") -} diff --git a/_examples/view/write-to/views/email/simple.html b/_examples/view/write-to/views/email/simple.html deleted file mode 100644 index 6e411194..00000000 --- a/_examples/view/write-to/views/email/simple.html +++ /dev/null @@ -1 +0,0 @@ -{{.Body}} \ No newline at end of file diff --git a/_examples/view/write-to/views/shared/email.html b/_examples/view/write-to/views/shared/email.html deleted file mode 100644 index 6d5baceb..00000000 --- a/_examples/view/write-to/views/shared/email.html +++ /dev/null @@ -1,6 +0,0 @@ -

    {{.Title}}

    -

    - {{yield}} -

    - -{{.RefTitle}} diff --git a/_examples/webassembly/client/go-wasm-runtime.js b/_examples/webassembly/client/go-wasm-runtime.js deleted file mode 100644 index ecb09650..00000000 --- a/_examples/webassembly/client/go-wasm-runtime.js +++ /dev/null @@ -1,412 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -(() => { - // Map web browser API and Node.js API to a single common API (preferring web standards over Node.js API). - const isNodeJS = typeof process !== "undefined"; - if (isNodeJS) { - global.require = require; - global.fs = require("fs"); - - const nodeCrypto = require("crypto"); - global.crypto = { - getRandomValues(b) { - nodeCrypto.randomFillSync(b); - }, - }; - - global.performance = { - now() { - const [sec, nsec] = process.hrtime(); - return sec * 1000 + nsec / 1000000; - }, - }; - - const util = require("util"); - global.TextEncoder = util.TextEncoder; - global.TextDecoder = util.TextDecoder; - } else { - window.global = window; - - let outputBuf = ""; - global.fs = { - constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1, O_NONBLOCK: -1, O_SYNC: -1 }, // unused - writeSync(fd, buf) { - outputBuf += decoder.decode(buf); - const nl = outputBuf.lastIndexOf("\n"); - if (nl != -1) { - console.log(outputBuf.substr(0, nl)); - outputBuf = outputBuf.substr(nl + 1); - } - return buf.length; - }, - openSync(path, flags, mode) { - const err = new Error("not implemented"); - err.code = "ENOSYS"; - throw err; - }, - }; - } - - const encoder = new TextEncoder("utf-8"); - const decoder = new TextDecoder("utf-8"); - - global.Go = class { - constructor() { - this.argv = ["js"]; - this.env = {}; - this.exit = (code) => { - if (code !== 0) { - console.warn("exit code:", code); - } - }; - this._callbackTimeouts = new Map(); - this._nextCallbackTimeoutID = 1; - - const mem = () => { - // The buffer may change when requesting more memory. - return new DataView(this._inst.exports.mem.buffer); - } - - const setInt64 = (addr, v) => { - mem().setUint32(addr + 0, v, true); - mem().setUint32(addr + 4, Math.floor(v / 4294967296), true); - } - - const getInt64 = (addr) => { - const low = mem().getUint32(addr + 0, true); - const high = mem().getInt32(addr + 4, true); - return low + high * 4294967296; - } - - const loadValue = (addr) => { - const f = mem().getFloat64(addr, true); - if (!isNaN(f)) { - return f; - } - - const id = mem().getUint32(addr, true); - return this._values[id]; - } - - const storeValue = (addr, v) => { - if (typeof v === "number") { - if (isNaN(v)) { - mem().setUint32(addr + 4, 0x7FF80000, true); // NaN - mem().setUint32(addr, 0, true); - return; - } - mem().setFloat64(addr, v, true); - return; - } - - mem().setUint32(addr + 4, 0x7FF80000, true); // NaN - - switch (v) { - case undefined: - mem().setUint32(addr, 1, true); - return; - case null: - mem().setUint32(addr, 2, true); - return; - case true: - mem().setUint32(addr, 3, true); - return; - case false: - mem().setUint32(addr, 4, true); - return; - } - - if (typeof v === "string") { - let ref = this._stringRefs.get(v); - if (ref === undefined) { - ref = this._values.length; - this._values.push(v); - this._stringRefs.set(v, ref); - } - mem().setUint32(addr, ref, true); - return; - } - - if (typeof v === "symbol") { - let ref = this._symbolRefs.get(v); - if (ref === undefined) { - ref = this._values.length; - this._values.push(v); - this._symbolRefs.set(v, ref); - } - mem().setUint32(addr, ref, true); - return; - } - - let ref = v[this._refProp]; - if (ref === undefined) { - ref = this._values.length; - this._values.push(v); - v[this._refProp] = ref; - } - mem().setUint32(addr, ref, true); - } - - const loadSlice = (addr) => { - const array = getInt64(addr + 0); - const len = getInt64(addr + 8); - return new Uint8Array(this._inst.exports.mem.buffer, array, len); - } - - const loadSliceOfValues = (addr) => { - const array = getInt64(addr + 0); - const len = getInt64(addr + 8); - const a = new Array(len); - for (let i = 0; i < len; i++) { - a[i] = loadValue(array + i * 8); - } - return a; - } - - const loadString = (addr) => { - const saddr = getInt64(addr + 0); - const len = getInt64(addr + 8); - return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len)); - } - - const timeOrigin = Date.now() - performance.now(); - this.importObject = { - go: { - // func wasmExit(code int32) - "runtime.wasmExit": (sp) => { - this.exited = true; - this.exit(mem().getInt32(sp + 8, true)); - }, - - // func wasmWrite(fd uintptr, p unsafe.Pointer, n int32) - "runtime.wasmWrite": (sp) => { - const fd = getInt64(sp + 8); - const p = getInt64(sp + 16); - const n = mem().getInt32(sp + 24, true); - fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n)); - }, - - // func nanotime() int64 - "runtime.nanotime": (sp) => { - setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000); - }, - - // func walltime() (sec int64, nsec int32) - "runtime.walltime": (sp) => { - const msec = (new Date).getTime(); - setInt64(sp + 8, msec / 1000); - mem().setInt32(sp + 16, (msec % 1000) * 1000000, true); - }, - - // func scheduleCallback(delay int64) int32 - "runtime.scheduleCallback": (sp) => { - const id = this._nextCallbackTimeoutID; - this._nextCallbackTimeoutID++; - this._callbackTimeouts.set(id, setTimeout( - () => { this._resolveCallbackPromise(); }, - getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early - )); - mem().setInt32(sp + 16, id, true); - }, - - // func clearScheduledCallback(id int32) - "runtime.clearScheduledCallback": (sp) => { - const id = mem().getInt32(sp + 8, true); - clearTimeout(this._callbackTimeouts.get(id)); - this._callbackTimeouts.delete(id); - }, - - // func getRandomData(r []byte) - "runtime.getRandomData": (sp) => { - crypto.getRandomValues(loadSlice(sp + 8)); - }, - - // func stringVal(value string) ref - "syscall/js.stringVal": (sp) => { - storeValue(sp + 24, loadString(sp + 8)); - }, - - // func valueGet(v ref, p string) ref - "syscall/js.valueGet": (sp) => { - storeValue(sp + 32, Reflect.get(loadValue(sp + 8), loadString(sp + 16))); - }, - - // func valueSet(v ref, p string, x ref) - "syscall/js.valueSet": (sp) => { - Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32)); - }, - - // func valueIndex(v ref, i int) ref - "syscall/js.valueIndex": (sp) => { - storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16))); - }, - - // valueSetIndex(v ref, i int, x ref) - "syscall/js.valueSetIndex": (sp) => { - Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24)); - }, - - // func valueCall(v ref, m string, args []ref) (ref, bool) - "syscall/js.valueCall": (sp) => { - try { - const v = loadValue(sp + 8); - const m = Reflect.get(v, loadString(sp + 16)); - const args = loadSliceOfValues(sp + 32); - storeValue(sp + 56, Reflect.apply(m, v, args)); - mem().setUint8(sp + 64, 1); - } catch (err) { - storeValue(sp + 56, err); - mem().setUint8(sp + 64, 0); - } - }, - - // func valueInvoke(v ref, args []ref) (ref, bool) - "syscall/js.valueInvoke": (sp) => { - try { - const v = loadValue(sp + 8); - const args = loadSliceOfValues(sp + 16); - storeValue(sp + 40, Reflect.apply(v, undefined, args)); - mem().setUint8(sp + 48, 1); - } catch (err) { - storeValue(sp + 40, err); - mem().setUint8(sp + 48, 0); - } - }, - - // func valueNew(v ref, args []ref) (ref, bool) - "syscall/js.valueNew": (sp) => { - try { - const v = loadValue(sp + 8); - const args = loadSliceOfValues(sp + 16); - storeValue(sp + 40, Reflect.construct(v, args)); - mem().setUint8(sp + 48, 1); - } catch (err) { - storeValue(sp + 40, err); - mem().setUint8(sp + 48, 0); - } - }, - - // func valueLength(v ref) int - "syscall/js.valueLength": (sp) => { - setInt64(sp + 16, parseInt(loadValue(sp + 8).length)); - }, - - // valuePrepareString(v ref) (ref, int) - "syscall/js.valuePrepareString": (sp) => { - const str = encoder.encode(String(loadValue(sp + 8))); - storeValue(sp + 16, str); - setInt64(sp + 24, str.length); - }, - - // valueLoadString(v ref, b []byte) - "syscall/js.valueLoadString": (sp) => { - const str = loadValue(sp + 8); - loadSlice(sp + 16).set(str); - }, - - // func valueInstanceOf(v ref, t ref) bool - "syscall/js.valueInstanceOf": (sp) => { - mem().setUint8(sp + 24, loadValue(sp + 8) instanceof loadValue(sp + 16)); - }, - - "debug": (value) => { - console.log(value); - }, - } - }; - } - - async run(instance) { - this._inst = instance; - this._values = [ // TODO: garbage collection - NaN, - undefined, - null, - true, - false, - global, - this._inst.exports.mem, - () => { // resolveCallbackPromise - if (this.exited) { - throw new Error("bad callback: Go program has already exited"); - } - setTimeout(this._resolveCallbackPromise, 0); // make sure it is asynchronous - }, - ]; - this._stringRefs = new Map(); - this._symbolRefs = new Map(); - this._refProp = Symbol(); - this.exited = false; - - const mem = new DataView(this._inst.exports.mem.buffer) - - // Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory. - let offset = 4096; - - const strPtr = (str) => { - let ptr = offset; - new Uint8Array(mem.buffer, offset, str.length + 1).set(encoder.encode(str + "\0")); - offset += str.length + (8 - (str.length % 8)); - return ptr; - }; - - const argc = this.argv.length; - - const argvPtrs = []; - this.argv.forEach((arg) => { - argvPtrs.push(strPtr(arg)); - }); - - const keys = Object.keys(this.env).sort(); - argvPtrs.push(keys.length); - keys.forEach((key) => { - argvPtrs.push(strPtr(`${key}=${this.env[key]}`)); - }); - - const argv = offset; - argvPtrs.forEach((ptr) => { - mem.setUint32(offset, ptr, true); - mem.setUint32(offset + 4, 0, true); - offset += 8; - }); - - while (true) { - const callbackPromise = new Promise((resolve) => { - this._resolveCallbackPromise = resolve; - }); - this._inst.exports.run(argc, argv); - if (this.exited) { - break; - } - await callbackPromise; - } - } - } - - if (isNodeJS) { - if (process.argv.length < 3) { - process.stderr.write("usage: go_js_wasm_exec [wasm binary] [arguments]\n"); - process.exit(1); - } - - const go = new Go(); - go.argv = process.argv.slice(2); - go.env = process.env; - go.exit = process.exit; - WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => { - process.on("exit", () => { // Node.js exits if no callback is pending - if (!go.exited) { - console.error("error: all goroutines asleep and no JavaScript callback pending - deadlock!"); - process.exit(1); - } - }); - return go.run(result.instance); - }).catch((err) => { - console.error(err); - go.exited = true; - process.exit(1); - }); - } -})(); diff --git a/_examples/webassembly/client/hello.html b/_examples/webassembly/client/hello.html deleted file mode 100644 index 29caa55b..00000000 --- a/_examples/webassembly/client/hello.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - Hello Webassembly + Iris (Go) - - -
    - - - \ No newline at end of file diff --git a/_examples/webassembly/client/hello_go114.go b/_examples/webassembly/client/hello_go114.go deleted file mode 100644 index 83e0413f..00000000 --- a/_examples/webassembly/client/hello_go114.go +++ /dev/null @@ -1,16 +0,0 @@ -// +build js - -package main - -import ( - "fmt" - "syscall/js" - "time" -) - -func main() { - // GOARCH=wasm GOOS=js /home/$yourusername/go1.14/bin/go build -o hello.wasm hello_go114.go - js.Global().Get("console").Call("log", "Hello Webassembly!") - message := fmt.Sprintf("Hello, the current time is: %s", time.Now().String()) - js.Global().Get("document").Call("getElementById", "hello").Set("innerText", message) -} diff --git a/_examples/webassembly/client/main.js b/_examples/webassembly/client/main.js deleted file mode 100644 index 02fac56a..00000000 --- a/_examples/webassembly/client/main.js +++ /dev/null @@ -1,13 +0,0 @@ -import './go-wasm-runtime.js'; - -if (!WebAssembly.instantiateStreaming) { // polyfill - WebAssembly.instantiateStreaming = async (resp, importObject) => { - const source = await (await resp).arrayBuffer(); - return await WebAssembly.instantiate(source, importObject); - }; -} - -const go = new Go(); -WebAssembly.instantiateStreaming(fetch("hello.wasm"), go.importObject).then((result) => { - return WebAssembly.instantiate(result.module, go.importObject); -}).then(instance => go.run(instance)); \ No newline at end of file diff --git a/_examples/webassembly/main.go b/_examples/webassembly/main.go deleted file mode 100644 index 6d611da1..00000000 --- a/_examples/webassembly/main.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" -) - -/* -You need to build the hello.wasm first, download the go1.14 and execute the below command: -$ cd client && GOARCH=wasm GOOS=js /home/$yourname/go1.14/bin/go build -o hello.wasm hello_go114.go -*/ - -func main() { - app := iris.New() - - // we could serve your assets like this the sake of the example, - // never include the .go files there in production. - app.HandleDir("/", iris.Dir("./client")) - - app.Get("/", func(ctx iris.Context) { - // ctx.CompressWriter(true) - ctx.ServeFile("./client/hello.html") - }) - - // visit http://localhost:8080 - // you should get an html output like this: - // Hello, the current time is: 2018-07-09 05:54:12.564 +0000 UTC m=+0.003900161 - app.Listen(":8080") -} diff --git a/_examples/websocket/README.md b/_examples/websocket/README.md deleted file mode 100644 index 8c8d9967..00000000 --- a/_examples/websocket/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Websocket - -[WebSocket](https://wikipedia.org/wiki/WebSocket) is a protocol that enables two-way persistent communication channels over TCP connections. It is used for applications such as chat, stock tickers, games, anywhere you want real-time functionality in a web application. - -Iris websocket library is now merged with the [neffos real-time framework](https://github.com/kataras/neffos) and Iris-specific helpers and type aliases live on the [iris/websocket](https://github.com/kataras/iris/tree/master/websocket) subpackage. Learn neffos from its [wiki](https://github.com/kataras/neffos#learning-neffos). - -Helpers and type aliases improves your code speed when writing a websocket module. -For example, instead of importing both `kataras/iris/websocket` - in order to use its `websocket.Handler` - and `github.com/kataras/neffos` - to create a new websocket server `neffos.New` - you can use the `websocket.New` instead, another example is the `neffos.Conn` which can be declared as `websocket.Conn`. - -All neffos and its subpackage's types and package-level functions exist as type aliases on the `kataras/iris/websocket` package too, there are too many of those and there is no need to write each one of those here, some common types: - -- `github.com/kataras/neffos/#Conn` -> `github.com/kataras/iris/websocket/#Conn` -- `github.com/kataras/neffos/gorilla/#DefaultUpgrader` -> `github.com/kataras/iris/websocket/#DefaultGorillaUpgrader` -- `github.com/kataras/neffos/stackexchange/redis/#NewStackExchange` -> `github.com/kataras/iris/websocket/#NewRedisStackExchange` diff --git a/_examples/websocket/basic/README.md b/_examples/websocket/basic/README.md deleted file mode 100644 index 948b18bc..00000000 --- a/_examples/websocket/basic/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# Basic Example - -At the end of this example you will be able to run a websocket server -and clients for all platforms (Go, Browser and Nodejs). - -![](overview.png) - -Open as many clients as you want to try out and start typing. - -This example contains only the basics, however, the library supports rooms, native websocket messages, any data can be sent and received (i.e protobufs, json) and all kinds of broadcasting and connections collections. - -## How to run - -### Server - -Open a terminal window instance and execute: - -```sh -$ go run server.go # start the websocket server. -``` - -### Client (Go) - -Start a new terminal instance and execute: - -```sh -$ cd ./go-client -$ go run client.go # start the websocket client. -# start typing... -``` - -### Client (Browser) - -Navigate to and start typing. -The `./browser/index.html` should be served, it contains the client-side code. - -### Client (Browserify) - -Install [NPM](https://nodejs.org) first, then start a new terminal instance and execute: - -```sh -$ cd ./browserify -$ npm install -# build the modern browser-side client: -# embed the neffos.js node-module and app.js -# into a single ./browserify/bundle.js file -# which ./browserify/client.html imports. -$ npm run-script build -``` - -Navigate to and start typing. - -### Client (Nodejs) - -Install [NPM](https://nodejs.org) if you haven't already and then, start a new terminal instance and execute: - -```sh -$ cd nodejs-client -$ npm install -$ node client.js # start the websocket client. -# start typing. -``` diff --git a/_examples/websocket/basic/browser/index.html b/_examples/websocket/basic/browser/index.html deleted file mode 100644 index 493b7987..00000000 --- a/_examples/websocket/basic/browser/index.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - -
    
    -
    -
    -
    \ No newline at end of file
    diff --git a/_examples/websocket/basic/browserify/app.js b/_examples/websocket/basic/browserify/app.js
    deleted file mode 100644
    index 8acfb9c9..00000000
    --- a/_examples/websocket/basic/browserify/app.js
    +++ /dev/null
    @@ -1,75 +0,0 @@
    -const neffos = require('neffos.js');
    -
    -var scheme = document.location.protocol == "https:" ? "wss" : "ws";
    -var port = document.location.port ? ":" + document.location.port : "";
    -
    -var wsURL = scheme + "://" + document.location.hostname + port + "/echo";
    -
    -const enableJWT = true;
    -if (enableJWT) {
    -  // This is just a signature and a payload of an example content, 
    -  // please replace this with your logic.
    -  //
    -  // Add a random letter in front of the token to make it
    -  // invalid and see that this client is not allowed to dial the websocket server.
    -  const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjozMjEzMjF9.8waEX7-vPKACa-Soi1pQvW3Rl8QY-SUFcHKTLZI4mvU";
    -  wsURL += "?token=" + token;
    -}
    -
    -var outputTxt = document.getElementById("output");
    -
    -function addMessage(msg) {
    -  outputTxt.innerHTML += msg + "\n";
    -}
    -
    -function handleError(reason) {
    -  console.log(reason);
    -  window.alert(reason);
    -}
    -
    -function handleNamespaceConnectedConn(nsConn) {
    -  nsConn.emit("chat", "Hello from browser(ify) client-side!");
    -
    -  const inputTxt = document.getElementById("input");
    -  const sendBtn = document.getElementById("sendBtn");
    -
    -  sendBtn.disabled = false;
    -  sendBtn.onclick = function () {
    -    const input = inputTxt.value;
    -    inputTxt.value = "";
    -
    -    nsConn.emit("chat", input);
    -    addMessage("Me: " + input);
    -  };
    -}
    -
    -async function runExample() {
    -  try {
    -    const conn = await neffos.dial(wsURL, {
    -      default: { // "default" namespace.
    -        _OnNamespaceConnected: function (nsConn, msg) {
    -          addMessage("connected to namespace: " + msg.Namespace);
    -          handleNamespaceConnectedConn(nsConn);
    -        },
    -        _OnNamespaceDisconnect: function (nsConn, msg) {
    -          addMessage("disconnected from namespace: " + msg.Namespace);
    -        },
    -        chat: function (nsConn, msg) { // "chat" event.
    -          addMessage(msg.Body);
    -        }
    -      }
    -    });
    -
    -    // You can either wait to conenct or just conn.connect("connect")
    -    // and put the `handleNamespaceConnectedConn` inside `_OnNamespaceConnected` callback instead.
    -    // const nsConn = await conn.connect("default");
    -    // handleNamespaceConnectedConn(nsConn);
    -    // nsConn.emit(...); handleNamespaceConnectedConn(nsConn);
    -    conn.connect("default");
    -
    -  } catch (err) {
    -    handleError(err);
    -  }
    -}
    -
    -runExample();
    \ No newline at end of file
    diff --git a/_examples/websocket/basic/browserify/bundle.js b/_examples/websocket/basic/browserify/bundle.js
    deleted file mode 100644
    index 9530f82c..00000000
    --- a/_examples/websocket/basic/browserify/bundle.js
    +++ /dev/null
    @@ -1 +0,0 @@
    -(function(){function b(d,e,g){function a(j,i){if(!e[j]){if(!d[j]){var f="function"==typeof require&&require;if(!i&&f)return f(j,!0);if(h)return h(j,!0);var c=new Error("Cannot find module '"+j+"'");throw c.code="MODULE_NOT_FOUND",c}var k=e[j]={exports:{}};d[j][0].call(k.exports,function(b){var c=d[j][1][b];return a(c||b)},k,k.exports,b,d,e,g)}return e[j].exports}for(var h="function"==typeof require&&require,c=0;c=i)return k.close(),null;var c=new Map;k.connectedNamespaces.forEach(function(a,b){var d=[];!q(a.rooms)&&0i[0]&&c[1]
    -
    -
    -
    -
    -
    -
    -
    
    -
    -
    diff --git a/_examples/websocket/basic/browserify/package.json b/_examples/websocket/basic/browserify/package.json
    deleted file mode 100644
    index de851367..00000000
    --- a/_examples/websocket/basic/browserify/package.json
    +++ /dev/null
    @@ -1,16 +0,0 @@
    -{
    -    "name": "neffos.js.example.browserify",
    -    "version": "0.0.1",
    -    "scripts": {
    -        "browserify": "browserify ./app.js -o ./bundle.js",
    -        "minifyES6": "minify ./bundle.js --outFile ./bundle.js",
    -        "build": "npm run-script browserify && npm run-script minifyES6"
    -    },
    -    "dependencies": {
    -        "neffos.js": "latest"
    -    },
    -    "devDependencies": {
    -        "browserify": "^16.2.3",
    -        "babel-minify": "^0.5.0"
    -    }
    -}
    diff --git a/_examples/websocket/basic/go-client/client.go b/_examples/websocket/basic/go-client/client.go
    deleted file mode 100644
    index 05464887..00000000
    --- a/_examples/websocket/basic/go-client/client.go
    +++ /dev/null
    @@ -1,85 +0,0 @@
    -package main
    -
    -import (
    -	"bufio"
    -	"bytes"
    -	"context"
    -	"fmt"
    -	"log"
    -	"os"
    -	"time"
    -
    -	"github.com/kataras/iris/v12/websocket"
    -)
    -
    -const (
    -	endpoint              = "ws://localhost:8080/echo"
    -	namespace             = "default"
    -	dialAndConnectTimeout = 5 * time.Second
    -)
    -
    -// this can be shared with the server.go's.
    -// `NSConn.Conn` has the `IsClient() bool` method which can be used to
    -// check if that's is a client or a server-side callback.
    -var clientEvents = websocket.Namespaces{
    -	namespace: websocket.Events{
    -		websocket.OnNamespaceConnected: func(c *websocket.NSConn, msg websocket.Message) error {
    -			log.Printf("connected to namespace: %s", msg.Namespace)
    -			return nil
    -		},
    -		websocket.OnNamespaceDisconnect: func(c *websocket.NSConn, msg websocket.Message) error {
    -			log.Printf("disconnected from namespace: %s", msg.Namespace)
    -			return nil
    -		},
    -		"chat": func(c *websocket.NSConn, msg websocket.Message) error {
    -			log.Printf("%s", string(msg.Body))
    -			return nil
    -		},
    -	},
    -}
    -
    -func main() {
    -	ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(dialAndConnectTimeout))
    -	defer cancel()
    -
    -	// username := "my_username"
    -	// dialer := websocket.GobwasDialer(websocket.GobwasDialerOptions{Header: websocket.GobwasHeader{"X-Username": []string{username}}})
    -	dialer := websocket.DefaultGobwasDialer
    -	client, err := websocket.Dial(ctx, dialer, endpoint, clientEvents)
    -	if err != nil {
    -		panic(err)
    -	}
    -	defer client.Close()
    -
    -	c, err := client.Connect(ctx, namespace)
    -	if err != nil {
    -		panic(err)
    -	}
    -
    -	c.Emit("chat", []byte("Hello from Go client side!"))
    -
    -	fmt.Fprint(os.Stdout, ">> ")
    -	scanner := bufio.NewScanner(os.Stdin)
    -	for {
    -		if !scanner.Scan() {
    -			log.Printf("ERROR: %v", scanner.Err())
    -			return
    -		}
    -
    -		text := scanner.Bytes()
    -
    -		if bytes.Equal(text, []byte("exit")) {
    -			if err := c.Disconnect(nil); err != nil {
    -				log.Printf("reply from server: %v", err)
    -			}
    -			break
    -		}
    -
    -		ok := c.Emit("chat", text)
    -		if !ok {
    -			break
    -		}
    -
    -		fmt.Fprint(os.Stdout, ">> ")
    -	}
    -} // try running this program twice or/and run the server's http://localhost:8080 to check the browser client as well.
    diff --git a/_examples/websocket/basic/go.mod b/_examples/websocket/basic/go.mod
    deleted file mode 100644
    index b126c8a5..00000000
    --- a/_examples/websocket/basic/go.mod
    +++ /dev/null
    @@ -1,5 +0,0 @@
    -module github.com/kataras/iris/_examples/websocket/basic
    -
    -go 1.15
    -
    -require github.com/iris-contrib/middleware/jwt v0.0.0-20200710202437-92b01b85baaf
    \ No newline at end of file
    diff --git a/_examples/websocket/basic/nodejs-client/client.js b/_examples/websocket/basic/nodejs-client/client.js
    deleted file mode 100644
    index fd4612ef..00000000
    --- a/_examples/websocket/basic/nodejs-client/client.js
    +++ /dev/null
    @@ -1,35 +0,0 @@
    -const neffos = require('neffos.js');
    -const stdin = process.openStdin();
    -
    -const wsURL = "ws://localhost:8080/echo";
    -
    -async function runExample() {
    -  try {
    -    const conn = await neffos.dial(wsURL, {
    -      default: { // "default" namespace.
    -        _OnNamespaceConnected: function (nsConn, msg) {
    -          console.log("connected to namespace: " + msg.Namespace);
    -        },
    -        _OnNamespaceDisconnect: function (nsConn, msg) {
    -          console.log("disconnected from namespace: " + msg.Namespace);
    -        },
    -        chat: function (nsConn, msg) { // "chat" event.
    -          console.log(msg.Body);
    -        }
    -      }
    -    });
    -
    -    const nsConn = await conn.connect("default");
    -    nsConn.emit("chat", "Hello from Nodejs client side!");
    -
    -    stdin.addListener("data", function (data) {
    -      const text = data.toString().trim();
    -      nsConn.emit("chat", text);
    -    });
    -
    -  } catch (err) {
    -    console.error(err);
    -  }
    -}
    -
    -runExample();
    diff --git a/_examples/websocket/basic/nodejs-client/package.json b/_examples/websocket/basic/nodejs-client/package.json
    deleted file mode 100644
    index 58540d07..00000000
    --- a/_examples/websocket/basic/nodejs-client/package.json
    +++ /dev/null
    @@ -1,8 +0,0 @@
    -{
    -    "name": "neffos.js.example.nodejsclient",
    -    "version": "0.0.1",
    -    "main": "client.js",
    -    "dependencies": {
    -        "neffos.js": "latest"
    -    }
    -}
    diff --git a/_examples/websocket/basic/overview.png b/_examples/websocket/basic/overview.png
    deleted file mode 100644
    index 69afa9d3efc57f2a839bb5f081450d2b9e4d08d4..0000000000000000000000000000000000000000
    GIT binary patch
    literal 0
    HcmV?d00001
    
    literal 206747
    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 NSConn.String() returns -> Conn.String() returns -> Conn.ID()
    -			log.Printf("[%s] sent: %s", nsConn, string(msg.Body))
    -
    -			// Write message back to the client message owner with:
    -			// nsConn.Emit("chat", msg)
    -			// Write message to all except this client with:
    -			nsConn.Conn.Server().Broadcast(nsConn, msg)
    -			return nil
    -		},
    -	},
    -}
    -
    -func main() {
    -	app := iris.New()
    -	websocketServer := websocket.New(
    -		websocket.DefaultGorillaUpgrader, /* DefaultGobwasUpgrader can be used too. */
    -		serverEvents)
    -
    -	j := jwt.New(jwt.Config{
    -		// Extract by the "token" url,
    -		// so the client should dial with ws://localhost:8080/echo?token=$token
    -		Extractor: jwt.FromParameter("token"),
    -
    -		ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
    -			return []byte("My Secret"), nil
    -		},
    -
    -		// When set, the middleware verifies that tokens are signed
    -		// with the specific signing algorithm
    -		// If the signing method is not constant the
    -		// `Config.ValidationKeyGetter` callback field can be used
    -		// to implement additional checks
    -		// Important to avoid security issues described here:
    -		// https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
    -		SigningMethod: jwt.SigningMethodHS256,
    -	})
    -
    -	idGen := func(ctx iris.Context) string {
    -		if username := ctx.GetHeader("X-Username"); username != "" {
    -			return username
    -		}
    -
    -		return websocket.DefaultIDGenerator(ctx)
    -	}
    -
    -	// serves the endpoint of ws://localhost:8080/echo
    -	// with optional custom ID generator.
    -	websocketRoute := app.Get("/echo", websocket.Handler(websocketServer, idGen))
    -
    -	if enableJWT {
    -		// Register the jwt middleware (on handshake):
    -		websocketRoute.Use(j.Serve)
    -		// OR
    -		//
    -		// Check for token through the jwt middleware
    -		// on websocket connection or on any event:
    -		/* websocketServer.OnConnect = func(c *websocket.Conn) error {
    -		ctx := websocket.GetContext(c)
    -		if err := j.CheckJWT(ctx); err != nil {
    -			// will send the above error on the client
    -			// and will not allow it to connect to the websocket server at all.
    -			return err
    -		}
    -
    -		user := ctx.Values().Get("jwt").(*jwt.Token)
    -		// or just: user := j.Get(ctx)
    -
    -		log.Printf("This is an authenticated request\n")
    -		log.Printf("Claim content:")
    -		log.Printf("%#+v\n", user.Claims)
    -
    -		log.Printf("[%s] connected to the server", c.ID())
    -
    -		return nil
    -		} */
    -	}
    -
    -	// serves the browser-based websocket client.
    -	app.Get("/", func(ctx iris.Context) {
    -		ctx.ServeFile("./browser/index.html")
    -	})
    -
    -	// serves the npm browser websocket client usage example.
    -	app.HandleDir("/browserify", iris.Dir("./browserify"))
    -
    -	app.Listen(":8080")
    -}
    diff --git a/_examples/websocket/gorilla-filewatch/go.mod b/_examples/websocket/gorilla-filewatch/go.mod
    deleted file mode 100644
    index 57c2ff69..00000000
    --- a/_examples/websocket/gorilla-filewatch/go.mod
    +++ /dev/null
    @@ -1,10 +0,0 @@
    -module gorilla-filewatch-example
    -
    -go 1.15
    -
    -require (
    -	github.com/gorilla/websocket v1.4.2
    -	github.com/kataras/iris/v12 v12.1.8
    -)
    -
    -replace github.com/kataras/iris/v12 => ../../../
    diff --git a/_examples/websocket/gorilla-filewatch/main.go b/_examples/websocket/gorilla-filewatch/main.go
    deleted file mode 100644
    index e740c707..00000000
    --- a/_examples/websocket/gorilla-filewatch/main.go
    +++ /dev/null
    @@ -1,168 +0,0 @@
    -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
    -// Use of this source code is governed by a BSD-style
    -// license that can be found in the LICENSE file.
    -//
    -// This example shows a use case with gorilla webscokets package
    -// sends a file to the browser client for display whenever the file is modified.
    -//
    -// $ go run main.go 
    -// # Open http://localhost:8080/ .
    -// # Modify the file to see it update in the browser.
    -package main
    -
    -import (
    -	"flag"
    -	"io/ioutil"
    -	"log"
    -	"os"
    -	"strconv"
    -	"time"
    -
    -	"github.com/gorilla/websocket"
    -	"github.com/kataras/iris/v12"
    -)
    -
    -const (
    -	// Time allowed to write the file to the client.
    -	writeWait = 10 * time.Second
    -
    -	// Time allowed to read the next pong message from the client.
    -	pongWait = 60 * time.Second
    -
    -	// Send pings to client with this period. Must be less than pongWait.
    -	pingPeriod = (pongWait * 9) / 10
    -
    -	// Poll file for changes with this period.
    -	filePeriod = 10 * time.Second
    -)
    -
    -var (
    -	addr     = flag.String("addr", ":8080", "http service address")
    -	filename string
    -	upgrader = websocket.Upgrader{
    -		ReadBufferSize:  1024,
    -		WriteBufferSize: 1024,
    -	}
    -)
    -
    -func readFileIfModified(lastMod time.Time) ([]byte, time.Time, error) {
    -	fi, err := os.Stat(filename)
    -	if err != nil {
    -		return nil, lastMod, err
    -	}
    -	if !fi.ModTime().After(lastMod) {
    -		return nil, lastMod, nil
    -	}
    -	p, err := ioutil.ReadFile(filename)
    -	if err != nil {
    -		return nil, fi.ModTime(), err
    -	}
    -	return p, fi.ModTime(), nil
    -}
    -
    -func reader(ws *websocket.Conn) {
    -	defer ws.Close()
    -	ws.SetReadLimit(512)
    -	ws.SetReadDeadline(time.Now().Add(pongWait))
    -	ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
    -	for {
    -		_, _, err := ws.ReadMessage()
    -		if err != nil {
    -			break
    -		}
    -	}
    -}
    -
    -func writer(ws *websocket.Conn, lastMod time.Time) {
    -	lastError := ""
    -	pingTicker := time.NewTicker(pingPeriod)
    -	fileTicker := time.NewTicker(filePeriod)
    -	defer func() {
    -		pingTicker.Stop()
    -		fileTicker.Stop()
    -		ws.Close()
    -	}()
    -	for {
    -		select {
    -		case <-fileTicker.C:
    -			var p []byte
    -			var err error
    -
    -			p, lastMod, err = readFileIfModified(lastMod)
    -
    -			if err != nil {
    -				if s := err.Error(); s != lastError {
    -					lastError = s
    -					p = []byte(lastError)
    -				}
    -			} else {
    -				lastError = ""
    -			}
    -
    -			if p != nil {
    -				ws.SetWriteDeadline(time.Now().Add(writeWait))
    -				if err := ws.WriteMessage(websocket.TextMessage, p); err != nil {
    -					return
    -				}
    -			}
    -		case <-pingTicker.C:
    -			ws.SetWriteDeadline(time.Now().Add(writeWait))
    -			if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
    -				return
    -			}
    -		}
    -	}
    -}
    -
    -func serveWs(ctx iris.Context) {
    -	ws, err := upgrader.Upgrade(ctx.ResponseWriter(), ctx.Request(), nil)
    -	if err != nil {
    -		if _, ok := err.(websocket.HandshakeError); !ok {
    -			log.Println(err)
    -		}
    -		return
    -	}
    -
    -	var lastMod time.Time
    -	if n, err := strconv.ParseInt(ctx.FormValue("lastMod"), 16, 64); err == nil {
    -		lastMod = time.Unix(0, n)
    -	}
    -
    -	go writer(ws, lastMod)
    -	reader(ws)
    -}
    -
    -func serveHome(ctx iris.Context) {
    -	p, lastMod, err := readFileIfModified(time.Time{})
    -	if err != nil {
    -		p = []byte(err.Error())
    -		lastMod = time.Unix(0, 0)
    -	}
    -	var v = struct {
    -		Host    string
    -		Data    string
    -		LastMod string
    -	}{
    -		ctx.Host(),
    -		string(p),
    -		strconv.FormatInt(lastMod.UnixNano(), 16),
    -	}
    -	ctx.View("home.html", v)
    -}
    -
    -// $ go get github.com/gorilla/websocket
    -// $ go run main.go testfile.txt
    -func main() {
    -	flag.Parse()
    -	if flag.NArg() != 1 {
    -		log.Fatal("filename not specified")
    -	}
    -	filename = flag.Args()[0]
    -
    -	app := iris.New()
    -	app.RegisterView(iris.HTML("./views", ".html"))
    -	app.Get("/", serveHome)
    -	app.Any("/ws", serveWs)
    -
    -	app.Listen(*addr)
    -}
    diff --git a/_examples/websocket/gorilla-filewatch/testfile.txt b/_examples/websocket/gorilla-filewatch/testfile.txt
    deleted file mode 100644
    index 21b4fc73..00000000
    --- a/_examples/websocket/gorilla-filewatch/testfile.txt
    +++ /dev/null
    @@ -1,4 +0,0 @@
    -Some Contents
    -# you can edit this file locally
    -# and http://localhost:8080
    -# will render the new contents through the live websocket connection.
    \ No newline at end of file
    diff --git a/_examples/websocket/gorilla-filewatch/views/home.html b/_examples/websocket/gorilla-filewatch/views/home.html
    deleted file mode 100644
    index e8e1d1d9..00000000
    --- a/_examples/websocket/gorilla-filewatch/views/home.html
    +++ /dev/null
    @@ -1,22 +0,0 @@
    -
    -
    -    
    -        WebSocket Example
    -    
    -    
    -        
    {{.Data}}
    - - - \ No newline at end of file diff --git a/_examples/websocket/native-messages/main.go b/_examples/websocket/native-messages/main.go deleted file mode 100644 index 19660642..00000000 --- a/_examples/websocket/native-messages/main.go +++ /dev/null @@ -1,59 +0,0 @@ -package main - -import ( - "log" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/websocket" -) - -type clientPage struct { - Title string - Host string -} - -func main() { - app := iris.New() - - app.RegisterView(iris.HTML("./templates", ".html")) // select the html engine to serve templates - - // Almost all features of neffos are disabled because no custom message can pass - // when app expects to accept and send only raw websocket native messages. - // When only allow native messages is a fact? - // When the registered namespace is just one and it's empty - // and contains only one registered event which is the `OnNativeMessage`. - // When `Events{...}` is used instead of `Namespaces{ "namespaceName": Events{...}}` - // then the namespace is empty "". - ws := websocket.New(websocket.DefaultGorillaUpgrader, websocket.Events{ - websocket.OnNativeMessage: func(nsConn *websocket.NSConn, msg websocket.Message) error { - log.Printf("Server got: %s from [%s]", msg.Body, nsConn.Conn.ID()) - - nsConn.Conn.Server().Broadcast(nsConn, msg) - return nil - }, - }) - - ws.OnConnect = func(c *websocket.Conn) error { - log.Printf("[%s] Connected to server!", c.ID()) - return nil - } - - ws.OnDisconnect = func(c *websocket.Conn) { - log.Printf("[%s] Disconnected from server", c.ID()) - } - - app.HandleDir("/js", iris.Dir("./static/js")) // serve our custom javascript code. - - // register the server on an endpoint. - // see the inline javascript code i the websockets.html, this endpoint is used to connect to the server. - app.Get("/my_endpoint", websocket.Handler(ws)) - - app.Get("/", func(ctx iris.Context) { - ctx.View("client.html", clientPage{"Client Page", "localhost:8080"}) - }) - - // Target some browser windows/tabs to http://localhost:8080 and send some messages, - // see the static/js/chat.js, - // note that the client is using only the browser's native WebSocket API instead of the neffos one. - app.Listen(":8080") -} diff --git a/_examples/websocket/native-messages/static/js/chat.js b/_examples/websocket/native-messages/static/js/chat.js deleted file mode 100644 index 2fe0f779..00000000 --- a/_examples/websocket/native-messages/static/js/chat.js +++ /dev/null @@ -1,35 +0,0 @@ -var messageTxt = document.getElementById("messageTxt"); -var messages = document.getElementById("messages"); -var sendBtn = document.getElementById("sendBtn") - -w = new WebSocket("ws://" + HOST + "/my_endpoint"); -w.onopen = function () { - console.log("Websocket connection enstablished"); -}; - -w.onclose = function () { - appendMessage("

    Disconnected

    "); -}; -w.onmessage = function (message) { - appendMessage("
    " + message.data + "
    "); -}; - -sendBtn.onclick = function () { - myText = messageTxt.value; - messageTxt.value = ""; - - appendMessage("
    me: " + myText + "
    "); - w.send(myText); -}; - -messageTxt.addEventListener("keyup", function (e) { - if (e.keyCode === 13) { - e.preventDefault(); - - sendBtn.click(); - } -}); - -function appendMessage(messageDivHTML) { - messages.insertAdjacentHTML('afterbegin', messageDivHTML); -} diff --git a/_examples/websocket/native-messages/templates/client.html b/_examples/websocket/native-messages/templates/client.html deleted file mode 100644 index 2d8187a2..00000000 --- a/_examples/websocket/native-messages/templates/client.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - {{ .Title}} - - - - - -
    -
    - - - - - - \ No newline at end of file diff --git a/_examples/websocket/online-visitors/main.go b/_examples/websocket/online-visitors/main.go deleted file mode 100644 index 5df905b4..00000000 --- a/_examples/websocket/online-visitors/main.go +++ /dev/null @@ -1,173 +0,0 @@ -package main - -import ( - "fmt" - "sync/atomic" - - "github.com/kataras/iris/v12" - - "github.com/kataras/iris/v12/websocket" -) - -var events = websocket.Namespaces{ - "default": websocket.Events{ - websocket.OnRoomJoined: onRoomJoined, - websocket.OnRoomLeft: onRoomLeft, - }, -} - -func main() { - // init the web application instance - // app := iris.New() - app := iris.Default() - - // load templates - app.RegisterView(iris.HTML("./templates", ".html").Reload(true)) - // setup the websocket server - ws := websocket.New(websocket.DefaultGorillaUpgrader, events) - - app.Get("/my_endpoint", websocket.Handler(ws)) - - // register static assets request path and system directory - app.HandleDir("/js", iris.Dir("./static/assets/js")) - - h := func(ctx iris.Context) { - ctx.ViewData("", page{PageID: "index page"}) - ctx.View("index.html") - } - - h2 := func(ctx iris.Context) { - ctx.ViewData("", page{PageID: "other page"}) - ctx.View("other.html") - } - - // Open some browser tabs/or windows - // and navigate to - // http://localhost:8080/ and http://localhost:8080/other multiple times. - // Each page has its own online-visitors counter. - app.Get("/", h) - app.Get("/other", h2) - app.Listen(":8080") -} - -type page struct { - PageID string -} - -type pageView struct { - source string - count uint64 -} - -func (v *pageView) increment() { - atomic.AddUint64(&v.count, 1) -} - -func (v *pageView) decrement() { - atomic.AddUint64(&v.count, ^uint64(0)) -} - -func (v *pageView) getCount() uint64 { - return atomic.LoadUint64(&v.count) -} - -type ( - pageViews []pageView -) - -func (v *pageViews) Add(source string) { - args := *v - n := len(args) - for i := 0; i < n; i++ { - kv := &args[i] - if kv.source == source { - kv.increment() - return - } - } - - c := cap(args) - if c > n { - args = args[:n+1] - kv := &args[n] - kv.source = source - kv.count = 1 - *v = args - return - } - - kv := pageView{} - kv.source = source - kv.count = 1 - *v = append(args, kv) -} - -func (v *pageViews) Get(source string) *pageView { - args := *v - n := len(args) - for i := 0; i < n; i++ { - kv := &args[i] - if kv.source == source { - return kv - } - } - return nil -} - -func (v *pageViews) Reset() { - *v = (*v)[:0] -} - -var v pageViews - -func viewsCountBytes(viewsCount uint64) []byte { - // * there are other methods to convert uint64 to []byte - return []byte(fmt.Sprintf("%d", viewsCount)) -} - -func onRoomJoined(ns *websocket.NSConn, msg websocket.Message) error { - // the roomName here is the source. - pageSource := string(msg.Room) - - v.Add(pageSource) - - viewsCount := v.Get(pageSource).getCount() - if viewsCount == 0 { - viewsCount++ // count should be always > 0 here - } - - // fire the "onNewVisit" client event - // on each connection joined to this room (source page) - // and notify of the new visit, - // including this connection (see nil on first input arg). - ns.Conn.Server().Broadcast(nil, websocket.Message{ - Namespace: msg.Namespace, - Room: pageSource, - Event: "onNewVisit", // fire the "onNewVisit" client event. - Body: viewsCountBytes(viewsCount), - }) - - return nil -} - -func onRoomLeft(ns *websocket.NSConn, msg websocket.Message) error { - // the roomName here is the source. - pageV := v.Get(msg.Room) - if pageV == nil { - return nil // for any case that this room is not a pageView source - } - // decrement -1 the specific counter for this page source. - pageV.decrement() - - // fire the "onNewVisit" client event - // on each connection joined to this room (source page) - // and notify of the new, decremented by one, visits count. - ns.Conn.Server().Broadcast(nil, websocket.Message{ - Namespace: msg.Namespace, - Room: msg.Room, - Event: "onNewVisit", - Body: viewsCountBytes(pageV.getCount()), - }) - - return nil -} diff --git a/_examples/websocket/online-visitors/static/assets/js/visitors.js b/_examples/websocket/online-visitors/static/assets/js/visitors.js deleted file mode 100644 index 0e74bc29..00000000 --- a/_examples/websocket/online-visitors/static/assets/js/visitors.js +++ /dev/null @@ -1,24 +0,0 @@ -(function () { - var events = { - default: { - _OnNamespaceConnected: function (ns, msg) { - ns.joinRoom(PAGE_SOURCE); - }, - _OnNamespaceDisconnect: function (ns, msg) { - document.getElementById("online_views").innerHTML = "you've been disconnected"; - }, - onNewVisit: function (ns, msg) { - var text = "1 online view"; - var onlineViews = Number(msg.Body); - if (onlineViews > 1) { - text = onlineViews + " online views"; - } - document.getElementById("online_views").innerHTML = text; - } - } - }; - - neffos.dial("ws://localhost:8080/my_endpoint", events).then(function (client) { - client.connect("default"); - }); -})(); diff --git a/_examples/websocket/online-visitors/templates/index.html b/_examples/websocket/online-visitors/templates/index.html deleted file mode 100644 index 02dd3a92..00000000 --- a/_examples/websocket/online-visitors/templates/index.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - Online visitors example - - - - -
    - 1 online view -
    - - - - - - - - - - \ No newline at end of file diff --git a/_examples/websocket/online-visitors/templates/other.html b/_examples/websocket/online-visitors/templates/other.html deleted file mode 100644 index 11b10d00..00000000 --- a/_examples/websocket/online-visitors/templates/other.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - Different page, different results - - - - - - 1 online view - - - - - - - - - - - \ No newline at end of file diff --git a/_examples/websocket/secure/README.md b/_examples/websocket/secure/README.md deleted file mode 100644 index 9b99bafd..00000000 --- a/_examples/websocket/secure/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Secure Websockets - -1. Run your server through `https://` (`iris.Run(iris.TLS)` or `iris.Run(iris.AutoTLS)` or a custom `iris.Listener(...)`) -2. Nothing changes inside the whole app, including the websocket side -3. The clients must dial the websocket server endpoint (i.e `/echo`) via `wss://` prefix (instead of the non-secure `ws://`), for example `wss://example.com/echo` -4. Ready to GO. diff --git a/_examples/websocket/socketio/asset/index.html b/_examples/websocket/socketio/asset/index.html deleted file mode 100644 index 6c839ab8..00000000 --- a/_examples/websocket/socketio/asset/index.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - - Socket.IO chat - - - - -
      -
      - -
      - - - - - - \ No newline at end of file diff --git a/_examples/websocket/socketio/go.mod b/_examples/websocket/socketio/go.mod deleted file mode 100644 index 61b7561a..00000000 --- a/_examples/websocket/socketio/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/kataras/iris/_examples/websocket/socketio - -go 1.15 - -require ( - github.com/googollee/go-socket.io v1.4.3-0.20191109153049-7451e2f8c2e0 - github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd -) diff --git a/_examples/websocket/socketio/main.go b/_examples/websocket/socketio/main.go deleted file mode 100644 index 9eefe0b3..00000000 --- a/_examples/websocket/socketio/main.go +++ /dev/null @@ -1,57 +0,0 @@ -// Package main runs a go-socket.io based websocket server. -// An Iris compatible clone of: https://github.com/googollee/go-socket.io#example, -// use of `iris.FromStd` to convert its handler. -package main - -import ( - "fmt" - "log" - - socketio "github.com/googollee/go-socket.io" - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - server, err := socketio.NewServer(nil) - if err != nil { - log.Fatal(err) - } - server.OnConnect("/", func(s socketio.Conn) error { - s.SetContext("") - fmt.Println("connected:", s.ID()) - return nil - }) - server.OnEvent("/", "notice", func(s socketio.Conn, msg string) { - fmt.Println("notice:", msg) - s.Emit("reply", "have "+msg) - }) - server.OnEvent("/chat", "msg", func(s socketio.Conn, msg string) string { - s.SetContext(msg) - return "recv " + msg - }) - server.OnEvent("/", "bye", func(s socketio.Conn) string { - last := s.Context().(string) - s.Emit("bye", last) - s.Close() - return last - }) - server.OnError("/", func(s socketio.Conn, e error) { - fmt.Println("meet error:", e) - }) - server.OnDisconnect("/", func(s socketio.Conn, reason string) { - fmt.Println("closed", reason) - }) - go server.Serve() - defer server.Close() - - app.HandleMany("GET POST", "/socket.io/{any:path}", iris.FromStd(server)) - app.HandleDir("/", iris.Dir("./asset")) - - app.Listen(":8000", iris.WithoutPathCorrection) -} - -/* -If you want to enable CORS in your websocket handler, -please follow this post: https://github.com/googollee/go-socket.io/issues/242 -*/ diff --git a/aliases.go b/aliases.go index b2109572..09a65f09 100644 --- a/aliases.go +++ b/aliases.go @@ -5,13 +5,13 @@ import ( "path" "regexp" - "github.com/kataras/iris/v12/cache" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/handlerconv" - "github.com/kataras/iris/v12/core/host" - "github.com/kataras/iris/v12/core/router" - "github.com/kataras/iris/v12/hero" - "github.com/kataras/iris/v12/view" + "github.com/kataras/iris/cache" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/handlerconv" + "github.com/kataras/iris/core/host" + "github.com/kataras/iris/core/router" + "github.com/kataras/iris/hero" + "github.com/kataras/iris/view" ) type ( @@ -354,7 +354,7 @@ var ( // Cache304 sends a `StatusNotModified` (304) whenever // the "If-Modified-Since" request header (time) is before the // time.Now() + expiresEvery (always compared to their UTC values). - // Use this, which is a shortcut of the, `chache#Cache304` instead of the "github.com/kataras/iris/v12/cache" or iris.Cache + // Use this, which is a shortcut of the, `chache#Cache304` instead of the "github.com/kataras/iris/cache" or iris.Cache // for better performance. // Clients that are compatible with the http RCF (all browsers are and tools like postman) // will handle the caching. diff --git a/cache/browser.go b/cache/browser.go index 9462cd5f..ed8c02f9 100644 --- a/cache/browser.go +++ b/cache/browser.go @@ -4,8 +4,8 @@ import ( "strconv" "time" - "github.com/kataras/iris/v12/cache/client" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/cache/client" + "github.com/kataras/iris/context" ) // CacheControlHeaderValue is the header value of the @@ -111,7 +111,7 @@ var ETag = func(ctx *context.Context) { // Cache304 sends a `StatusNotModified` (304) whenever // the "If-Modified-Since" request header (time) is before the // time.Now() + expiresEvery (always compared to their UTC values). -// Use this `cache#Cache304` instead of the "github.com/kataras/iris/v12/cache" or iris.Cache +// Use this `cache#Cache304` instead of the "github.com/kataras/iris/cache" or iris.Cache // for better performance. // Clients that are compatible with the http RCF (all browsers are and tools like postman) // will handle the caching. diff --git a/cache/browser_test.go b/cache/browser_test.go deleted file mode 100644 index 7b0eac2e..00000000 --- a/cache/browser_test.go +++ /dev/null @@ -1,102 +0,0 @@ -package cache_test - -import ( - "strconv" - "testing" - "time" - - "github.com/kataras/iris/v12/cache" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/httptest" -) - -func TestNoCache(t *testing.T) { - app := iris.New() - app.Get("/", cache.NoCache, func(ctx iris.Context) { - ctx.WriteString("no_cache") - }) - - // tests - e := httptest.New(t, app) - - r := e.GET("/").Expect().Status(httptest.StatusOK) - r.Body().Equal("no_cache") - r.Header(context.CacheControlHeaderKey).Equal(cache.CacheControlHeaderValue) - r.Header(cache.PragmaHeaderKey).Equal(cache.PragmaNoCacheHeaderValue) - r.Header(cache.ExpiresHeaderKey).Equal(cache.ExpiresNeverHeaderValue) -} - -func TestStaticCache(t *testing.T) { - // test change the time format, which is not recommended but can be done. - app := iris.New().Configure(iris.WithTimeFormat("02 Jan 2006 15:04:05 GMT")) - - cacheDur := 30 * (24 * time.Hour) - var expectedTime time.Time - app.Get("/", cache.StaticCache(cacheDur), func(ctx iris.Context) { - expectedTime = time.Now() - ctx.WriteString("static_cache") - }) - - // tests - e := httptest.New(t, app) - r := e.GET("/").Expect().Status(httptest.StatusOK) - r.Body().Equal("static_cache") - - r.Header(cache.ExpiresHeaderKey).Equal(expectedTime.Add(cacheDur).Format(app.ConfigurationReadOnly().GetTimeFormat())) - cacheControlHeaderValue := "public, max-age=" + strconv.Itoa(int(cacheDur.Seconds())) - r.Header(context.CacheControlHeaderKey).Equal(cacheControlHeaderValue) -} - -func TestCache304(t *testing.T) { - // t.Parallel() - app := iris.New() - - expiresEvery := 4 * time.Second - app.Get("/", cache.Cache304(expiresEvery), func(ctx iris.Context) { - ctx.WriteString("send") - }) - // handlers - e := httptest.New(t, app) - - // when 304, content type, content length and if ETagg is there are removed from the headers. - insideCacheTimef := time.Now().Add(-expiresEvery).UTC().Format(app.ConfigurationReadOnly().GetTimeFormat()) - r := e.GET("/").WithHeader(context.IfModifiedSinceHeaderKey, insideCacheTimef).Expect().Status(httptest.StatusNotModified) - r.Headers().NotContainsKey(context.ContentTypeHeaderKey).NotContainsKey(context.ContentLengthHeaderKey).NotContainsKey("ETag") - r.Body().Equal("") - - // continue to the handler itself. - cacheInvalidatedTimef := time.Now().Add(expiresEvery).UTC().Format(app.ConfigurationReadOnly().GetTimeFormat()) // after ~5seconds. - r = e.GET("/").WithHeader(context.LastModifiedHeaderKey, cacheInvalidatedTimef).Expect().Status(httptest.StatusOK) - r.Body().Equal("send") - // now without header, it should continue to the handler itself as well. - r = e.GET("/").Expect().Status(httptest.StatusOK) - r.Body().Equal("send") -} - -func TestETag(t *testing.T) { - // t.Parallel() - - app := iris.New() - n := "_" - app.Get("/", cache.ETag, func(ctx iris.Context) { - ctx.WriteString(n) - n += "_" - }) - - // the first and last test writes the content with status OK without cache, - // the rest tests the cache headers and status 304 and return, so body should be "". - e := httptest.New(t, app) - - r := e.GET("/").Expect().Status(httptest.StatusOK) - r.Header("ETag").Equal("/") // test if header set. - r.Body().Equal("_") - - e.GET("/").WithHeader("ETag", "/").WithHeader("If-None-Match", "/").Expect(). - Status(httptest.StatusNotModified).Body().Equal("") // browser is responsible, no the test engine. - - r = e.GET("/").Expect().Status(httptest.StatusOK) - r.Header("ETag").Equal("/") // test if header set. - r.Body().Equal("__") -} diff --git a/cache/cache.go b/cache/cache.go index 9babe5c1..b02d8238 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -9,8 +9,8 @@ Example code: import ( "time" - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/cache" + "github.com/kataras/iris" + "github.com/kataras/iris/cache" ) func main(){ @@ -30,8 +30,8 @@ package cache import ( "time" - "github.com/kataras/iris/v12/cache/client" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/cache/client" + "github.com/kataras/iris/context" ) // Cache accepts the cache expiration duration. diff --git a/cache/cache_test.go b/cache/cache_test.go deleted file mode 100644 index f80f15b3..00000000 --- a/cache/cache_test.go +++ /dev/null @@ -1,215 +0,0 @@ -package cache_test - -import ( - "fmt" - "net/http" - "sync/atomic" - "testing" - "time" - - "github.com/kataras/iris/v12/cache" - "github.com/kataras/iris/v12/cache/client" - "github.com/kataras/iris/v12/cache/client/rule" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - - "github.com/iris-contrib/httpexpect/v2" - "github.com/kataras/iris/v12/httptest" -) - -var ( - cacheDuration = 2 * time.Second - expectedBodyStr = "Imagine it as a big message to achieve x20 response performance!" -) - -type testError struct { - expected int - got uint32 -} - -func (h *testError) Error() string { - return fmt.Sprintf("expected the main handler to be executed %d times instead of %d", h.expected, h.got) -} - -func runTest(e *httpexpect.Expect, path string, counterPtr *uint32, expectedBodyStr string, nocache string) error { - e.GET(path).Expect().Status(http.StatusOK).Body().Equal(expectedBodyStr) - time.Sleep(cacheDuration / 5) // lets wait for a while, cache should be saved and ready - e.GET(path).Expect().Status(http.StatusOK).Body().Equal(expectedBodyStr) - counter := atomic.LoadUint32(counterPtr) - if counter > 1 { - // n should be 1 because it doesn't changed after the first call - return &testError{1, counter} - } - time.Sleep(cacheDuration) - - // cache should be cleared now - e.GET(path).Expect().Status(http.StatusOK).Body().Equal(expectedBodyStr) - time.Sleep(cacheDuration / 5) - // let's call again , the cache should be saved - e.GET(path).Expect().Status(http.StatusOK).Body().Equal(expectedBodyStr) - counter = atomic.LoadUint32(counterPtr) - if counter != 2 { - return &testError{2, counter} - } - - // we have cache response saved for the path, we have some time more here, but here - // we will make the requestS with some of the deniers options - e.GET(path).WithHeader("max-age", "0").Expect().Status(http.StatusOK).Body().Equal(expectedBodyStr) - e.GET(path).WithHeader("Authorization", "basic or anything").Expect().Status(http.StatusOK).Body().Equal(expectedBodyStr) - counter = atomic.LoadUint32(counterPtr) - if counter != 4 { - return &testError{4, counter} - } - - if nocache != "" { - // test the NoCache, first sleep to pass the cache expiration, - // second add to the cache with a valid request and response - // third, do it with the "/nocache" path (static for now, pure test design) given by the consumer - time.Sleep(cacheDuration) - - // cache should be cleared now, this should work because we are not in the "nocache" path - e.GET("/").Expect().Status(http.StatusOK).Body().Equal(expectedBodyStr) // counter = 5 - time.Sleep(cacheDuration / 5) - - // let's call the "nocache", the expiration is not passed so but the "nocache" - // route's path has the cache.NoCache so it should be not cached and the counter should be ++ - e.GET(nocache).Expect().Status(http.StatusOK).Body().Equal(expectedBodyStr) // counter should be 6 - counter = atomic.LoadUint32(counterPtr) - if counter != 6 { // 4 before, 5 with the first call to store the cache, and six with the no cache, again original handler executation - return &testError{6, counter} - } - - // let's call again the path the expiration is not passed so it should be cached - e.GET(path).Expect().Status(http.StatusOK).Body().Equal(expectedBodyStr) - counter = atomic.LoadUint32(counterPtr) - if counter != 6 { - return &testError{6, counter} - } - - // but now check for the No - } - - return nil -} - -func TestClientNoCache(t *testing.T) { - app := iris.New() - var n uint32 - - app.Get("/", cache.Handler(cacheDuration), func(ctx *context.Context) { - atomic.AddUint32(&n, 1) - ctx.Write([]byte(expectedBodyStr)) - }) - - app.Get("/nocache", cache.Handler(cacheDuration), func(ctx *context.Context) { - client.NoCache(ctx) // <---- - atomic.AddUint32(&n, 1) - ctx.Write([]byte(expectedBodyStr)) - }) - - e := httptest.New(t, app) - if err := runTest(e, "/", &n, expectedBodyStr, "/nocache"); err != nil { - t.Fatalf(t.Name()+": %v", err) - } -} - -func TestCache(t *testing.T) { - app := iris.New() - var n uint32 - - app.Use(cache.Handler(cacheDuration)) - - app.Get("/", func(ctx *context.Context) { - atomic.AddUint32(&n, 1) - ctx.Write([]byte(expectedBodyStr)) - }) - - var ( - n2 uint32 - expectedBodyStr2 = "This is the other" - ) - - app.Get("/other", func(ctx *context.Context) { - atomic.AddUint32(&n2, 1) - ctx.Write([]byte(expectedBodyStr2)) - }) - - e := httptest.New(t, app) - if err := runTest(e, "/", &n, expectedBodyStr, ""); err != nil { - t.Fatalf(t.Name()+": %v", err) - } - - if err := runTest(e, "/other", &n2, expectedBodyStr2, ""); err != nil { - t.Fatalf(t.Name()+" other: %v", err) - } -} - -// This works but we have issue on golog.SetLevel and get golog.Level on httptest.New -// when tests are running in parallel and the loggers are used. -// // TODO: Fix it on golog repository or here, we'll see. -// func TestCacheHandlerParallel(t *testing.T) { -// t.Parallel() -// TestCache(t) -// } - -func TestCacheValidator(t *testing.T) { - app := iris.New() - var n uint32 - - h := func(ctx *context.Context) { - atomic.AddUint32(&n, 1) - ctx.Write([]byte(expectedBodyStr)) - } - - validCache := cache.Cache(cacheDuration) - app.Get("/", validCache.ServeHTTP, h) - - managedCache := cache.Cache(cacheDuration) - managedCache.AddRule(rule.Validator([]rule.PreValidator{ - func(ctx *context.Context) bool { - // should always invalid for cache, don't bother to go to try to get or set cache - return ctx.Request().URL.Path != "/invalid" - }, - }, nil)) - - managedCache2 := cache.Cache(cacheDuration) - managedCache2.AddRule(rule.Validator(nil, - []rule.PostValidator{ - func(ctx *context.Context) bool { - // it's passed the Claim and now Valid checks if the response contains a header of "DONT" - return ctx.ResponseWriter().Header().Get("DONT") == "" - }, - }, - )) - - app.Get("/valid", validCache.ServeHTTP, h) - - app.Get("/invalid", managedCache.ServeHTTP, h) - app.Get("/invalid2", managedCache2.ServeHTTP, func(ctx *context.Context) { - atomic.AddUint32(&n, 1) - ctx.Header("DONT", "DO not cache that response even if it was claimed") - ctx.Write([]byte(expectedBodyStr)) - }) - - e := httptest.New(t, app) - - // execute from cache the next time - e.GET("/valid").Expect().Status(http.StatusOK).Body().Equal(expectedBodyStr) - time.Sleep(cacheDuration / 5) // lets wait for a while, cache should be saved and ready - e.GET("/valid").Expect().Status(http.StatusOK).Body().Equal(expectedBodyStr) - counter := atomic.LoadUint32(&n) - if counter > 1 { - // n should be 1 because it doesn't changed after the first call - t.Fatalf("%s: %v", t.Name(), &testError{1, counter}) - } - // don't execute from cache, execute the original, counter should ++ here - e.GET("/invalid").Expect().Status(http.StatusOK).Body().Equal(expectedBodyStr) // counter = 2 - e.GET("/invalid2").Expect().Status(http.StatusOK).Body().Equal(expectedBodyStr) // counter = 3 - - counter = atomic.LoadUint32(&n) - if counter != 3 { - // n should be 1 because it doesn't changed after the first call - t.Fatalf("%s: %v", t.Name(), &testError{3, counter}) - } -} diff --git a/cache/client/client.go b/cache/client/client.go index 5d89c429..c941131f 100644 --- a/cache/client/client.go +++ b/cache/client/client.go @@ -6,10 +6,10 @@ import ( "net/http" "time" - "github.com/kataras/iris/v12/cache/cfg" - "github.com/kataras/iris/v12/cache/client/rule" - "github.com/kataras/iris/v12/cache/uri" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/cache/cfg" + "github.com/kataras/iris/cache/client/rule" + "github.com/kataras/iris/cache/uri" + "github.com/kataras/iris/context" ) // ClientHandler is the client-side handler diff --git a/cache/client/handler.go b/cache/client/handler.go index ffeae084..4e4b73a1 100644 --- a/cache/client/handler.go +++ b/cache/client/handler.go @@ -4,9 +4,9 @@ import ( "sync" "time" - "github.com/kataras/iris/v12/cache/client/rule" - "github.com/kataras/iris/v12/cache/entry" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/cache/client/rule" + "github.com/kataras/iris/cache/entry" + "github.com/kataras/iris/context" ) func init() { diff --git a/cache/client/rule/chained.go b/cache/client/rule/chained.go index 20a29960..63778309 100644 --- a/cache/client/rule/chained.go +++ b/cache/client/rule/chained.go @@ -1,7 +1,7 @@ package rule import ( - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) // chainedRule is a Rule with next Rule diff --git a/cache/client/rule/conditional.go b/cache/client/rule/conditional.go index a07f0cd3..82e12e96 100644 --- a/cache/client/rule/conditional.go +++ b/cache/client/rule/conditional.go @@ -1,7 +1,7 @@ package rule import ( - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) // Conditional is a Rule witch adds a predicate in order to its methods to execute diff --git a/cache/client/rule/header.go b/cache/client/rule/header.go index b118fec4..c9972894 100644 --- a/cache/client/rule/header.go +++ b/cache/client/rule/header.go @@ -1,9 +1,9 @@ package rule import ( - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" - "github.com/kataras/iris/v12/cache/ruleset" + "github.com/kataras/iris/cache/ruleset" ) // The HeaderPredicate should be alived on each of $package/rule BUT GOLANG DOESN'T SUPPORT type alias and I don't want to have so many copies around diff --git a/cache/client/rule/not_satisfied.go b/cache/client/rule/not_satisfied.go index cfd85f9a..bab15d80 100644 --- a/cache/client/rule/not_satisfied.go +++ b/cache/client/rule/not_satisfied.go @@ -1,7 +1,7 @@ package rule import ( - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) type notSatisfiedRule struct{} diff --git a/cache/client/rule/rule.go b/cache/client/rule/rule.go index 92fe252f..0c85dd18 100644 --- a/cache/client/rule/rule.go +++ b/cache/client/rule/rule.go @@ -1,6 +1,6 @@ package rule -import "github.com/kataras/iris/v12/context" +import "github.com/kataras/iris/context" // Rule a superset of validators type Rule interface { diff --git a/cache/client/rule/satisfied.go b/cache/client/rule/satisfied.go index 9fd40875..cf342fa5 100644 --- a/cache/client/rule/satisfied.go +++ b/cache/client/rule/satisfied.go @@ -1,7 +1,7 @@ package rule import ( - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) type satisfiedRule struct{} diff --git a/cache/client/rule/validator.go b/cache/client/rule/validator.go index 1f8ca36c..af38f594 100644 --- a/cache/client/rule/validator.go +++ b/cache/client/rule/validator.go @@ -1,6 +1,6 @@ package rule -import "github.com/kataras/iris/v12/context" +import "github.com/kataras/iris/context" // Validators are introduced to implement the RFC about cache (https://tools.ietf.org/html/rfc7234#section-1.1). diff --git a/cache/client/ruleset.go b/cache/client/ruleset.go index 52ec35a1..7ce414c1 100644 --- a/cache/client/ruleset.go +++ b/cache/client/ruleset.go @@ -1,10 +1,10 @@ package client import ( - "github.com/kataras/iris/v12/cache/cfg" - "github.com/kataras/iris/v12/cache/client/rule" - "github.com/kataras/iris/v12/cache/ruleset" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/cache/cfg" + "github.com/kataras/iris/cache/client/rule" + "github.com/kataras/iris/cache/ruleset" + "github.com/kataras/iris/context" ) // DefaultRuleSet is a list of the default pre-cache validators diff --git a/cache/entry/entry.go b/cache/entry/entry.go index f03b8342..ed79ce64 100644 --- a/cache/entry/entry.go +++ b/cache/entry/entry.go @@ -3,7 +3,7 @@ package entry import ( "time" - "github.com/kataras/iris/v12/cache/cfg" + "github.com/kataras/iris/cache/cfg" ) // Entry is the cache entry diff --git a/cache/uri/uribuilder.go b/cache/uri/uribuilder.go index 3ee078c7..f14da064 100644 --- a/cache/uri/uribuilder.go +++ b/cache/uri/uribuilder.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "github.com/kataras/iris/v12/cache/cfg" + "github.com/kataras/iris/cache/cfg" ) // URIBuilder is the requested url builder diff --git a/cli.go b/cli.go index bed303b0..c90ad63e 100644 --- a/cli.go +++ b/cli.go @@ -13,8 +13,8 @@ import ( "path/filepath" "strings" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/router" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/router" "gopkg.in/yaml.v3" ) diff --git a/configuration.go b/configuration.go index e9dcf3ab..e1518b9e 100644 --- a/configuration.go +++ b/configuration.go @@ -11,8 +11,8 @@ import ( "strings" "github.com/kataras/golog" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/netutil" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/netutil" "github.com/BurntSushi/toml" "github.com/kataras/sitemap" diff --git a/configuration_test.go b/configuration_test.go deleted file mode 100644 index ae0e3edf..00000000 --- a/configuration_test.go +++ /dev/null @@ -1,360 +0,0 @@ -package iris - -import ( - "io/ioutil" - "os" - "reflect" - "testing" - "time" - - "gopkg.in/yaml.v3" -) - -// $ go test -v -run TestConfiguration* - -func TestConfigurationStatic(t *testing.T) { - def := DefaultConfiguration() - - app := New() - afterNew := *app.config - - if !reflect.DeepEqual(def, afterNew) { - t.Fatalf("Default configuration is not the same after NewFromConfig expected:\n %#v \ngot:\n %#v", def, afterNew) - } - - afterNew.Charset = "changed" - - if reflect.DeepEqual(def, afterNew) { - t.Fatalf("Configuration should be not equal, got: %#v", afterNew) - } - - app = New().Configure(WithConfiguration(Configuration{DisableBodyConsumptionOnUnmarshal: true})) - - afterNew = *app.config - - if !app.config.DisableBodyConsumptionOnUnmarshal { - t.Fatalf("Passing a Configuration field as Option fails, expected DisableBodyConsumptionOnUnmarshal to be true but was false") - } - - app = New() // empty , means defaults so - if !reflect.DeepEqual(def, *app.config) { - t.Fatalf("Default configuration is not the same after NewFromConfig expected:\n %#v \ngot:\n %#v", def, *app.config) - } -} - -func TestConfigurationOptions(t *testing.T) { - charset := "MYCHARSET" - disableBodyConsumptionOnUnmarshal := true - disableBanner := true - - app := New().Configure(WithCharset(charset), WithoutBodyConsumptionOnUnmarshal, WithoutBanner) - - if got := app.config.Charset; got != charset { - t.Fatalf("Expected configuration Charset to be: %s but got: %s", charset, got) - } - - if got := app.config.DisableBodyConsumptionOnUnmarshal; got != disableBodyConsumptionOnUnmarshal { - t.Fatalf("Expected configuration DisableBodyConsumptionOnUnmarshal to be: %#v but got: %#v", disableBodyConsumptionOnUnmarshal, got) - } - - if got := app.config.DisableStartupLog; got != disableBanner { - t.Fatalf("Expected configuration DisableStartupLog to be: %#v but got: %#v", disableBanner, got) - } - - // now check if other default values are set (should be set automatically) - - expected := DefaultConfiguration() - expected.Charset = charset - expected.DisableBodyConsumptionOnUnmarshal = disableBodyConsumptionOnUnmarshal - expected.DisableStartupLog = disableBanner - - has := *app.config - if !reflect.DeepEqual(has, expected) { - t.Fatalf("Default configuration is not the same after New expected:\n %#v \ngot:\n %#v", expected, has) - } -} - -func TestConfigurationOptionsDeep(t *testing.T) { - charset := "MYCHARSET" - - app := New().Configure(WithCharset(charset), WithoutBodyConsumptionOnUnmarshal, WithoutBanner) - - expected := DefaultConfiguration() - expected.Charset = charset - expected.DisableBodyConsumptionOnUnmarshal = true - expected.DisableStartupLog = true - - has := *app.config - - if !reflect.DeepEqual(has, expected) { - t.Fatalf("DEEP configuration is not the same after New expected:\n %#v \ngot:\n %#v", expected, has) - } -} - -func createGlobalConfiguration(t *testing.T) { - filename := homeConfigurationFilename(".yml") - c, err := parseYAML(filename) - if err != nil { - // this error will be occurred the first time that the configuration - // file doesn't exist. - // Create the YAML-ONLY global configuration file now using the default configuration 'c'. - // This is useful when we run multiple iris servers that share the same - // configuration, even with custom values at its "Other" field. - out, err := yaml.Marshal(&c) - - if err == nil { - err = ioutil.WriteFile(filename, out, os.FileMode(0666)) - } - if err != nil { - t.Fatalf("error while writing the global configuration field at: %s. Trace: %v\n", filename, err) - } - } -} - -func TestConfigurationGlobal(t *testing.T) { - t.Cleanup(func() { - os.Remove(homeConfigurationFilename(".yml")) - }) - - createGlobalConfiguration(t) - - testConfigurationGlobal(t, WithGlobalConfiguration) - testConfigurationGlobal(t, WithConfiguration(YAML(globalConfigurationKeyword))) -} - -func testConfigurationGlobal(t *testing.T, c Configurator) { - app := New().Configure(c) - - if has, expected := *app.config, DefaultConfiguration(); !reflect.DeepEqual(has, expected) { - t.Fatalf("global configuration (which should be defaulted) is not the same with the default one:\n %#v \ngot:\n %#v", has, expected) - } -} - -func TestConfigurationYAML(t *testing.T) { - yamlFile, ferr := ioutil.TempFile("", "configuration.yml") - - if ferr != nil { - t.Fatal(ferr) - } - - defer func() { - yamlFile.Close() - time.Sleep(50 * time.Millisecond) - os.Remove(yamlFile.Name()) - }() - - yamlConfigurationContents := ` -DisablePathCorrection: false -DisablePathCorrectionRedirection: true -EnablePathIntelligence: true -EnablePathEscape: false -FireMethodNotAllowed: true -EnableOptimizations: true -DisableBodyConsumptionOnUnmarshal: true -TimeFormat: "Mon, 02 Jan 2006 15:04:05 GMT" -Charset: "utf-8" -RemoteAddrHeaders: - - X-Real-Ip - - X-Forwarded-For - - CF-Connecting-IP -HostProxyHeaders: - X-Host: true -SSLProxyHeaders: - X-Forwarded-Proto: https -Other: - MyServerName: "Iris: https://github.com/kataras/iris" -` - yamlFile.WriteString(yamlConfigurationContents) - filename := yamlFile.Name() - app := New().Configure(WithConfiguration(YAML(filename))) - - c := app.config - - if expected := false; c.DisablePathCorrection != expected { - t.Fatalf("error on TestConfigurationYAML: Expected DisablePathCorrection %v but got %v", expected, c.DisablePathCorrection) - } - - if expected := true; c.DisablePathCorrectionRedirection != expected { - t.Fatalf("error on TestConfigurationYAML: Expected DisablePathCorrectionRedirection %v but got %v", expected, c.DisablePathCorrectionRedirection) - } - - if expected := true; c.EnablePathIntelligence != expected { - t.Fatalf("error on TestConfigurationYAML: Expected EnablePathIntelligence %v but got %v", expected, c.EnablePathIntelligence) - } - - if expected := false; c.EnablePathEscape != expected { - t.Fatalf("error on TestConfigurationYAML: Expected EnablePathEscape %v but got %v", expected, c.EnablePathEscape) - } - - if expected := true; c.EnableOptimizations != expected { - t.Fatalf("error on TestConfigurationYAML: Expected EnableOptimizations %v but got %v", expected, c.EnablePathEscape) - } - - if expected := true; c.FireMethodNotAllowed != expected { - t.Fatalf("error on TestConfigurationYAML: Expected FireMethodNotAllowed %v but got %v", expected, c.FireMethodNotAllowed) - } - - if expected := true; c.DisableBodyConsumptionOnUnmarshal != expected { - t.Fatalf("error on TestConfigurationYAML: Expected DisableBodyConsumptionOnUnmarshal %v but got %v", expected, c.DisableBodyConsumptionOnUnmarshal) - } - - if expected := "Mon, 02 Jan 2006 15:04:05 GMT"; c.TimeFormat != expected { - t.Fatalf("error on TestConfigurationYAML: Expected TimeFormat %s but got %s", expected, c.TimeFormat) - } - - if expected := "utf-8"; c.Charset != expected { - t.Fatalf("error on TestConfigurationYAML: Expected Charset %s but got %s", expected, c.Charset) - } - - if len(c.RemoteAddrHeaders) == 0 { - t.Fatalf("error on TestConfigurationYAML: Expected RemoteAddrHeaders to be filled") - } - - expectedRemoteAddrHeaders := []string{ - "X-Real-Ip", - "X-Forwarded-For", - "CF-Connecting-IP", - } - - if expected, got := len(c.RemoteAddrHeaders), len(expectedRemoteAddrHeaders); expected != got { - t.Fatalf("error on TestConfigurationYAML: Expected RemoteAddrHeaders' len(%d) and got(%d), len is not the same", expected, got) - } - - for i, v := range c.RemoteAddrHeaders { - if expected, got := expectedRemoteAddrHeaders[i], v; expected != got { - t.Fatalf("error on TestConfigurationYAML: Expected RemoteAddrHeaders[%d] = %s but got %s", i, expected, got) - } - } - - expectedHostProxyHeaders := map[string]bool{ - "X-Host": true, - } - - if expected, got := len(c.HostProxyHeaders), len(expectedHostProxyHeaders); expected != got { - t.Fatalf("error on TestConfigurationYAML: Expected HostProxyHeaders' len(%d) and got(%d), len is not the same", expected, got) - } - - for k, v := range c.HostProxyHeaders { - if expected, got := expectedHostProxyHeaders[k], v; expected != got { - t.Fatalf("error on TestConfigurationYAML: Expected HostProxyHeaders[%s] = %t but got %t", k, expected, got) - } - } - - expectedSSLProxyHeaders := map[string]string{ - "X-Forwarded-Proto": "https", - } - - if expected, got := len(c.SSLProxyHeaders), len(c.SSLProxyHeaders); expected != got { - t.Fatalf("error on TestConfigurationYAML: Expected SSLProxyHeaders' len(%d) and got(%d), len is not the same", expected, got) - } - - for k, v := range c.SSLProxyHeaders { - if expected, got := expectedSSLProxyHeaders[k], v; expected != got { - t.Fatalf("error on TestConfigurationYAML: Expected SSLProxyHeaders[%s] = %s but got %s", k, expected, got) - } - } - - if len(c.Other) == 0 { - t.Fatalf("error on TestConfigurationYAML: Expected Other to be filled") - } - - if expected, got := "Iris: https://github.com/kataras/iris", c.Other["MyServerName"]; expected != got { - t.Fatalf("error on TestConfigurationYAML: Expected Other['MyServerName'] %s but got %s", expected, got) - } -} - -func TestConfigurationTOML(t *testing.T) { - tomlFile, ferr := ioutil.TempFile("", "configuration.toml") - - if ferr != nil { - t.Fatal(ferr) - } - - defer func() { - tomlFile.Close() - time.Sleep(50 * time.Millisecond) - os.Remove(tomlFile.Name()) - }() - - tomlConfigurationContents := ` -DisablePathCorrectionRedirection = true -EnablePathEscape = false -FireMethodNotAllowed = true -EnableOptimizations = true -DisableBodyConsumptionOnUnmarshal = true -TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT" -Charset = "utf-8" - -RemoteAddrHeaders = ["X-Real-Ip", "X-Forwarded-For", "CF-Connecting-IP"] - -[Other] - # Indentation (tabs and/or spaces) is allowed but not required - MyServerName = "Iris: https://github.com/kataras/iris" - -` - tomlFile.WriteString(tomlConfigurationContents) - filename := tomlFile.Name() - app := New().Configure(WithConfiguration(TOML(filename))) - - c := app.config - - if expected := false; c.DisablePathCorrection != expected { - t.Fatalf("error on TestConfigurationTOML: Expected DisablePathCorrection %v but got %v", expected, c.DisablePathCorrection) - } - - if expected := true; c.DisablePathCorrectionRedirection != expected { - t.Fatalf("error on TestConfigurationTOML: Expected DisablePathCorrectionRedirection %v but got %v", expected, c.DisablePathCorrectionRedirection) - } - - if expected := false; c.EnablePathEscape != expected { - t.Fatalf("error on TestConfigurationTOML: Expected EnablePathEscape %v but got %v", expected, c.EnablePathEscape) - } - - if expected := true; c.EnableOptimizations != expected { - t.Fatalf("error on TestConfigurationTOML: Expected EnableOptimizations %v but got %v", expected, c.EnablePathEscape) - } - - if expected := true; c.FireMethodNotAllowed != expected { - t.Fatalf("error on TestConfigurationTOML: Expected FireMethodNotAllowed %v but got %v", expected, c.FireMethodNotAllowed) - } - - if expected := true; c.DisableBodyConsumptionOnUnmarshal != expected { - t.Fatalf("error on TestConfigurationTOML: Expected DisableBodyConsumptionOnUnmarshal %v but got %v", expected, c.DisableBodyConsumptionOnUnmarshal) - } - - if expected := "Mon, 02 Jan 2006 15:04:05 GMT"; c.TimeFormat != expected { - t.Fatalf("error on TestConfigurationTOML: Expected TimeFormat %s but got %s", expected, c.TimeFormat) - } - - if expected := "utf-8"; c.Charset != expected { - t.Fatalf("error on TestConfigurationTOML: Expected Charset %s but got %s", expected, c.Charset) - } - - if len(c.RemoteAddrHeaders) == 0 { - t.Fatalf("error on TestConfigurationTOML: Expected RemoteAddrHeaders to be filled") - } - - expectedRemoteAddrHeaders := []string{ - "X-Real-Ip", - "X-Forwarded-For", - "CF-Connecting-IP", - } - - if expected, got := len(c.RemoteAddrHeaders), len(expectedRemoteAddrHeaders); expected != got { - t.Fatalf("error on TestConfigurationTOML: Expected RemoteAddrHeaders' len(%d) and got(%d), len is not the same", expected, got) - } - - for i, got := range c.RemoteAddrHeaders { - if expected := expectedRemoteAddrHeaders[i]; expected != got { - t.Fatalf("error on TestConfigurationTOML: Expected RemoteAddrHeaders[%d] = %s but got %s", i, expected, got) - } - } - - if len(c.Other) == 0 { - t.Fatalf("error on TestConfigurationTOML: Expected Other to be filled") - } - - if expected, got := "Iris: https://github.com/kataras/iris", c.Other["MyServerName"]; expected != got { - t.Fatalf("error on TestConfigurationTOML: Expected Other['MyServerName'] %s but got %s", expected, got) - } -} diff --git a/context/configuration.go b/context/configuration.go index fa9091d7..15cc8567 100644 --- a/context/configuration.go +++ b/context/configuration.go @@ -1,6 +1,6 @@ package context -import "github.com/kataras/iris/v12/core/netutil" +import "github.com/kataras/iris/core/netutil" // ConfigurationReadOnly can be implemented // by Configuration, it's being used inside the Context. diff --git a/context/context.go b/context/context.go index afd0aee3..b7d723ac 100644 --- a/context/context.go +++ b/context/context.go @@ -25,8 +25,8 @@ import ( "time" "unsafe" - "github.com/kataras/iris/v12/core/memstore" - "github.com/kataras/iris/v12/core/netutil" + "github.com/kataras/iris/core/memstore" + "github.com/kataras/iris/core/netutil" "github.com/Shopify/goreferrer" "github.com/fatih/structs" diff --git a/context/handler.go b/context/handler.go index 6e653536..a61e0bdf 100644 --- a/context/handler.go +++ b/context/handler.go @@ -31,7 +31,7 @@ var ( // If the name starts with "iris" then it replaces that string with the // full Iris module package name, // e.g. iris/middleware/logger.(*requestLoggerMiddleware).ServeHTTP-fm to -// github.com/kataras/iris/v12/middleware/logger.(*requestLoggerMiddleware).ServeHTTP-fm +// github.com/kataras/iris/middleware/logger.(*requestLoggerMiddleware).ServeHTTP-fm // for convenient between Iris versions. func SetHandlerName(original string, replacement string) { if strings.HasPrefix(original, "iris") { diff --git a/context/request_params.go b/context/request_params.go index 4aa4ae78..ccc48d63 100644 --- a/context/request_params.go +++ b/context/request_params.go @@ -6,7 +6,7 @@ import ( "strconv" "strings" - "github.com/kataras/iris/v12/core/memstore" + "github.com/kataras/iris/core/memstore" ) // RequestParams is a key string - value string storage which diff --git a/context/route.go b/context/route.go index 56104828..6e332292 100644 --- a/context/route.go +++ b/context/route.go @@ -4,7 +4,7 @@ import ( "io" "time" - "github.com/kataras/iris/v12/macro" + "github.com/kataras/iris/macro" ) // RouteReadOnly allows decoupled access to the current route diff --git a/core/errgroup/errgroup_test.go b/core/errgroup/errgroup_test.go deleted file mode 100644 index f01fbfff..00000000 --- a/core/errgroup/errgroup_test.go +++ /dev/null @@ -1,173 +0,0 @@ -package errgroup - -import ( - "errors" - "fmt" - "strings" - "testing" -) - -func TestErrorError(t *testing.T) { - testErr := errors.New("error") - err := &Error{Err: testErr} - if expected, got := testErr.Error(), err.Error(); expected != got { - t.Fatalf("expected %s but got %s", expected, got) - } -} - -func TestErrorUnwrap(t *testing.T) { - wrapped := errors.New("unwrap") - - err := &Error{Err: fmt.Errorf("this wraps:%w", wrapped)} - if expected, got := wrapped, errors.Unwrap(err); expected != got { - t.Fatalf("expected %#+v but got %#+v", expected, got) - } - -} -func TestErrorIs(t *testing.T) { - testErr := errors.New("is") - err := &Error{Err: fmt.Errorf("this is: %w", testErr)} - if expected, got := true, errors.Is(err, testErr); expected != got { - t.Fatalf("expected %v but got %v", expected, got) - } -} - -func TestErrorAs(t *testing.T) { - testErr := errors.New("as") - err := &Error{Err: testErr} - if expected, got := true, errors.As(err, &testErr); expected != got { - t.Fatalf("[testErr as err] expected %v but got %v", expected, got) - } - if expected, got := true, errors.As(testErr, &err); expected != got { - t.Fatalf("[err as testErr] expected %v but got %v", expected, got) - } -} - -func TestGroupError(t *testing.T) { - g := New(0) - tests := []string{"error 1", "error 2", "error 3"} - for _, tt := range tests { - g.Add(errors.New(tt)) - } - - if expected, got := strings.Join(tests, "\n"), g.Error(); expected != got { - t.Fatalf("expected '%s' but got '%s'", expected, got) - } -} - -func TestGroup(t *testing.T) { - const ( - apiErrorsType = iota + 1 - childAPIErrorsType - childAPIErrors2Type = "string type 1" - childAPIErrors2Type1 = "string type 2" - - apiErrorsText = "apiErrors error 1" - childAPIErrorsText = "apiErrors:child error 1" - childAPIErrors2Text = "apiErrors:child2 error 1" - childAPIErrors2Text1 = "apiErrors:child2_1 error 1" - ) - - g := New(nil) - apiErrorsGroup := g.Group(apiErrorsType) - apiErrorsGroup.Errf(apiErrorsText) - - childAPIErrorsGroup := apiErrorsGroup.Group(childAPIErrorsType) - childAPIErrorsGroup.Addf(childAPIErrorsText) - childAPIErrorsGroup2 := apiErrorsGroup.Group(childAPIErrors2Type) - childAPIErrorsGroup2.Addf(childAPIErrors2Text) - childAPIErrorsGroup2Group1 := childAPIErrorsGroup2.Group(childAPIErrors2Type1) - childAPIErrorsGroup2Group1.Addf(childAPIErrors2Text1) - - if apiErrorsGroup.Type != apiErrorsType { - t.Fatal("invalid type") - } - - if childAPIErrorsGroup.Type != childAPIErrorsType { - t.Fatal("invalid type") - } - - if childAPIErrorsGroup2.Type != childAPIErrors2Type { - t.Fatal("invalid type") - } - - if childAPIErrorsGroup2Group1.Type != childAPIErrors2Type1 { - t.Fatal("invalid type") - } - - if expected, got := 2, len(apiErrorsGroup.children); expected != got { - t.Fatalf("expected %d but got %d", expected, got) - } - - if expected, got := 0, len(childAPIErrorsGroup.children); expected != got { - t.Fatalf("expected %d but got %d", expected, got) - } - - if expected, got := 1, len(childAPIErrorsGroup2.children); expected != got { - t.Fatalf("expected %d but got %d", expected, got) - } - - if expected, got := 0, len(childAPIErrorsGroup2Group1.children); expected != got { - t.Fatalf("expected %d but got %d", expected, got) - } - - if expected, got := 1, apiErrorsGroup.index; expected != got { - t.Fatalf("expected index %d but got %d", expected, got) - } - - if expected, got := 2, childAPIErrorsGroup.index; expected != got { - t.Fatalf("expected index %d but got %d", expected, got) - } - - if expected, got := 3, childAPIErrorsGroup2.index; expected != got { - t.Fatalf("expected index %d but got %d", expected, got) - } - - if expected, got := 4, childAPIErrorsGroup2Group1.index; expected != got { - t.Fatalf("expected index %d but got %d", expected, got) - } - - t.Run("Error", func(t *testing.T) { - if expected, got := - strings.Join([]string{apiErrorsText, childAPIErrorsText, childAPIErrors2Text, childAPIErrors2Text1}, delim), g.Error(); expected != got { - t.Fatalf("expected '%s' but got '%s'", expected, got) - } - }) - - t.Run("Walk", func(t *testing.T) { - expectedEntries := 4 - _ = Walk(g, func(typ interface{}, err error) { - g.IncludeChildren = false - childAPIErrorsGroup.IncludeChildren = false - childAPIErrorsGroup2.IncludeChildren = false - childAPIErrorsGroup2Group1.IncludeChildren = false - - expectedEntries-- - var expected string - - switch typ { - case apiErrorsType: - expected = apiErrorsText - case childAPIErrorsType: - expected = childAPIErrorsText - case childAPIErrors2Type: - expected = childAPIErrors2Text - case childAPIErrors2Type1: - expected = childAPIErrors2Text1 - } - - if got := err.Error(); expected != got { - t.Fatalf("[%v] expected '%s' but got '%s'", typ, expected, got) - } - }) - - if expectedEntries != 0 { - t.Fatalf("not valid number of errors [...%d]", expectedEntries) - } - - g.IncludeChildren = true - childAPIErrorsGroup.IncludeChildren = true - childAPIErrorsGroup2.IncludeChildren = true - childAPIErrorsGroup2Group1.IncludeChildren = true - }) -} diff --git a/core/handlerconv/from_std.go b/core/handlerconv/from_std.go index d42ac1c0..983ddd43 100644 --- a/core/handlerconv/from_std.go +++ b/core/handlerconv/from_std.go @@ -4,7 +4,7 @@ import ( "fmt" "net/http" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) // FromStd converts native http.Handler & http.HandlerFunc to context.Handler. diff --git a/core/handlerconv/from_std_test.go b/core/handlerconv/from_std_test.go deleted file mode 100644 index c024f244..00000000 --- a/core/handlerconv/from_std_test.go +++ /dev/null @@ -1,71 +0,0 @@ -// black-box testing -package handlerconv_test - -import ( - stdContext "context" - "net/http" - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/handlerconv" - "github.com/kataras/iris/v12/httptest" -) - -func TestFromStd(t *testing.T) { - expected := "ok" - std := func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write([]byte(expected)) - if err != nil { - t.Fatal(err) - } - } - - h := handlerconv.FromStd(http.HandlerFunc(std)) - - hFunc := handlerconv.FromStd(std) - - app := iris.New() - app.Get("/handler", h) - app.Get("/func", hFunc) - - e := httptest.New(t, app) - - e.GET("/handler"). - Expect().Status(iris.StatusOK).Body().Equal(expected) - - e.GET("/func"). - Expect().Status(iris.StatusOK).Body().Equal(expected) -} - -func TestFromStdWithNext(t *testing.T) { - basicauth := "secret" - passed := "ok" - - type contextKey string - stdWNext := func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - if username, password, ok := r.BasicAuth(); ok && - username == basicauth && password == basicauth { - ctx := stdContext.WithValue(r.Context(), contextKey("key"), "ok") - next.ServeHTTP(w, r.WithContext(ctx)) - return - } - w.WriteHeader(iris.StatusForbidden) - } - - h := handlerconv.FromStdWithNext(stdWNext) - next := func(ctx *context.Context) { - ctx.WriteString(ctx.Request().Context().Value(contextKey("key")).(string)) - } - - app := iris.New() - app.Get("/handlerwithnext", h, next) - - e := httptest.New(t, app) - - e.GET("/handlerwithnext"). - Expect().Status(iris.StatusForbidden) - - e.GET("/handlerwithnext").WithBasicAuth(basicauth, basicauth). - Expect().Status(iris.StatusOK).Body().Equal(passed) -} diff --git a/core/host/proxy.go b/core/host/proxy.go index 2f9ecee1..04460916 100644 --- a/core/host/proxy.go +++ b/core/host/proxy.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/kataras/iris/v12/core/netutil" + "github.com/kataras/iris/core/netutil" ) func singleJoiningSlash(a, b string) string { diff --git a/core/host/proxy_test.go b/core/host/proxy_test.go deleted file mode 100644 index 3ef18860..00000000 --- a/core/host/proxy_test.go +++ /dev/null @@ -1,69 +0,0 @@ -// black-box testing -package host_test - -import ( - "net" - "net/url" - "testing" - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/host" - "github.com/kataras/iris/v12/httptest" -) - -func TestProxy(t *testing.T) { - expectedIndex := "ok /" - expectedAbout := "ok /about" - unexpectedRoute := "unexpected" - - // proxySrv := iris.New() - u, err := url.Parse("https://localhost:4444") - if err != nil { - t.Fatalf("%v while parsing url", err) - } - - proxy := host.NewProxy("", u) - - addr := &net.TCPAddr{ - IP: net.IPv4(127, 0, 0, 1), - Port: 0, - } - - listener, err := net.ListenTCP("tcp", addr) - if err != nil { - t.Fatalf("%v while creating listener", err) - } - - go proxy.Serve(listener) // should be localhost/127.0.0.1:80 but travis throws permission denied. - - t.Log(listener.Addr().String()) - <-time.After(time.Second) - t.Log(listener.Addr().String()) - - app := iris.New() - app.Get("/", func(ctx *context.Context) { - ctx.WriteString(expectedIndex) - }) - - app.Get("/about", func(ctx *context.Context) { - ctx.WriteString(expectedAbout) - }) - - app.OnErrorCode(iris.StatusNotFound, func(ctx *context.Context) { - ctx.WriteString(unexpectedRoute) - }) - - l, err := net.Listen("tcp", "localhost:4444") // should be localhost/127.0.0.1:443 but travis throws permission denied. - if err != nil { - t.Fatalf("%v while creating tcp4 listener for new tls local test listener", err) - } - // main server - go app.Run(iris.Listener(httptest.NewLocalTLSListener(l)), iris.WithoutStartupLog) // nolint:errcheck - - e := httptest.NewInsecure(t, httptest.URL("http://"+listener.Addr().String())) - e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(expectedIndex) - e.GET("/about").Expect().Status(iris.StatusOK).Body().Equal(expectedAbout) - e.GET("/notfound").Expect().Status(iris.StatusNotFound).Body().Equal(unexpectedRoute) -} diff --git a/core/host/supervisor.go b/core/host/supervisor.go index dec1b58b..bacdbe9a 100644 --- a/core/host/supervisor.go +++ b/core/host/supervisor.go @@ -14,7 +14,7 @@ import ( "sync/atomic" "time" - "github.com/kataras/iris/v12/core/netutil" + "github.com/kataras/iris/core/netutil" "golang.org/x/crypto/acme/autocert" ) diff --git a/core/host/supervisor_task_example_test.go b/core/host/supervisor_task_example_test.go deleted file mode 100644 index d0db8edd..00000000 --- a/core/host/supervisor_task_example_test.go +++ /dev/null @@ -1,112 +0,0 @@ -// white-box testing -package host - -import ( - "context" - "fmt" - "log" - "net" - "net/http" - "os" - "time" -) - -func ExampleSupervisor_RegisterOnError() { - su := New(&http.Server{Addr: ":8273", Handler: http.DefaultServeMux}) - - su.RegisterOnError(func(err error) { - fmt.Println(err.Error()) - }) - - su.RegisterOnError(func(err error) { - fmt.Println(err.Error()) - }) - - su.RegisterOnError(func(err error) { - fmt.Println(err.Error()) - }) - - go su.ListenAndServe() - time.Sleep(1 * time.Second) - if err := su.Shutdown(context.TODO()); err != nil { - panic(err) - } - time.Sleep(1 * time.Second) - - // Output: - // http: Server closed - // http: Server closed - // http: Server closed -} - -type myTestTask struct { - restartEvery time.Duration - maxRestarts int - logger *log.Logger -} - -func (m myTestTask) OnServe(host TaskHost) { - host.Supervisor.DeferFlow() // don't exit on underline server's Shutdown. - - ticker := time.NewTicker(m.restartEvery) - defer ticker.Stop() - rans := 0 - for range ticker.C { - exitAfterXRestarts := m.maxRestarts - if rans == exitAfterXRestarts { - m.logger.Println("exit") - ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second) - defer cancel() - _ = host.Supervisor.Shutdown(ctx) // total shutdown - host.Supervisor.RestoreFlow() // free to exit (if shutdown) - return - } - - rans++ - - m.logger.Println(fmt.Sprintf("closed %d times", rans)) - host.Shutdown(context.TODO()) - - startDelay := 2 * time.Second - time.AfterFunc(startDelay, func() { - m.logger.Println("restart") - if err := host.Serve(); err != nil { // restart - panic(err) - } - }) - - } -} - -func ExampleSupervisor_RegisterOnServe() { - h := New(&http.Server{ - Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - }), - }) - - logger := log.New(os.Stdout, "Supervisor: ", 0) - - mytask := myTestTask{ - restartEvery: 3 * time.Second, - maxRestarts: 2, - logger: logger, - } - - h.RegisterOnServe(mytask.OnServe) - - ln, err := net.Listen("tcp4", ":9394") - if err != nil { - panic(err.Error()) - } - - logger.Println("server started...") - h.Serve(ln) - - // Output: - // Supervisor: server started... - // Supervisor: closed 1 times - // Supervisor: restart - // Supervisor: closed 2 times - // Supervisor: restart - // Supervisor: exit -} diff --git a/core/host/supervisor_test.go b/core/host/supervisor_test.go deleted file mode 100644 index 380b7a7f..00000000 --- a/core/host/supervisor_test.go +++ /dev/null @@ -1,119 +0,0 @@ -// white-box testing - -package host - -import ( - "bytes" - "context" - "crypto/tls" - "log" - "net" - "net/http" - "strings" - "sync" - "testing" - - "github.com/iris-contrib/httpexpect/v2" -) - -const ( - debug = false -) - -func newTester(t *testing.T, baseURL string, handler http.Handler) *httpexpect.Expect { - var transporter http.RoundTripper - - if strings.HasPrefix(baseURL, "http") { // means we are testing real serve time - transporter = &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - } else { // means we are testing the handler itself - transporter = httpexpect.NewBinder(handler) - } - - testConfiguration := httpexpect.Config{ - BaseURL: baseURL, - Client: &http.Client{ - Transport: transporter, - Jar: httpexpect.NewJar(), - }, - Reporter: httpexpect.NewAssertReporter(t), - } - - if debug { - testConfiguration.Printers = []httpexpect.Printer{ - httpexpect.NewDebugPrinter(t, true), - } - } - - return httpexpect.WithConfig(testConfiguration) -} - -func testSupervisor(t *testing.T, creator func(*http.Server, []func(TaskHost)) *Supervisor) { - loggerOutput := &bytes.Buffer{} - logger := log.New(loggerOutput, "", 0) - mu := new(sync.RWMutex) - const ( - expectedHelloMessage = "Hello\n" - ) - - // http routing - - expectedBody := "this is the response body\n" - - mux := http.NewServeMux() - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write([]byte(expectedBody)) - if err != nil { - t.Fatal(err) - } - }) - - // host (server wrapper and adapter) construction - - srv := &http.Server{Handler: mux, ErrorLog: logger} - addr := "localhost:5525" - // serving - ln, err := net.Listen("tcp4", addr) - if err != nil { - t.Fatal(err) - } - - helloMe := func(_ TaskHost) { - mu.Lock() - logger.Print(expectedHelloMessage) - mu.Unlock() - } - - host := creator(srv, []func(TaskHost){helloMe}) - defer host.Shutdown(context.TODO()) - - go host.Serve(ln) - - // http testsing and various calls - // no need for time sleep because the following will take some time by theirselves - tester := newTester(t, "http://"+addr, mux) - tester.Request("GET", "/").Expect().Status(http.StatusOK).Body().Equal(expectedBody) - - // WARNING: Data Race here because we try to read the logs - // but it's "safe" here. - - // testing Task (recorded) message: - mu.RLock() - got := loggerOutput.String() - mu.RUnlock() - if expectedHelloMessage != got { - t.Fatalf("expected hello Task's message to be '%s' but got '%s'", expectedHelloMessage, got) - } -} - -func TestSupervisor(t *testing.T) { - testSupervisor(t, func(srv *http.Server, tasks []func(TaskHost)) *Supervisor { - su := New(srv) - for _, t := range tasks { - su.RegisterOnServe(t) - } - - return su - }) -} diff --git a/core/host/task.go b/core/host/task.go index 3fd10652..4741f50c 100644 --- a/core/host/task.go +++ b/core/host/task.go @@ -13,7 +13,7 @@ import ( "runtime" "time" - "github.com/kataras/iris/v12/core/netutil" + "github.com/kataras/iris/core/netutil" ) // WriteStartupLogOnServe is a task which accepts a logger(io.Writer) diff --git a/core/memstore/memstore_test.go b/core/memstore/memstore_test.go deleted file mode 100644 index 686d48e4..00000000 --- a/core/memstore/memstore_test.go +++ /dev/null @@ -1,167 +0,0 @@ -// white-box testing -package memstore - -import ( - "bytes" - "encoding/json" - "fmt" - "testing" -) - -type myTestObject struct { - Name string `json:"name"` -} - -func TestMuttable(t *testing.T) { - var p Store - - // slice - p.Set("slice", []myTestObject{{"value 1"}, {"value 2"}}) - v := p.Get("slice").([]myTestObject) - v[0].Name = "modified" - - vv := p.Get("slice").([]myTestObject) - if vv[0].Name != "modified" { - t.Fatalf("expected slice to be muttable but caller was not able to change its value") - } - - // map - - p.Set("map", map[string]myTestObject{"key 1": {"value 1"}, "key 2": {"value 2"}}) - vMap := p.Get("map").(map[string]myTestObject) - vMap["key 1"] = myTestObject{"modified"} - - vvMap := p.Get("map").(map[string]myTestObject) - if vvMap["key 1"].Name != "modified" { - t.Fatalf("expected map to be muttable but caller was not able to change its value") - } - - // object pointer of a value, it can change like maps or slices and arrays. - p.Set("objp", &myTestObject{"value"}) - // we expect pointer here, as we set it. - vObjP := p.Get("objp").(*myTestObject) - - vObjP.Name = "modified" - - vvObjP := p.Get("objp").(*myTestObject) - if vvObjP.Name != "modified" { - t.Fatalf("expected objp to be muttable but caller was able to change its value") - } -} - -func TestImmutable(t *testing.T) { - var p Store - - // slice - p.SetImmutable("slice", []myTestObject{{"value 1"}, {"value 2"}}) - v := p.Get("slice").([]myTestObject) - v[0].Name = "modified" - - vv := p.Get("slice").([]myTestObject) - if vv[0].Name == "modified" { - t.Fatalf("expected slice to be immutable but caller was able to change its value") - } - - // map - p.SetImmutable("map", map[string]myTestObject{"key 1": {"value 1"}, "key 2": {"value 2"}}) - vMap := p.Get("map").(map[string]myTestObject) - vMap["key 1"] = myTestObject{"modified"} - - vvMap := p.Get("map").(map[string]myTestObject) - if vvMap["key 1"].Name == "modified" { - t.Fatalf("expected map to be immutable but caller was able to change its value") - } - - // object value, it's immutable at all cases. - p.SetImmutable("obj", myTestObject{"value"}) - vObj := p.Get("obj").(myTestObject) - vObj.Name = "modified" - - vvObj := p.Get("obj").(myTestObject) - if vvObj.Name == "modified" { - t.Fatalf("expected obj to be immutable but caller was able to change its value") - } - - // object pointer of a value, it's immutable at all cases. - p.SetImmutable("objp", &myTestObject{"value"}) - // we expect no pointer here if SetImmutable. - // so it can't be changed by-design - vObjP := p.Get("objp").(myTestObject) - - vObjP.Name = "modified" - - vvObjP := p.Get("objp").(myTestObject) - if vvObjP.Name == "modified" { - t.Fatalf("expected objp to be immutable but caller was able to change its value") - } -} - -func TestImmutableSetOnlyWithSetImmutable(t *testing.T) { - var p Store - - p.SetImmutable("objp", &myTestObject{"value"}) - - p.Set("objp", &myTestObject{"modified"}) - vObjP := p.Get("objp").(myTestObject) - if vObjP.Name == "modified" { - t.Fatalf("caller should not be able to change the immutable entry with a simple `Set`") - } - - p.SetImmutable("objp", &myTestObject{"value with SetImmutable"}) - vvObjP := p.Get("objp").(myTestObject) - if vvObjP.Name != "value with SetImmutable" { - t.Fatalf("caller should be able to change the immutable entry with a `SetImmutable`") - } -} - -func TestGetInt64Default(t *testing.T) { - var p Store - - p.Set("a uint16", uint16(2)) - if v := p.GetInt64Default("a uint16", 0); v != 2 { - t.Fatalf("unexpected value of %d", v) - } -} - -func TestJSON(t *testing.T) { - var p Store - - p.Set("key1", "value1") - p.Set("key2", 2) - p.Set("key3", myTestObject{Name: "makis"}) - - b, err := json.Marshal(p) - if err != nil { - t.Fatal(err) - } - - expectedJSON := []byte(`[{"key":"key1","value":"value1"},{"key":"key2","value":2},{"key":"key3","value":{"name":"makis"}}]`) - - if !bytes.Equal(b, expectedJSON) { - t.Fatalf("expected: %s but got: %s", string(expectedJSON), string(b)) - } - - var newStore Store - if err = json.Unmarshal(b, &newStore); err != nil { - t.Fatal(err) - } - - for i, v := range newStore { - expected, got := p.Get(v.Key), v.ValueRaw - - if ex, g := fmt.Sprintf("%v", expected), fmt.Sprintf("%v", got); ex != g { - if _, isMap := got.(map[string]interface{}); isMap { - // was struct but converted into map (as expected). - b1, _ := json.Marshal(expected) - b2, _ := json.Marshal(got) - - if !bytes.Equal(b1, b2) { - t.Fatalf("[%d] JSON expected: %s but got: %s", i, string(b1), string(b2)) - } - - continue - } - t.Fatalf("[%d] expected: %s but got: %s", i, ex, g) - } - } -} diff --git a/core/netutil/addr_test.go b/core/netutil/addr_test.go deleted file mode 100644 index e5fec93d..00000000 --- a/core/netutil/addr_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package netutil - -import ( - "testing" -) - -func TestIsLoopbackHost(t *testing.T) { - tests := []struct { - host string - valid bool - }{ - {"subdomain.127.0.0.1:8080", true}, - {"subdomain.127.0.0.1", true}, - {"subdomain.localhost:8080", true}, - {"subdomain.localhost", true}, - {"subdomain.127.0000.0000.1:8080", true}, - {"subdomain.127.0000.0000.1", true}, - {"subdomain.127.255.255.254:8080", true}, - {"subdomain.127.255.255.254", true}, - - {"subdomain.0000:0:0000::01.1:8080", false}, - {"subdomain.0000:0:0000::01", false}, - {"subdomain.0000:0:0000::01.1:8080", false}, - {"subdomain.0000:0:0000::01", false}, - {"subdomain.0000:0000:0000:0000:0000:0000:0000:0001:8080", true}, - {"subdomain.0000:0000:0000:0000:0000:0000:0000:0001", false}, - - {"subdomain.example:8080", false}, - {"subdomain.example", false}, - {"subdomain.example.com:8080", false}, - {"subdomain.example.com", false}, - {"subdomain.com", false}, - {"subdomain", false}, - {".subdomain", false}, - {"127.0.0.1.com", false}, - } - - for i, tt := range tests { - if expected, got := tt.valid, IsLoopbackHost(tt.host); expected != got { - t.Fatalf("[%d] expected %t but got %t for %s", i, expected, got, tt.host) - } - } -} diff --git a/core/netutil/ip_test.go b/core/netutil/ip_test.go deleted file mode 100644 index 4451b4fa..00000000 --- a/core/netutil/ip_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package netutil - -import ( - "net" - "testing" -) - -func TestIP(t *testing.T) { - privateRanges := []IPRange{ - { - Start: net.ParseIP("10.0.0.0"), - End: net.ParseIP("10.255.255.255"), - }, - { - Start: net.ParseIP("100.64.0.0"), - End: net.ParseIP("100.127.255.255"), - }, - { - Start: net.ParseIP("172.16.0.0"), - End: net.ParseIP("172.31.255.255"), - }, - { - Start: net.ParseIP("192.0.0.0"), - End: net.ParseIP("192.0.0.255"), - }, - { - Start: net.ParseIP("192.168.0.0"), - End: net.ParseIP("192.168.255.255"), - }, - { - Start: net.ParseIP("198.18.0.0"), - End: net.ParseIP("198.19.255.255"), - }, - } - - addresses := []string{ - "201.37.138.59", - "159.117.3.153", - "166.192.97.84", - "225.181.213.210", - "124.50.84.134", - "87.53.250.102", - "106.79.33.62", - "242.120.17.144", - "131.179.101.254", - "103.11.11.174", - "115.97.0.114", - "219.202.120.251", - "37.72.123.120", - "154.94.78.101", - "126.105.144.250", - } - - got, ok := GetIPAddress(addresses, privateRanges) - if !ok { - t.Logf("expected addr to be matched") - } - - if expected := "126.105.144.250"; expected != got { - t.Logf("expected addr to be found: %s but got: %s", expected, got) - } -} diff --git a/core/router/api_builder.go b/core/router/api_builder.go index a781f47c..ef8113a6 100644 --- a/core/router/api_builder.go +++ b/core/router/api_builder.go @@ -10,11 +10,11 @@ import ( "strings" "time" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/errgroup" - "github.com/kataras/iris/v12/hero" - "github.com/kataras/iris/v12/macro" - macroHandler "github.com/kataras/iris/v12/macro/handler" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/errgroup" + "github.com/kataras/iris/hero" + "github.com/kataras/iris/macro" + macroHandler "github.com/kataras/iris/macro/handler" ) // MethodNone is a Virtual method diff --git a/core/router/api_builder_benchmark_test.go b/core/router/api_builder_benchmark_test.go deleted file mode 100644 index e709b266..00000000 --- a/core/router/api_builder_benchmark_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package router - -import ( - "bytes" - "math/rand" - "strings" - "testing" - "time" - - "github.com/kataras/iris/v12/context" -) - -// -// randStringBytesMaskImprSrc helps us to generate random paths for the test, -// the below piece of code is external, as an answer to a stackoverflow question. -// -// START. -const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" -const ( - letterIdxBits = 6 // 6 bits to represent a letter index - letterIdxMask = 1<= 0; { - if remain == 0 { - cache, remain = src.Int63(), letterIdxMax - } - if idx := int(cache & letterIdxMask); idx < len(letterBytes) { - b[i] = letterBytes[idx] - i-- - } - cache >>= letterIdxBits - remain-- - } - - return strings.ToLower(string(b)) -} - -// END. - -func genPaths(routesLength, minCharLength, maxCharLength int) []string { - // b := new(strings.Builder) - b := new(bytes.Buffer) - paths := make([]string, routesLength) - pathStart := '/' - for i := 0; i < routesLength; i++ { - pathSegmentCharsLength := rand.Intn(maxCharLength-minCharLength) + minCharLength - - b.WriteRune(pathStart) - b.WriteString(randStringBytesMaskImprSrc(pathSegmentCharsLength)) - b.WriteString("/{name:string}/") // sugar. - b.WriteString(randStringBytesMaskImprSrc(pathSegmentCharsLength)) - b.WriteString("/{age:int}/end") - paths[i] = b.String() - - b.Reset() - } - - return paths -} - -// Build 1296(=144*9(the available http methods)) routes -// with up to 2*range(15-42)+ 2 named paths lowercase letters -// and 12 request handlers each. -// -// GOCACHE=off && go test -run=XXX -bench=BenchmarkAPIBuilder$ -benchtime=10s -func BenchmarkAPIBuilder(b *testing.B) { - rand.Seed(time.Now().Unix()) - - noOpHandler := func(ctx *context.Context) {} - handlersPerRoute := make(context.Handlers, 12) - for i := 0; i < cap(handlersPerRoute); i++ { - handlersPerRoute[i] = noOpHandler - } - - routesLength := 144 - // i.e /gzhyweumidvelqewrvoyqmzopvuxli/{name:string}/bibrkratnrrhvsjwsxygfwmqwhcstc/{age:int}/end - paths := genPaths(routesLength, 15, 42) - - api := NewAPIBuilder() - requestHandler := NewDefaultHandler(nil, nil) - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < routesLength; i++ { - api.Any(paths[i], handlersPerRoute...) - } - - if err := requestHandler.Build(api); err != nil { - b.Fatal(err) - } - - b.StopTimer() - - b.Logf("%d routes have just builded\n", len(api.GetRoutes())) -} diff --git a/core/router/api_container.go b/core/router/api_container.go index 0504eeb9..5ffd94bd 100644 --- a/core/router/api_container.go +++ b/core/router/api_container.go @@ -3,9 +3,9 @@ package router import ( "net/http" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/hero" - "github.com/kataras/iris/v12/macro" + "github.com/kataras/iris/context" + "github.com/kataras/iris/hero" + "github.com/kataras/iris/macro" ) // APIContainer is a wrapper of a common `Party` featured by Dependency Injection. diff --git a/core/router/fs.go b/core/router/fs.go index a9224293..ce83fe0c 100644 --- a/core/router/fs.go +++ b/core/router/fs.go @@ -19,7 +19,7 @@ import ( "sync" "time" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) const indexName = "/index.html" diff --git a/core/router/handler.go b/core/router/handler.go index 8dd8fafc..18f1fb49 100644 --- a/core/router/handler.go +++ b/core/router/handler.go @@ -7,10 +7,10 @@ import ( "strings" "time" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/errgroup" - "github.com/kataras/iris/v12/core/netutil" - macroHandler "github.com/kataras/iris/v12/macro/handler" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/errgroup" + "github.com/kataras/iris/core/netutil" + macroHandler "github.com/kataras/iris/macro/handler" "github.com/kataras/golog" "github.com/kataras/pio" diff --git a/core/router/handler_execution_rules.go b/core/router/handler_execution_rules.go index 3ea0b069..85ddf903 100644 --- a/core/router/handler_execution_rules.go +++ b/core/router/handler_execution_rules.go @@ -1,7 +1,7 @@ package router import ( - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) // ExecutionRules gives control to the execution of the route handlers outside of the handlers themselves. diff --git a/core/router/handler_execution_rules_test.go b/core/router/handler_execution_rules_test.go deleted file mode 100644 index ae65a800..00000000 --- a/core/router/handler_execution_rules_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package router_test - -import ( - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/router" - "github.com/kataras/iris/v12/httptest" -) - -var ( - finalExecutionRulesResponse = "1234" - - testExecutionResponse = func(t *testing.T, app *iris.Application, path string) { - e := httptest.New(t, app) - e.GET(path).Expect().Status(httptest.StatusOK).Body().Equal(finalExecutionRulesResponse) - } -) - -func writeStringHandler(text string, withNext bool) context.Handler { - return func(ctx *context.Context) { - ctx.WriteString(text) - if withNext { - ctx.Next() - } - } -} - -func TestRouterExecutionRulesForceMain(t *testing.T) { - app := iris.New() - begin := app.Party("/") - begin.SetExecutionRules(router.ExecutionRules{Main: router.ExecutionOptions{Force: true}}) - - // no need of `ctx.Next()` all main handlers should be executed with the Main.Force:True rule. - begin.Get("/", writeStringHandler("12", false), writeStringHandler("3", false), writeStringHandler("4", false)) - - testExecutionResponse(t, app, "/") -} - -func TestRouterExecutionRulesForceBegin(t *testing.T) { - app := iris.New() - begin := app.Party("/begin_force") - begin.SetExecutionRules(router.ExecutionRules{Begin: router.ExecutionOptions{Force: true}}) - - // should execute, begin rule is to force execute them without `ctx.Next()`. - begin.Use(writeStringHandler("1", false)) - begin.Use(writeStringHandler("2", false)) - // begin starts with begin and ends to the main handlers but not last, so this done should not be executed. - begin.Done(writeStringHandler("5", false)) - begin.Get("/", writeStringHandler("3", false), writeStringHandler("4", false)) - - testExecutionResponse(t, app, "/begin_force") -} - -func TestRouterExecutionRulesForceDone(t *testing.T) { - app := iris.New() - done := app.Party("/done_force") - done.SetExecutionRules(router.ExecutionRules{Done: router.ExecutionOptions{Force: true}}) - - // these done should be executed without `ctx.Next()` - done.Done(writeStringHandler("3", false), writeStringHandler("4", false)) - // first with `ctx.Next()`, because Done.Force:True rule will alter the latest of the main handler(s) only. - done.Get("/", writeStringHandler("1", true), writeStringHandler("2", false)) - - // rules should be kept in children. - doneChild := done.Party("/child") - // even if only one, it's the latest, Done.Force:True rule should modify it. - doneChild.Get("/", writeStringHandler("12", false)) - - testExecutionResponse(t, app, "/done_force") - testExecutionResponse(t, app, "/done_force/child") -} - -func TestRouterExecutionRulesShouldNotModifyTheCallersHandlerAndChildrenCanResetExecutionRules(t *testing.T) { - app := iris.New() - app.SetExecutionRules(router.ExecutionRules{Done: router.ExecutionOptions{Force: true}}) - h := writeStringHandler("4", false) - - app.Done(h) - app.Get("/", writeStringHandler("123", false)) - - // remember: the handler stored in var didn't had a `ctx.Next()`, modified its clone above with adding a `ctx.Next()` - // note the "clone" word, the original handler shouldn't be changed. - app.Party("/c").SetExecutionRules(router.ExecutionRules{}).Get("/", h, writeStringHandler("err caller modified!", false)) - - testExecutionResponse(t, app, "/") - - e := httptest.New(t, app) - e.GET("/c").Expect().Status(httptest.StatusOK).Body().Equal("4") // the "should not" should not be written. -} diff --git a/core/router/mime.go b/core/router/mime.go index 1fb50b36..e5e9ff5e 100644 --- a/core/router/mime.go +++ b/core/router/mime.go @@ -4,7 +4,7 @@ import ( "mime" "path/filepath" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) var types = map[string]string{ diff --git a/core/router/party.go b/core/router/party.go index 4051ea49..c1e06591 100644 --- a/core/router/party.go +++ b/core/router/party.go @@ -3,9 +3,9 @@ package router import ( "net/http" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/errgroup" - "github.com/kataras/iris/v12/macro" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/errgroup" + "github.com/kataras/iris/macro" ) // Party is just a group joiner of routes which have the same prefix and share same middleware(s) also. diff --git a/core/router/path.go b/core/router/path.go index 5dbb5239..59dc3c77 100644 --- a/core/router/path.go +++ b/core/router/path.go @@ -6,10 +6,10 @@ import ( "strconv" "strings" - "github.com/kataras/iris/v12/core/netutil" - "github.com/kataras/iris/v12/macro" - "github.com/kataras/iris/v12/macro/interpreter/ast" - "github.com/kataras/iris/v12/macro/interpreter/lexer" + "github.com/kataras/iris/core/netutil" + "github.com/kataras/iris/macro" + "github.com/kataras/iris/macro/interpreter/ast" + "github.com/kataras/iris/macro/interpreter/lexer" ) // Param receives a parameter name prefixed with the ParamStart symbol. diff --git a/core/router/path_test.go b/core/router/path_test.go deleted file mode 100644 index 5e5c6abc..00000000 --- a/core/router/path_test.go +++ /dev/null @@ -1,136 +0,0 @@ -package router - -import ( - "testing" -) - -func TestCleanPath(t *testing.T) { - tests := []struct { - path string - expected string - }{ - { - "/", - "/", - }, - { - "noslashPrefix", - "/noslashPrefix", - }, - { - "slashSuffix/", - "/slashSuffix", - }, - { - "noSlashPrefixAndslashSuffix/", - "/noSlashPrefixAndslashSuffix", - }, - // don't do any clean up inside {}, - // fixes #927. - { - "/total/{year:string regexp(\\d{4})}", - "/total/{year:string regexp(\\d{4})}", - }, - { - "/total/{year:string regexp(\\d{4})}/more", - "/total/{year:string regexp(\\d{4})}/more", - }, - { - "/total/{year:string regexp(\\d{4})}/more/{s:string regexp(\\d{7})}", - "/total/{year:string regexp(\\d{4})}/more/{s:string regexp(\\d{7})}", - }, - { - "/single_no_params", - "/single_no_params", - }, - { - "/single/{id:uint64}", - "/single/{id:uint64}", - }, - } - - for i, tt := range tests { - if expected, got := tt.expected, cleanPath(tt.path); expected != got { - t.Fatalf("[%d] - expected path '%s' but got '%s'", i, expected, got) - } - } -} - -func TestSplitPath(t *testing.T) { - tests := []struct { - path string - expected []string - }{ - { - "/v2/stores/{id:string format(uuid)} /v3", - []string{"/v2/stores/{id:string format(uuid)}", "/v3"}, - }, - { - "/user/{id:uint64} /admin/{id:uint64}", - []string{"/user/{id:uint64}", "/admin/{id:uint64}"}, - }, - { - "/users/{id:int} /admins/{id:int64}", - []string{"/users/{id:int}", "/admins/{id:int64}"}, - }, - { - "/user /admin", - []string{"/user", "/admin"}, - }, - { - "/single_no_params", - []string{"/single_no_params"}, - }, - { - "/single/{id:int}", - []string{"/single/{id:int}"}, - }, - } - - equalSlice := func(s1 []string, s2 []string) bool { - if len(s1) != len(s2) { - return false - } - - for i := range s1 { - if s2[i] != s1[i] { - return false - } - } - - return true - } - - for i, tt := range tests { - paths := splitPath(tt.path) - if expected, got := tt.expected, paths; !equalSlice(expected, got) { - t.Fatalf("[%d] - expected paths '%#v' but got '%#v'", i, expected, got) - } - } -} - -func TestSplitSubdomainAndPath(t *testing.T) { - tests := []struct { - original string - subdomain string - path string - }{ - {"admin./users/42", "admin.", "/users/42"}, - {"static.", "static.", "/"}, - {"static./" + WildcardFileParam(), "static.", "/" + WildcardFileParam()}, - {"//api/users\\42", "", "/api/users/42"}, - {"admin./users//42", "admin.", "/users/42"}, - {"*./users/42/", "*.", "/users/42"}, - } - - for i, tt := range tests { - subdomain, path := splitSubdomainAndPath(tt.original) - - if expected, got := tt.subdomain, subdomain; expected != got { - t.Fatalf("[%d] - expected subdomain '%s' but got '%s'", i, expected, got) - } - if expected, got := tt.path, path; expected != got { - t.Fatalf("[%d] - expected path '%s' but got '%s'", i, expected, got) - } - } -} diff --git a/core/router/route.go b/core/router/route.go index 6b64b1d5..8e31c5ea 100644 --- a/core/router/route.go +++ b/core/router/route.go @@ -8,9 +8,9 @@ import ( "strings" "time" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/macro" - "github.com/kataras/iris/v12/macro/handler" + "github.com/kataras/iris/context" + "github.com/kataras/iris/macro" + "github.com/kataras/iris/macro/handler" "github.com/kataras/pio" ) diff --git a/core/router/route_register_rule_test.go b/core/router/route_register_rule_test.go deleted file mode 100644 index 1a581ac2..00000000 --- a/core/router/route_register_rule_test.go +++ /dev/null @@ -1,111 +0,0 @@ -package router_test - -import ( - "reflect" - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/core/router" - "github.com/kataras/iris/v12/httptest" -) - -func TestRegisterRule(t *testing.T) { - app := iris.New() - v1 := app.Party("/v1") - v1.SetRegisterRule(iris.RouteSkip) - - getHandler := func(ctx iris.Context) { - ctx.Writef("[get] %s", ctx.Method()) - } - - anyHandler := func(ctx iris.Context) { - ctx.Writef("[any] %s", ctx.Method()) - } - - getRoute := v1.Get("/", getHandler) - v1.Any("/", anyHandler) - if route := v1.Get("/", getHandler); !reflect.DeepEqual(route, getRoute) { - t.Fatalf("expected route to be equal with the original get route") - } - - // test RouteSkip. - e := httptest.New(t, app, httptest.LogLevel("error")) - testRegisterRule(e, "[get] GET") - - // test RouteOverride (default behavior). - v1.SetRegisterRule(iris.RouteOverride) - v1.Any("/", anyHandler) - app.RefreshRouter() - testRegisterRule(e, "[any] GET") - - // test RouteError. - v1.SetRegisterRule(iris.RouteError) - if route := v1.Get("/", getHandler); route != nil { - t.Fatalf("expected duplicated route, with RouteError rule, to be nil but got: %#+v", route) - } - if expected, got := 1, len(v1.GetReporter().Errors); expected != got { - t.Fatalf("expected api builder's errors length to be: %d but got: %d", expected, got) - } -} - -func testRegisterRule(e *httptest.Expect, expectedGetBody string) { - for _, method := range router.AllMethods { - tt := e.Request(method, "/v1").Expect().Status(httptest.StatusOK).Body() - if method == iris.MethodGet { - tt.Equal(expectedGetBody) - } else { - tt.Equal("[any] " + method) - } - } -} - -func TestRegisterRuleOverlap(t *testing.T) { - app := iris.New() - // TODO(@kataras) the overlapping does not work per-party yet, - // it just checks compares from the total app's routes (which is the best possible action to do - // because MVC applications can be separated into different parties too?). - usersRouter := app.Party("/users") - usersRouter.SetRegisterRule(iris.RouteOverlap) - - // second handler will be executed, status will be reset-ed as well, - // stop without data written. - usersRouter.Get("/", func(ctx iris.Context) { - ctx.StopWithStatus(iris.StatusUnauthorized) - }) - usersRouter.Get("/", func(ctx iris.Context) { - ctx.WriteString("data") - }) - - // first handler will be executed, no stop called. - usersRouter.Get("/p1", func(ctx iris.Context) { - ctx.StatusCode(iris.StatusUnauthorized) - }) - usersRouter.Get("/p1", func(ctx iris.Context) { - ctx.WriteString("not written") - }) - - // first handler will be executed, stop but with data sent on default writer - // (body sent cannot be reset-ed here). - usersRouter.Get("/p2", func(ctx iris.Context) { - ctx.StopWithText(iris.StatusUnauthorized, "no access") - }) - usersRouter.Get("/p2", func(ctx iris.Context) { - ctx.WriteString("not written") - }) - - // second will be executed, response can be reset-ed on recording. - usersRouter.Get("/p3", func(ctx iris.Context) { - ctx.Record() - ctx.StopWithText(iris.StatusUnauthorized, "no access") - }) - usersRouter.Get("/p3", func(ctx iris.Context) { - ctx.WriteString("p3 data") - }) - - e := httptest.New(t, app) - - e.GET("/users").Expect().Status(httptest.StatusOK).Body().Equal("data") - e.GET("/users/p1").Expect().Status(httptest.StatusUnauthorized).Body().Equal("Unauthorized") - e.GET("/users/p2").Expect().Status(httptest.StatusUnauthorized).Body().Equal("no access") - e.GET("/users/p3").Expect().Status(httptest.StatusOK).Body().Equal("p3 data") -} diff --git a/core/router/route_test.go b/core/router/route_test.go deleted file mode 100644 index f0b989ca..00000000 --- a/core/router/route_test.go +++ /dev/null @@ -1,56 +0,0 @@ -// white-box testing - -package router - -import ( - "testing" - - "github.com/kataras/iris/v12/macro" -) - -func TestRouteStaticPath(t *testing.T) { - tests := []struct { - tmpl string - static string - }{ - { - tmpl: "/files/{file:path}", - static: "/files", - }, - { - tmpl: "/path", - static: "/path", - }, - { - tmpl: "/path/segment", - static: "/path/segment", - }, - { - tmpl: "/path/segment/{n:int}", - static: "/path/segment", - }, - { - tmpl: "/path/{n:uint64}/{n:int}", - static: "/path", - }, - { - tmpl: "/path/{n:uint64}/static", - static: "/path", - }, - { - tmpl: "/{name}", - static: "/", - }, - { - tmpl: "/", - static: "/", - }, - } - - for i, tt := range tests { - route := Route{tmpl: macro.Template{Src: tt.tmpl}} - if expected, got := tt.static, route.StaticPath(); expected != got { - t.Fatalf("[%d:%s] expected static path to be: '%s' but got: '%s'", i, tt.tmpl, expected, got) - } - } -} diff --git a/core/router/router.go b/core/router/router.go index 2fd9071a..6857575f 100644 --- a/core/router/router.go +++ b/core/router/router.go @@ -7,7 +7,7 @@ import ( "strings" "sync" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" "github.com/schollz/closestmatch" ) diff --git a/core/router/router_handlers_order_test.go b/core/router/router_handlers_order_test.go deleted file mode 100644 index 057fbdcf..00000000 --- a/core/router/router_handlers_order_test.go +++ /dev/null @@ -1,287 +0,0 @@ -// black-box testing -// -// see _examples/routing/main_test.go for the most common router tests that you may want to see, -// this is a test which makes sure that the APIBuilder's `UseGlobal`, `Use` and `Done` functions are -// working as expected. - -package router_test - -import ( - "fmt" - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/httptest" -) - -// test registering of below handlers -// with a different order but the route's final -// response should be the same at all cases. -var ( - writeHandler = func(s string) iris.Handler { - return func(ctx iris.Context) { - ctx.WriteString(s) - ctx.Next() - } - } - - mainResponse = "main" - mainHandler = writeHandler(mainResponse) - - firstUseResponse = "use1" - firstUseHandler = writeHandler(firstUseResponse) - - secondUseResponse = "use2" - secondUseHandler = writeHandler(secondUseResponse) - - firstUseRouterResponse = "userouter1" - // Use inline handler, no the `writeHandler`, - // because it will be overriden by `secondUseRouterHandler` otherwise, - // look `UseRouter:context.UpsertHandlers` for more. - firstUseRouterHandler = func(ctx iris.Context) { - ctx.WriteString(firstUseRouterResponse) - ctx.Next() - } - - secondUseRouterResponse = "userouter2" - secondUseRouterHandler = writeHandler(secondUseRouterResponse) - - firstUseGlobalResponse = "useglobal1" - firstUseGlobalHandler = writeHandler(firstUseGlobalResponse) - - secondUseGlobalResponse = "useglobal2" - secondUseGlobalHandler = writeHandler(secondUseGlobalResponse) - - firstDoneResponse = "done1" - firstDoneHandler = writeHandler(firstDoneResponse) - - secondDoneResponse = "done2" - secondDoneHandler = func(ctx iris.Context) { - ctx.WriteString(secondDoneResponse) - } - - finalResponse = firstUseRouterResponse + secondUseRouterResponse + firstUseGlobalResponse + secondUseGlobalResponse + - firstUseResponse + secondUseResponse + mainResponse + firstDoneResponse + secondDoneResponse - - testResponse = func(t *testing.T, app *iris.Application, path string) { - t.Helper() - - e := httptest.New(t, app) - e.GET(path).Expect().Status(httptest.StatusOK).Body().Equal(finalResponse) - } -) - -func TestMiddlewareByRouteDef(t *testing.T) { - app := iris.New() - app.UseRouter(firstUseRouterHandler) - app.UseRouter(secondUseRouterHandler) - - app.Get("/mypath", firstUseGlobalHandler, secondUseGlobalHandler, firstUseHandler, secondUseHandler, - mainHandler, firstDoneHandler, secondDoneHandler) - - testResponse(t, app, "/mypath") -} - -func TestMiddlewareByUseAndDoneDef(t *testing.T) { - app := iris.New() - app.UseRouter(firstUseRouterHandler, secondUseRouterHandler) - app.Use(firstUseGlobalHandler, secondUseGlobalHandler, firstUseHandler, secondUseHandler) - app.Done(firstDoneHandler, secondDoneHandler) - - app.Get("/mypath", mainHandler) - - testResponse(t, app, "/mypath") -} - -func TestMiddlewareByUseUseGlobalAndDoneDef(t *testing.T) { - app := iris.New() - - app.Use(firstUseHandler, secondUseHandler) - // if failed then UseGlobal didnt' registered these handlers even before the - // existing middleware. - app.UseGlobal(firstUseGlobalHandler, secondUseGlobalHandler) - app.Done(firstDoneHandler, secondDoneHandler) - - app.UseRouter(firstUseRouterHandler, secondUseRouterHandler) - app.Get("/mypath", mainHandler) - - testResponse(t, app, "/mypath") -} - -func TestMiddlewareByUseDoneAndUseGlobalDef(t *testing.T) { - app := iris.New() - app.UseRouter(firstUseRouterHandler, secondUseRouterHandler) - - app.Use(firstUseHandler, secondUseHandler) - app.Done(firstDoneHandler, secondDoneHandler) - - app.Get("/mypath", mainHandler) - - // if failed then UseGlobal was unable to - // prepend these handlers to the route was registered before - // OR - // when order failed because these should be executed in order, first the firstUseGlobalHandler, - // because they are the same type (global begin handlers) - app.UseGlobal(firstUseGlobalHandler) - app.UseGlobal(secondUseGlobalHandler) - - testResponse(t, app, "/mypath") -} - -func TestMiddlewareByUseGlobalUseAndDoneGlobalDef(t *testing.T) { - app := iris.New() - app.UseRouter(firstUseRouterHandler) - app.UseRouter(secondUseRouterHandler) - - app.UseGlobal(firstUseGlobalHandler) - app.UseGlobal(secondUseGlobalHandler) - app.Use(firstUseHandler, secondUseHandler) - - app.Get("/mypath", mainHandler) - - app.DoneGlobal(firstDoneHandler, secondDoneHandler) - - testResponse(t, app, "/mypath") -} - -func TestMiddlewareByDoneUseAndUseGlobalDef(t *testing.T) { - app := iris.New() - app.UseRouter(firstUseRouterHandler, secondUseRouterHandler) - app.Done(firstDoneHandler, secondDoneHandler) - - app.Use(firstUseHandler, secondUseHandler) - - app.Get("/mypath", mainHandler) - - app.UseGlobal(firstUseGlobalHandler) - app.UseGlobal(secondUseGlobalHandler) - - testResponse(t, app, "/mypath") -} - -func TestUseRouterStopExecution(t *testing.T) { - app := iris.New() - app.UseRouter(func(ctx iris.Context) { - ctx.WriteString("stop") - // no ctx.Next, so the router has not even the chance to work. - }) - app.Get("/", writeHandler("index")) - - e := httptest.New(t, app) - e.GET("/").Expect().Status(iris.StatusOK).Body().Equal("stop") - - app = iris.New() - app.OnErrorCode(iris.StatusForbidden, func(ctx iris.Context) { - ctx.Writef("err: %v", ctx.GetErr()) - }) - app.UseRouter(func(ctx iris.Context) { - ctx.StopWithPlainError(iris.StatusForbidden, fmt.Errorf("custom error")) - // stopped but not data written yet, the error code handler - // should be responsible of it (use StopWithError to write and close). - }) - app.Get("/", writeHandler("index")) - - e = httptest.New(t, app) - e.GET("/").Expect().Status(iris.StatusForbidden).Body().Equal("err: custom error") -} - -func TestUseRouterParentDisallow(t *testing.T) { - const expectedResponse = "no_userouter_allowed" - - app := iris.New() - app.UseRouter(func(ctx iris.Context) { - ctx.WriteString("always") - ctx.Next() - }) - app.Get("/index", func(ctx iris.Context) { - ctx.WriteString(expectedResponse) - }) - - app.SetPartyMatcher(func(p iris.Party, ctx iris.Context) bool { - // modifies the PartyMatcher to not match any UseRouter, - // tests should receive the handlers response alone. - return false - }) - - app.PartyFunc("/", func(p iris.Party) { // it's the same instance of app. - p.UseRouter(func(ctx iris.Context) { - ctx.WriteString("_2") - ctx.Next() - }) - p.Get("/", func(ctx iris.Context) { - ctx.WriteString(expectedResponse) - }) - }) - - app.PartyFunc("/user", func(p iris.Party) { - p.UseRouter(func(ctx iris.Context) { - ctx.WriteString("_3") - ctx.Next() - }) - - p.Get("/", func(ctx iris.Context) { - ctx.WriteString(expectedResponse) - }) - }) - - e := httptest.New(t, app) - e.GET("/index").Expect().Status(iris.StatusOK).Body().Equal(expectedResponse) - e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(expectedResponse) - e.GET("/user").Expect().Status(iris.StatusOK).Body().Equal(expectedResponse) -} - -func TestUseRouterSubdomains(t *testing.T) { - app := iris.New() - app.UseRouter(func(ctx iris.Context) { - if ctx.Subdomain() == "old" { - ctx.Next() // call the router, do not write. - return - } - - // if we write here, it will always give 200 OK, - // even on not registered routes, that's the point at the end, - // full control here when we need it. - ctx.WriteString("always_") - ctx.Next() - }) - - adminAPI := app.Subdomain("admin") - adminAPI.UseRouter(func(ctx iris.Context) { - ctx.WriteString("admin always_") - ctx.Next() - }) - adminAPI.Get("/", func(ctx iris.Context) { - ctx.WriteString("admin") - }) - - adminControlAPI := adminAPI.Subdomain("control") - adminControlAPI.UseRouter(func(ctx iris.Context) { - ctx.WriteString("control admin always_") - ctx.Next() - }) - adminControlAPI.Get("/", func(ctx iris.Context) { - ctx.WriteString("control admin") - }) - - oldAPI := app.Subdomain("old") - oldAPI.Get("/", func(ctx iris.Context) { - ctx.WriteString("chat") - }) - - e := httptest.New(t, app, httptest.URL("http://example.com")) - e.GET("/notfound").Expect().Status(iris.StatusOK).Body().Equal("always_") - - e.GET("/").WithURL("http://admin.example.com").Expect().Status(iris.StatusOK).Body(). - Equal("always_admin always_admin") - - e.GET("/").WithURL("http://control.admin.example.com").Expect().Status(iris.StatusOK).Body(). - Equal("always_admin always_control admin always_control admin") - - // It has a route, and use router just proceeds to the router. - e.GET("/").WithURL("http://old.example.com").Expect().Status(iris.StatusOK).Body(). - Equal("chat") - // this is not a registered path, should fire 404, the UseRouter does not write - // anything to the response writer, so the router has control over it. - e.GET("/notfound").WithURL("http://old.example.com").Expect().Status(iris.StatusNotFound).Body(). - Equal("Not Found") -} diff --git a/core/router/router_subdomain_redirect_wrapper.go b/core/router/router_subdomain_redirect_wrapper.go index 37a7b615..99bec727 100644 --- a/core/router/router_subdomain_redirect_wrapper.go +++ b/core/router/router_subdomain_redirect_wrapper.go @@ -4,8 +4,8 @@ import ( "net/http" "strings" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/netutil" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/netutil" ) type subdomainRedirectWrapper struct { diff --git a/core/router/router_test.go b/core/router/router_test.go deleted file mode 100644 index 535cb7bd..00000000 --- a/core/router/router_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package router_test - -import ( - "net/http" - "strings" - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/httptest" -) - -func TestRouteExists(t *testing.T) { - // build the api - app := iris.New() - emptyHandler := func(*context.Context) {} - - // setup the tested routes - app.Handle("GET", "/route-exists", emptyHandler) - app.Handle("POST", "/route-with-param/{param}", emptyHandler) - - // check RouteExists - app.Handle("GET", "/route-test", func(ctx *context.Context) { - if ctx.RouteExists("GET", "/route-not-exists") { - t.Error("Route with path should not exists") - } - - if ctx.RouteExists("POST", "/route-exists") { - t.Error("Route with method should not exists") - } - - if !ctx.RouteExists("GET", "/route-exists") { - t.Error("Route 1 should exists") - } - - if !ctx.RouteExists("POST", "/route-with-param/a-param") { - t.Error("Route 2 should exists") - } - }) - - // run the tests - httptest.New(t, app, httptest.Debug(false)).Request("GET", "/route-test").Expect().Status(iris.StatusOK) -} - -func TestLowercaseRouting(t *testing.T) { - app := iris.New() - app.WrapRouter(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - // test bottom to begin wrapper, the last ones should execute first. - // The ones that are registered at `Build` state, after this `WrapRouter` call. - // So path should be already lowecased. - if expected, got := strings.ToLower(r.URL.Path), r.URL.Path; expected != got { - t.Fatalf("expected path: %s but got: %s", expected, got) - } - next(w, r) - }) - - h := func(ctx iris.Context) { ctx.WriteString(ctx.Path()) } - - // Register routes. - tests := []string{"/", "/lowercase", "/UPPERCASE", "/Title", "/m1xEd2"} - for _, tt := range tests { - app.Get(tt, h) - } - - app.Configure(iris.WithLowercaseRouting) - // Test routes. - e := httptest.New(t, app) - for _, tt := range tests { - s := strings.ToLower(tt) - e.GET(tt).Expect().Status(httptest.StatusOK).Body().Equal(s) - e.GET(s).Expect().Status(httptest.StatusOK).Body().Equal(s) - e.GET(strings.ToUpper(tt)).Expect().Status(httptest.StatusOK).Body().Equal(s) - } -} diff --git a/core/router/router_wildcard_root_test.go b/core/router/router_wildcard_root_test.go deleted file mode 100644 index becfc398..00000000 --- a/core/router/router_wildcard_root_test.go +++ /dev/null @@ -1,198 +0,0 @@ -// black-box testing -// -// see _examples/routing/main_test.go for the most common router tests that you may want to see, -// this is a test for the new feature that I just coded: wildcard "/{p:path}" on root without conflicts - -package router_test - -import ( - "net/http" - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/httptest" -) - -const ( - same_as_request_path = "same" - from_status_code = "from" - staticPathPrefixBody = "from the static path: " - prefix_static_path_following_by_request_path = "prefix_same" -) - -type testRouteRequest struct { - method string - subdomain string - path string - expectedStatusCode int - expectedBody string -} - -type testRoute struct { - method string - path string - handler context.Handler - requests []testRouteRequest -} - -var h = func(ctx *context.Context) { - ctx.WriteString(ctx.Path()) -} - -var h2 = func(ctx *context.Context) { - ctx.StatusCode(iris.StatusForbidden) // ! 200 but send the body as expected, - // we need that kind of behavior to determinate which handler is executed for routes that - // both having wildcard path but first one is registered on root level. - ctx.WriteString(ctx.Path()) -} - -func h3(ctx *context.Context) { - ctx.Writef(staticPathPrefixBody + ctx.Path()) -} - -func TestRouterWildcardDifferentPrefixPath(t *testing.T) { - tt := []testRoute{ - {"GET", "/s/{p:path}", h, []testRouteRequest{ - {"GET", "", "/s/that/is/wildcard", iris.StatusOK, same_as_request_path}, - {"GET", "", "/s/ok", iris.StatusOK, same_as_request_path}, - }}, - {"GET", "/som/{p:path}", h, []testRouteRequest{ - {"GET", "", "/som/that/is/wildcard", iris.StatusOK, same_as_request_path}, - {"GET", "", "/som/ok", iris.StatusOK, same_as_request_path}, - }}, - {"GET", "/some/{p:path}", h, []testRouteRequest{ - {"GET", "", "/some/that/is/wildcard", iris.StatusOK, same_as_request_path}, - {"GET", "", "/some1/that/is/wildcard", iris.StatusNotFound, from_status_code}, - }}, - } - - testTheRoutes(t, tt, false) -} - -func TestRouterWildcardAndStatic(t *testing.T) { - tt := []testRoute{ - {"GET", "/some/{p:path}", h2, []testRouteRequest{ - {"GET", "", "/some/that/is/wildcard", iris.StatusForbidden, same_as_request_path}, - {"GET", "", "/some/did", iris.StatusForbidden, same_as_request_path}, - {"GET", "", "/some1/that/is/wildcard", iris.StatusNotFound, from_status_code}, - }}, - {"GET", "/some/static", h, []testRouteRequest{ - {"GET", "", "/some/static", iris.StatusOK, same_as_request_path}, - }}, - - {"GET", "/s/{p:path}", h2, []testRouteRequest{ - {"GET", "", "/s/that/is/wildcard", iris.StatusForbidden, same_as_request_path}, - {"GET", "", "/s/did", iris.StatusForbidden, same_as_request_path}, - {"GET", "", "/s1/that/is/wildcard", iris.StatusNotFound, from_status_code}, - }}, - {"GET", "/s/static", h, []testRouteRequest{ - {"GET", "", "/s/static", iris.StatusOK, same_as_request_path}, - }}, - } - - testTheRoutes(t, tt, false) -} - -func TestRouterWildcardRootMany(t *testing.T) { - tt := []testRoute{ - // all routes will be handlded by "h" because we added wildcard to root, - // this feature is very important and can remove noumerous of previous hacks on our apps. - {"GET", "/{p:path}", h, []testRouteRequest{ - {"GET", "", "/this/is/wildcard/on/root", iris.StatusOK, same_as_request_path}, - }}, // mormally, order matters, root should be registered at last - // but we change the front level order algorithm to put last these automatically - // see handler.go - {"GET", "/some/{p:path}", h2, []testRouteRequest{ - {"GET", "", "/some/that/is/wildcard", iris.StatusForbidden, same_as_request_path}, - {"GET", "", "/some/did", iris.StatusForbidden, same_as_request_path}, - }}, - {"GET", "/some/static", h, []testRouteRequest{ - {"GET", "", "/some/static", iris.StatusOK, same_as_request_path}, - }}, - {"GET", "/some1", h, []testRouteRequest{ - {"GET", "", "/some1", iris.StatusOK, same_as_request_path}, - // this will show up because of the first wildcard, as we wanted to do. - {"GET", "", "/some1/that/is/wildcard", iris.StatusOK, same_as_request_path}, - }}, - } - - testTheRoutes(t, tt, false) -} - -func TestRouterWildcardRootManyAndRootStatic(t *testing.T) { - tt := []testRoute{ - // routes that may return 404 will be handled by the below route ("h" handler) because we added wildcard to root, - // this feature is very important and can remove noumerous of previous hacks on our apps. - // - // Static paths and parameters have priority over wildcard, all three types can be registered in the same path prefix. - // - // Remember, all of those routes are registered don't be tricked by the visual appearance of the below test blocks. - {"GET", "/{p:path}", h, []testRouteRequest{ - {"GET", "", "/other2almost/some", iris.StatusOK, same_as_request_path}, - }}, - {"GET", "/static/{p:path}", h, []testRouteRequest{ - {"GET", "", "/static", iris.StatusOK, same_as_request_path}, // HERE<- IF NOT FOUND THEN BACKWARDS TO WILDCARD IF THERE IS ONE, HMM. - {"GET", "", "/static/something/here", iris.StatusOK, same_as_request_path}, - }}, - {"GET", "/", h, []testRouteRequest{ - {"GET", "", "/", iris.StatusOK, same_as_request_path}, - }}, - {"GET", "/other/{paramother:path}", h2, []testRouteRequest{ - // OK and not h2 because of the root wildcard. - {"GET", "", "/other", iris.StatusOK, same_as_request_path}, - {"GET", "", "/other/wildcard", iris.StatusForbidden, same_as_request_path}, - {"GET", "", "/other/wildcard/here", iris.StatusForbidden, same_as_request_path}, - }}, - {"GET", "/other2/{paramothersecond:path}", h2, []testRouteRequest{ - {"GET", "", "/other2/wildcard", iris.StatusForbidden, same_as_request_path}, - {"GET", "", "/other2/more/than/one/path/parts", iris.StatusForbidden, same_as_request_path}, - }}, - {"GET", "/other2/static", h3, []testRouteRequest{ - {"GET", "", "/other2/static", iris.StatusOK, prefix_static_path_following_by_request_path}, - // h2(Forbiddenn) instead of h3 OK because it will be handled by the /other2/{paramothersecond:path}'s handler which gives 403. - {"GET", "", "/other2/staticed", iris.StatusForbidden, same_as_request_path}, - }}, - } - - testTheRoutes(t, tt, false) -} - -func testTheRoutes(t *testing.T, tests []testRoute, debug bool) { - // build the api - app := iris.New() - for _, tt := range tests { - app.Handle(tt.method, tt.path, tt.handler) - } - - // setup the test suite - e := httptest.New(t, app, httptest.Debug(debug)) - - // run the tests - for _, tt := range tests { - for _, req := range tt.requests { - // t.Logf("req: %s:%s\n", tt.method, tt.path) - method := req.method - if method == "" { - method = tt.method - } - ex := e.Request(method, req.path) - if req.subdomain != "" { - ex.WithURL("http://" + req.subdomain + ".localhost:8080") - } - - expectedBody := req.expectedBody - if req.expectedBody == same_as_request_path { - expectedBody = req.path - } - if req.expectedBody == from_status_code { - expectedBody = http.StatusText(req.expectedStatusCode) - } - if req.expectedBody == prefix_static_path_following_by_request_path { - expectedBody = staticPathPrefixBody + req.path - } - - ex.Expect().Status(req.expectedStatusCode).Body().Equal(expectedBody) - } - } -} diff --git a/core/router/router_wrapper_test.go b/core/router/router_wrapper_test.go deleted file mode 100644 index a6d6d2d3..00000000 --- a/core/router/router_wrapper_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package router - -import ( - "bytes" - "net/http" - "net/http/httptest" - "testing" -) - -func TestMakeWrapperFunc(t *testing.T) { - var ( - firstBody = []byte("1") - secondBody = []byte("2") - mainBody = []byte("3") - expectedBody = append(firstBody, append(secondBody, mainBody...)...) - ) - - pre := func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - w.Header().Set("X-Custom", "data") - next(w, r) - } - - first := func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - w.Write(firstBody) - next(w, r) - } - - second := func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - w.Write(secondBody) - next(w, r) - } - - mainHandler := func(w http.ResponseWriter, r *http.Request) { - w.Write(mainBody) - } - - wrapper := makeWrapperFunc(second, first) - wrapper = makeWrapperFunc(wrapper, pre) - - w := httptest.NewRecorder() - r := httptest.NewRequest("GET", "https://iris-go.com", nil) - wrapper(w, r, mainHandler) - - if got := w.Body.Bytes(); !bytes.Equal(expectedBody, got) { - t.Fatalf("expected boy: %s but got: %s", string(expectedBody), string(got)) - } - - if expected, got := "data", w.Header().Get("X-Custom"); expected != got { - t.Fatalf("expected x-custom header: %s but got: %s", expected, got) - } -} diff --git a/core/router/status_test.go b/core/router/status_test.go deleted file mode 100644 index 8a4a109f..00000000 --- a/core/router/status_test.go +++ /dev/null @@ -1,160 +0,0 @@ -// black-box testing -package router_test - -import ( - "bytes" - "net/http" - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - - "github.com/kataras/iris/v12/httptest" -) - -var defaultErrHandler = func(ctx *context.Context) { - text := http.StatusText(ctx.GetStatusCode()) - ctx.WriteString(text) -} - -func TestOnAnyErrorCode(t *testing.T) { - app := iris.New() - app.Configure(iris.WithFireMethodNotAllowed) - - buff := &bytes.Buffer{} - expectedPrintBeforeExecuteErr := "printed before error" - - // with a middleware - app.OnAnyErrorCode(func(ctx *context.Context) { - buff.WriteString(expectedPrintBeforeExecuteErr) - ctx.Next() - }, defaultErrHandler) - - expectedFoundResponse := "found" - app.Get("/found", func(ctx *context.Context) { - ctx.WriteString(expectedFoundResponse) - }) - - expected407 := "this should be sent, we manage the response response by ourselves" - app.Get("/407", func(ctx *context.Context) { - ctx.Record() - ctx.WriteString(expected407) - ctx.StatusCode(iris.StatusProxyAuthRequired) - }) - - e := httptest.New(t, app) - - e.GET("/found").Expect().Status(iris.StatusOK). - Body().Equal(expectedFoundResponse) - - e.GET("/notfound").Expect().Status(iris.StatusNotFound). - Body().Equal(http.StatusText(iris.StatusNotFound)) - - checkAndClearBuf(t, buff, expectedPrintBeforeExecuteErr) - - e.POST("/found").Expect().Status(iris.StatusMethodNotAllowed). - Body().Equal(http.StatusText(iris.StatusMethodNotAllowed)) - - checkAndClearBuf(t, buff, expectedPrintBeforeExecuteErr) - - e.GET("/407").Expect().Status(iris.StatusProxyAuthRequired). - Body().Equal(expected407) - - // Test Configuration.ResetOnFireErrorCode. - app2 := iris.New() - app2.Configure(iris.WithResetOnFireErrorCode) - - app2.OnAnyErrorCode(func(ctx *context.Context) { - buff.WriteString(expectedPrintBeforeExecuteErr) - ctx.Next() - }, defaultErrHandler) - - app2.Get("/406", func(ctx *context.Context) { - ctx.Record() - ctx.WriteString("this should not be sent, only status text will be sent") - ctx.WriteString("the handler can handle 'rollback' of the text when error code fired because of the recorder") - ctx.StatusCode(iris.StatusNotAcceptable) - }) - - httptest.New(t, app2).GET("/406").Expect().Status(iris.StatusNotAcceptable). - Body().Equal(http.StatusText(iris.StatusNotAcceptable)) - - checkAndClearBuf(t, buff, expectedPrintBeforeExecuteErr) -} - -func checkAndClearBuf(t *testing.T, buff *bytes.Buffer, expected string) { - t.Helper() - - if got := buff.String(); got != expected { - t.Fatalf("expected middleware to run before the error handler, expected: '%s' but got: '%s'", expected, got) - } - - buff.Reset() -} - -func TestPartyOnErrorCode(t *testing.T) { - app := iris.New() - app.Configure(iris.WithFireMethodNotAllowed) - - globalNotFoundResponse := "custom not found" - app.OnErrorCode(iris.StatusNotFound, func(ctx iris.Context) { - ctx.WriteString(globalNotFoundResponse) - }) - - globalMethodNotAllowedResponse := "global: method not allowed" - app.OnErrorCode(iris.StatusMethodNotAllowed, func(ctx iris.Context) { - ctx.WriteString(globalMethodNotAllowedResponse) - }) - - app.Get("/path", h) - - usersResponse := "users: method allowed" - users := app.Party("/users") - users.OnErrorCode(iris.StatusMethodNotAllowed, func(ctx iris.Context) { - ctx.WriteString(usersResponse) - }) - users.Get("/", h) - write400 := func(ctx iris.Context) { ctx.StatusCode(iris.StatusBadRequest) } - // test setting the error code from a handler. - users.Get("/badrequest", write400) - - usersuserResponse := "users:user: method allowed" - user := users.Party("/{id:int}") - user.OnErrorCode(iris.StatusMethodNotAllowed, func(ctx iris.Context) { - ctx.WriteString(usersuserResponse) - }) - usersuserNotFoundResponse := "users:user: not found" - user.OnErrorCode(iris.StatusNotFound, func(ctx iris.Context) { - ctx.WriteString(usersuserNotFoundResponse) - }) - user.Get("/", h) - user.Get("/ab/badrequest", write400) - - friends := users.Party("/friends") - friends.Get("/{id:int}", h) - - e := httptest.New(t, app) - - e.GET("/notfound").Expect().Status(iris.StatusNotFound).Body().Equal(globalNotFoundResponse) - e.POST("/path").Expect().Status(iris.StatusMethodNotAllowed).Body().Equal(globalMethodNotAllowedResponse) - e.GET("/path").Expect().Status(iris.StatusOK).Body().Equal("/path") - - e.POST("/users").Expect().Status(iris.StatusMethodNotAllowed). - Body().Equal(usersResponse) - - e.POST("/users/42").Expect().Status(iris.StatusMethodNotAllowed). - Body().Equal(usersuserResponse) - - e.GET("/users/42").Expect().Status(iris.StatusOK). - Body().Equal("/users/42") - e.GET("/users/ab").Expect().Status(iris.StatusNotFound).Body().Equal(usersuserNotFoundResponse) - // inherit the parent. - e.GET("/users/42/friends/dsa").Expect().Status(iris.StatusNotFound).Body().Equal(usersuserNotFoundResponse) - - // if not registered to the party, then the root is taking action. - e.GET("/users/42/ab/badrequest").Expect().Status(iris.StatusBadRequest).Body().Equal(http.StatusText(iris.StatusBadRequest)) - - // if not registered to the party, and not in root, then just write the status text (fallback behavior) - e.GET("/users/badrequest").Expect().Status(iris.StatusBadRequest). - Body().Equal(http.StatusText(iris.StatusBadRequest)) -} diff --git a/core/router/trie.go b/core/router/trie.go index a22dc769..0ebde8cf 100644 --- a/core/router/trie.go +++ b/core/router/trie.go @@ -3,7 +3,7 @@ package router import ( "strings" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) const ( diff --git a/doc.go b/doc.go deleted file mode 100644 index db3ee4b9..00000000 --- a/doc.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2017-2020 The Iris Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Iris nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -/* -Package iris implements the highest realistic performance, easy to learn Go web framework. -Iris provides a beautifully expressive and easy to use foundation for your next website, API, or distributed app. -Low-level handlers compatible with `net/http` and high-level fastest MVC implementation and handlers dependency injection. -Easy to learn for new gophers and advanced features for experienced, it goes as far as you dive into it! - -Source code and other details for the project are available at GitHub: - - https://github.com/kataras/iris - -Current Version - -12.2.0 - -Installation - -The only requirement is the Go Programming Language, at least version 1.13. - - $ go get github.com/kataras/iris/v12@latest - -Wiki: - - https://github.com/kataras/iris/wiki - -Examples: - - https://github.com/kataras/iris/tree/master/_examples - -Middleware: - - https://github.com/kataras/iris/tree/master/middleware - https://github.com/iris-contrib/middleware - -Home Page: - - https://iris-go.com - -*/ -package iris diff --git a/go.mod b/go.mod index c77486e4..53b1256c 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/kataras/iris/v12 +module github.com/kataras/iris go 1.14 diff --git a/hero/binding.go b/hero/binding.go index 18620cc3..7c83d0c4 100644 --- a/hero/binding.go +++ b/hero/binding.go @@ -5,7 +5,7 @@ import ( "reflect" "sort" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) // binding contains the Dependency and the Input, it's the result of a function or struct + dependencies. diff --git a/hero/binding_test.go b/hero/binding_test.go deleted file mode 100644 index 40d05c52..00000000 --- a/hero/binding_test.go +++ /dev/null @@ -1,548 +0,0 @@ -package hero - -import ( - stdContext "context" - "fmt" - "net/http" - "reflect" - "testing" - "time" - - "github.com/kataras/golog" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/sessions" -) - -var ( - stdContextTyp = reflect.TypeOf((*stdContext.Context)(nil)).Elem() - sessionTyp = reflect.TypeOf((*sessions.Session)(nil)) - timeTyp = reflect.TypeOf((*time.Time)(nil)).Elem() - mapStringsTyp = reflect.TypeOf(map[string][]string{}) -) - -func contextBinding(index int) *binding { - return &binding{ - Dependency: BuiltinDependencies[0], - Input: &Input{Type: BuiltinDependencies[0].DestType, Index: index}, - } -} - -func TestGetBindingsForFunc(t *testing.T) { - type ( - testResponse struct { - Name string `json:"name"` - } - - testRequest struct { - Email string `json:"email"` - } - - testRequest2 struct { - // normally a body can't have two requests but let's test it. - Age int `json:"age"` - } - ) - - var testRequestTyp = reflect.TypeOf(testRequest{}) - - var deps = []*Dependency{ - NewDependency(func(ctx *context.Context) testRequest { return testRequest{Email: "should be ignored"} }), - NewDependency(42), - NewDependency(func(ctx *context.Context) (v testRequest, err error) { - err = ctx.ReadJSON(&v) - return - }), - NewDependency("if two strings requested this should be the last one"), - NewDependency("should not be ignored when requested"), - - // Dependencies like these should always be registered last. - NewDependency(func(ctx *context.Context, input *Input) (newValue reflect.Value, err error) { - wasPtr := input.Type.Kind() == reflect.Ptr - - newValue = reflect.New(indirectType(input.Type)) - ptr := newValue.Interface() - err = ctx.ReadJSON(ptr) - - if !wasPtr { - newValue = newValue.Elem() - } - - return newValue, err - }), - } - - var tests = []struct { - Func interface{} - Expected []*binding - }{ - { // 0 - Func: func(ctx *context.Context) { - ctx.WriteString("t1") - }, - Expected: []*binding{contextBinding(0)}, - }, - { // 1 - Func: func(ctx *context.Context) error { - return fmt.Errorf("err1") - }, - Expected: []*binding{contextBinding(0)}, - }, - { // 2 - Func: func(ctx *context.Context) testResponse { - return testResponse{Name: "name"} - }, - Expected: []*binding{contextBinding(0)}, - }, - { // 3 - Func: func(in testRequest) (testResponse, error) { - return testResponse{Name: "email of " + in.Email}, nil - }, - Expected: []*binding{{Dependency: deps[2], Input: &Input{Index: 0, Type: testRequestTyp}}}, - }, - { // 4 - Func: func(in testRequest) (testResponse, error) { - return testResponse{Name: "not valid "}, fmt.Errorf("invalid") - }, - Expected: []*binding{{Dependency: deps[2], Input: &Input{Index: 0, Type: testRequestTyp}}}, - }, - { // 5 - Func: func(ctx *context.Context, in testRequest) testResponse { - return testResponse{Name: "(with ctx) email of " + in.Email} - }, - Expected: []*binding{contextBinding(0), {Dependency: deps[2], Input: &Input{Index: 1, Type: testRequestTyp}}}, - }, - { // 6 - Func: func(in testRequest, ctx *context.Context) testResponse { // reversed. - return testResponse{Name: "(with ctx) email of " + in.Email} - }, - Expected: []*binding{{Dependency: deps[2], Input: &Input{Index: 0, Type: testRequestTyp}}, contextBinding(1)}, - }, - { // 7 - Func: func(in testRequest, ctx *context.Context, in2 string) testResponse { // reversed. - return testResponse{Name: "(with ctx) email of " + in.Email + "and in2: " + in2} - }, - Expected: []*binding{ - { - Dependency: deps[2], - Input: &Input{Index: 0, Type: testRequestTyp}, - }, - contextBinding(1), - { - Dependency: deps[4], - Input: &Input{Index: 2, Type: reflect.TypeOf("")}, - }, - }, - }, - { // 8 - Func: func(in testRequest, ctx *context.Context, in2, in3 string) testResponse { // reversed. - return testResponse{Name: "(with ctx) email of " + in.Email + " | in2: " + in2 + " in3: " + in3} - }, - Expected: []*binding{ - { - Dependency: deps[2], - Input: &Input{Index: 0, Type: testRequestTyp}, - }, - contextBinding(1), - { - Dependency: deps[len(deps)-3], - Input: &Input{Index: 2, Type: reflect.TypeOf("")}, - }, - { - Dependency: deps[len(deps)-2], - Input: &Input{Index: 3, Type: reflect.TypeOf("")}, - }, - }, - }, - { // 9 - Func: func(ctx *context.Context, in testRequest, in2 testRequest2) testResponse { - return testResponse{Name: fmt.Sprintf("(with ctx) email of %s and in2.Age %d", in.Email, in2.Age)} - }, - Expected: []*binding{ - contextBinding(0), - { - Dependency: deps[2], - Input: &Input{Index: 1, Type: testRequestTyp}, - }, - { - Dependency: deps[len(deps)-1], - Input: &Input{Index: 2, Type: reflect.TypeOf(testRequest2{})}, - }, - }, - }, - { // 10 - Func: func() testResponse { - return testResponse{Name: "empty in, one out"} - }, - Expected: nil, - }, - { // 1 - Func: func(userID string, age int) testResponse { - return testResponse{Name: "in from path parameters"} - }, - Expected: []*binding{ - paramBinding(0, 0, reflect.TypeOf("")), - paramBinding(1, 1, reflect.TypeOf(0)), - }, - }, - // test std context, session, time, request, response writer and headers bindings. - { // 12 - Func: func(stdContext.Context, *sessions.Session, *golog.Logger, time.Time, *http.Request, http.ResponseWriter, http.Header) testResponse { - return testResponse{"builtin deps"} - }, - Expected: []*binding{ - { - Dependency: NewDependency(BuiltinDependencies[1]), - Input: &Input{Index: 0, Type: stdContextTyp}, - }, - { - Dependency: NewDependency(BuiltinDependencies[2]), - Input: &Input{Index: 1, Type: sessionTyp}, - }, - { - Dependency: NewDependency(BuiltinDependencies[3]), - Input: &Input{Index: 2, Type: BuiltinDependencies[3].DestType}, - }, - { - Dependency: NewDependency(BuiltinDependencies[4]), - Input: &Input{Index: 3, Type: timeTyp}, - }, - { - Dependency: NewDependency(BuiltinDependencies[5]), - Input: &Input{Index: 4, Type: BuiltinDependencies[5].DestType}, - }, - { - Dependency: NewDependency(BuiltinDependencies[6]), - Input: &Input{Index: 5, Type: BuiltinDependencies[6].DestType}, - }, - { - Dependency: NewDependency(BuiltinDependencies[7]), - Input: &Input{Index: 6, Type: BuiltinDependencies[7].DestType}, - }, - }, - }, - // test explicitly of http.Header and its underline type map[string][]string which - // but shouldn't be binded to request headers because of the (.Explicitly()), instead - // the map should be binded to our last of "deps" which is is a dynamic functions reads from request body's JSON - // (it's a builtin dependency as well but we declared it to test user dynamic dependencies too). - { // 13 - Func: func(http.Header) testResponse { - return testResponse{"builtin http.Header dep"} - }, - Expected: []*binding{ - { - Dependency: NewDependency(BuiltinDependencies[7]), - Input: &Input{Index: 0, Type: BuiltinDependencies[7].DestType}, - }, - }, - }, - { // 14 - Func: func(map[string][]string) testResponse { - return testResponse{"not dep registered except the dynamic one"} - }, - Expected: []*binding{ - { - Dependency: deps[len(deps)-1], - Input: &Input{Index: 0, Type: mapStringsTyp}, - }, - }, - }, - { // 15 - Func: func(http.Header, map[string][]string) testResponse { - return testResponse{} - }, - Expected: []*binding{ // only http.Header should be binded, we don't have map[string][]string registered. - { - Dependency: NewDependency(BuiltinDependencies[7]), - Input: &Input{Index: 0, Type: BuiltinDependencies[7].DestType}, - }, - { - Dependency: deps[len(deps)-1], - Input: &Input{Index: 1, Type: mapStringsTyp}, - }, - }, - }, - } - - c := New() - for _, dependency := range deps { - c.Register(dependency) - } - - for i, tt := range tests { - bindings := getBindingsForFunc(reflect.ValueOf(tt.Func), c.Dependencies, 0) - - if expected, got := len(tt.Expected), len(bindings); expected != got { - t.Fatalf("[%d] expected bindings length to be: %d but got: %d of: %s", i, expected, got, bindings) - } - - for j, b := range bindings { - if b == nil { - t.Fatalf("[%d:%d] binding is nil!", i, j) - } - - if tt.Expected[j] == nil { - t.Fatalf("[%d:%d] expected dependency was not found!", i, j) - } - - // if expected := tt.Expected[j]; !expected.Equal(b) { - // t.Fatalf("[%d:%d] got unexpected binding:\n%s", i, j, spew.Sdump(expected, b)) - // } - - if expected := tt.Expected[j]; !expected.Equal(b) { - t.Fatalf("[%d:%d] expected binding:\n%s\nbut got:\n%s", i, j, expected, b) - } - } - } -} - -type ( - service interface { - String() string - } - serviceImpl struct{} -) - -var serviceTyp = reflect.TypeOf((*service)(nil)).Elem() - -func (s *serviceImpl) String() string { - return "service" -} - -func TestBindingsForStruct(t *testing.T) { - type ( - controller struct { - Name string - Service service - } - - embedded1 struct { - Age int - } - - embedded2 struct { - Now time.Time - } - - Embedded3 struct { - Age int - } - - Embedded4 struct { - Now time.Time - } - - controllerEmbeddingExported struct { - Embedded3 - Embedded4 - } - - controllerEmbeddingUnexported struct { - embedded1 - embedded2 - } - - controller2 struct { - Emb1 embedded1 - Emb2 embedded2 - } - - controller3 struct { - Emb1 embedded1 - emb2 embedded2 // unused - } - ) - - var deps = []*Dependency{ - NewDependency("name"), - NewDependency(new(serviceImpl)), - } - - var depsForAnonymousEmbedded = []*Dependency{ - NewDependency(42), - NewDependency(time.Now()), - } - - var depsForFieldsOfStruct = []*Dependency{ - NewDependency(embedded1{Age: 42}), - NewDependency(embedded2{time.Now()}), - } - - var depsInterfaces = []*Dependency{ - NewDependency(func(ctx *context.Context) interface{} { - return "name" - }), - } - - var autoBindings = []*binding{ - payloadBinding(0, reflect.TypeOf(embedded1{})), - payloadBinding(1, reflect.TypeOf(embedded2{})), - } - - for _, b := range autoBindings { - b.Input.StructFieldIndex = []int{b.Input.Index} - } - - var tests = []struct { - Value interface{} - Registered []*Dependency - Expected []*binding - }{ - { // 0. - Value: &controller{}, - Registered: deps, - Expected: []*binding{ - { - Dependency: deps[0], - Input: &Input{Index: 0, StructFieldIndex: []int{0}, Type: reflect.TypeOf("")}, - }, - { - Dependency: deps[1], - Input: &Input{Index: 1, StructFieldIndex: []int{1}, Type: serviceTyp}, - }, - }, - }, - // 1. test controller with pre-defined variables. - { - Value: &controller{Name: "name_struct", Service: new(serviceImpl)}, - Expected: []*binding{ - { - Dependency: NewDependency("name_struct"), - Input: &Input{Index: 0, StructFieldIndex: []int{0}, Type: reflect.TypeOf("")}, - }, - { - Dependency: NewDependency(new(serviceImpl)), - Input: &Input{Index: 1, StructFieldIndex: []int{1}, Type: serviceTyp}, - }, - }, - }, - // 2. test controller with pre-defined variables and other deps with the exact order and value - // (deps from non zero values should be registerded only, if not the Dependency:name_struct will fail for sure). - { - Value: &controller{Name: "name_struct", Service: new(serviceImpl)}, - Registered: deps, - Expected: []*binding{ - { - Dependency: NewDependency("name_struct"), - Input: &Input{Index: 0, StructFieldIndex: []int{0}, Type: reflect.TypeOf("")}, - }, - { - Dependency: NewDependency(new(serviceImpl)), - Input: &Input{Index: 1, StructFieldIndex: []int{1}, Type: serviceTyp}, - }, - }, - }, - // 3. test embedded structs with anonymous and exported. - { - Value: &controllerEmbeddingExported{}, - Registered: depsForAnonymousEmbedded, - Expected: []*binding{ - { - Dependency: depsForAnonymousEmbedded[0], - Input: &Input{Index: 0, StructFieldIndex: []int{0, 0}, Type: reflect.TypeOf(0)}, - }, - { - Dependency: depsForAnonymousEmbedded[1], - Input: &Input{Index: 1, StructFieldIndex: []int{1, 0}, Type: reflect.TypeOf(time.Time{})}, - }, - }, - }, - // 4. test for anonymous but not exported (should still be 2, unexported structs are binded). - { - Value: &controllerEmbeddingUnexported{}, - Registered: depsForAnonymousEmbedded, - Expected: []*binding{ - { - Dependency: depsForAnonymousEmbedded[0], - Input: &Input{Index: 0, StructFieldIndex: []int{0, 0}, Type: reflect.TypeOf(0)}, - }, - { - Dependency: depsForAnonymousEmbedded[1], - Input: &Input{Index: 1, StructFieldIndex: []int{1, 0}, Type: reflect.TypeOf(time.Time{})}, - }, - }, - }, - // 5. test for auto-bindings with zero registered. - { - Value: &controller2{}, - Registered: nil, - Expected: autoBindings, - }, - // 6. test for embedded with named fields which should NOT contain any registered deps - // except the two auto-bindings for structs, - { - Value: &controller2{}, - Registered: depsForAnonymousEmbedded, - Expected: autoBindings, - }, // 7. and only embedded struct's fields are readen, otherwise we expect the struct to be a dependency. - { - Value: &controller2{}, - Registered: depsForFieldsOfStruct, - Expected: []*binding{ - { - Dependency: depsForFieldsOfStruct[0], - Input: &Input{Index: 0, StructFieldIndex: []int{0}, Type: reflect.TypeOf(embedded1{})}, - }, - { - Dependency: depsForFieldsOfStruct[1], - Input: &Input{Index: 1, StructFieldIndex: []int{1}, Type: reflect.TypeOf(embedded2{})}, - }, - }, - }, - // 8. test one exported and other not exported. - { - Value: &controller3{}, - Registered: []*Dependency{depsForFieldsOfStruct[0]}, - Expected: []*binding{ - { - Dependency: depsForFieldsOfStruct[0], - Input: &Input{Index: 0, StructFieldIndex: []int{0}, Type: reflect.TypeOf(embedded1{})}, - }, - }, - }, - // 9. test same as the above but by registering all dependencies. - { - Value: &controller3{}, - Registered: depsForFieldsOfStruct, - Expected: []*binding{ - { - Dependency: depsForFieldsOfStruct[0], - Input: &Input{Index: 0, StructFieldIndex: []int{0}, Type: reflect.TypeOf(embedded1{})}, - }, - }, - }, - // 10. test bind an interface{}. - { - Value: &controller{}, - Registered: depsInterfaces, - Expected: []*binding{ - { - Dependency: depsInterfaces[0], - Input: &Input{Index: 0, StructFieldIndex: []int{0}, Type: reflect.TypeOf("")}, - }, - }, - }, - } - - for i, tt := range tests { - bindings := getBindingsForStruct(reflect.ValueOf(tt.Value), tt.Registered, 0, nil) - - if expected, got := len(tt.Expected), len(bindings); expected != got { - t.Logf("[%d] expected bindings length to be: %d but got: %d:\n", i, expected, got) - for _, b := range bindings { - t.Logf("\t%s\n", b) - } - t.FailNow() - } - - for j, b := range bindings { - if tt.Expected[j] == nil { - t.Fatalf("[%d:%d] expected dependency was not found!", i, j) - } - - if expected := tt.Expected[j]; !expected.Equal(b) { - t.Fatalf("[%d:%d] expected binding:\n%s\nbut got:\n%s", i, j, expected, b) - } - } - } - -} diff --git a/hero/container.go b/hero/container.go index b82cebcd..102b5207 100644 --- a/hero/container.go +++ b/hero/container.go @@ -8,8 +8,8 @@ import ( "reflect" "time" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/sessions" + "github.com/kataras/iris/context" + "github.com/kataras/iris/sessions" "github.com/kataras/golog" ) diff --git a/hero/container_test.go b/hero/container_test.go deleted file mode 100644 index 8399ebcf..00000000 --- a/hero/container_test.go +++ /dev/null @@ -1,131 +0,0 @@ -package hero_test - -import ( - "fmt" - "reflect" - "testing" - - "github.com/kataras/iris/v12" - . "github.com/kataras/iris/v12/hero" - "github.com/kataras/iris/v12/httptest" -) - -var errTyp = reflect.TypeOf((*error)(nil)).Elem() - -// isError returns true if "typ" is type of `error`. -func isError(typ reflect.Type) bool { - return typ.Implements(errTyp) -} - -type ( - testInput struct { - Name string `json:"name"` - } - - testOutput struct { - ID int `json:"id"` - Name string `json:"name"` - } -) - -var ( - fn = func(id int, in testInput) testOutput { - return testOutput{ - ID: id, - Name: in.Name, - } - } - - expectedOutput = testOutput{ - ID: 42, - Name: "makis", - } - - input = testInput{ - Name: "makis", - } -) - -func TestContainerHandler(t *testing.T) { - app := iris.New() - - c := New() - postHandler := c.Handler(fn) - app.Post("/{id:int}", postHandler) - - e := httptest.New(t, app) - path := fmt.Sprintf("/%d", expectedOutput.ID) - e.POST(path).WithJSON(input).Expect().Status(httptest.StatusOK).JSON().Equal(expectedOutput) -} - -func TestContainerInject(t *testing.T) { - c := New() - - expected := testInput{Name: "test"} - c.Register(expected) - c.Register(&expected) - - // struct value. - var got1 testInput - if err := c.Inject(&got1); err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expected, got1) { - t.Fatalf("[struct value] expected: %#+v but got: %#+v", expected, got1) - } - - // ptr. - var got2 *testInput - if err := c.Inject(&got2); err != nil { - t.Fatal(err) - } - - if !reflect.DeepEqual(&expected, got2) { - t.Fatalf("[ptr] expected: %#+v but got: %#+v", &expected, got2) - } - - // register implementation, expect interface. - expected3 := &testServiceImpl{prefix: "prefix: "} - c.Register(expected3) - - var got3 testService - if err := c.Inject(&got3); err != nil { - t.Fatal(err) - } - - if !reflect.DeepEqual(expected3, got3) { - t.Fatalf("[service] expected: %#+v but got: %#+v", expected3, got3) - } -} - -func TestContainerUseResultHandler(t *testing.T) { - c := New() - resultLogger := func(next ResultHandler) ResultHandler { - return func(ctx iris.Context, v interface{}) error { - t.Logf("%#+v", v) - return next(ctx, v) - } - } - - c.UseResultHandler(resultLogger) - expectedResponse := map[string]interface{}{"injected": true} - c.UseResultHandler(func(next ResultHandler) ResultHandler { - return func(ctx iris.Context, v interface{}) error { - return next(ctx, expectedResponse) - } - }) - c.UseResultHandler(resultLogger) - - handler := c.Handler(func(id int) testOutput { - return testOutput{ - ID: id, - Name: "kataras", - } - }) - - app := iris.New() - app.Get("/{id:int}", handler) - - e := httptest.New(t, app) - e.GET("/42").Expect().Status(httptest.StatusOK).JSON().Equal(expectedResponse) -} diff --git a/hero/dependency.go b/hero/dependency.go index 5d960ff6..5a9d8725 100644 --- a/hero/dependency.go +++ b/hero/dependency.go @@ -5,7 +5,7 @@ import ( "reflect" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) type ( diff --git a/hero/dependency_test.go b/hero/dependency_test.go deleted file mode 100644 index b90e341e..00000000 --- a/hero/dependency_test.go +++ /dev/null @@ -1,206 +0,0 @@ -package hero_test - -import ( - "fmt" - "reflect" - "testing" - - "github.com/kataras/iris/v12/context" - . "github.com/kataras/iris/v12/hero" -) - -type testDependencyTest struct { - Dependency interface{} - Expected interface{} -} - -func TestDependency(t *testing.T) { - var tests = []testDependencyTest{ - { - Dependency: "myValue", - Expected: "myValue", - }, - { - Dependency: struct{ Name string }{"name"}, - Expected: struct{ Name string }{"name"}, - }, - { - Dependency: func(*context.Context, *Input) (reflect.Value, error) { - return reflect.ValueOf(42), nil - }, - Expected: 42, - }, - { - Dependency: DependencyHandler(func(*context.Context, *Input) (reflect.Value, error) { - return reflect.ValueOf(255), nil - }), - Expected: 255, - }, - { - Dependency: func(*context.Context) (reflect.Value, error) { - return reflect.ValueOf("OK without Input"), nil - }, - Expected: "OK without Input", - }, - { - - Dependency: func(*context.Context, ...string) (reflect.Value, error) { - return reflect.ValueOf("OK variadic ignored"), nil - }, - Expected: "OK variadic ignored", - }, - { - - Dependency: func(*context.Context) reflect.Value { - return reflect.ValueOf("OK without Input and error") - }, - Expected: "OK without Input and error", - }, - { - - Dependency: func(*context.Context, ...int) reflect.Value { - return reflect.ValueOf("OK without error and variadic ignored") - }, - Expected: "OK without error and variadic ignored", - }, - { - - Dependency: func(*context.Context) interface{} { - return "1" - }, - Expected: "1", - }, - { - - Dependency: func(*context.Context) interface{} { - return false - }, - Expected: false, - }, - } - - testDependencies(t, tests) -} - -// Test dependencies that depend on previous one(s). -func TestDependentDependency(t *testing.T) { - msgBody := "prefix: it is a deep dependency" - newMsgBody := msgBody + " new" - var tests = []testDependencyTest{ - // test three level depth and error. - { // 0 - Dependency: &testServiceImpl{prefix: "prefix:"}, - Expected: &testServiceImpl{prefix: "prefix:"}, - }, - { // 1 - Dependency: func(service testService) testMessage { - return testMessage{Body: service.Say("it is a deep") + " dependency"} - }, - Expected: testMessage{Body: msgBody}, - }, - { // 2 - Dependency: func(msg testMessage) string { - return msg.Body - }, - Expected: msgBody, - }, - { // 3 - Dependency: func(msg testMessage) error { - return fmt.Errorf(msg.Body) - }, - Expected: fmt.Errorf(msgBody), - }, - // Test depend on more than one previous registered dependencies and require a before-previous one. - { // 4 - Dependency: func(body string, msg testMessage) string { - if body != msg.Body { - t.Fatalf("body[%s] != msg.Body[%s]", body, msg.Body) - } - - return body + " new" - }, - Expected: newMsgBody, - }, - // Test dependency order by expecting the first returning value and not the later-on registered dependency(#4). - // 5 - { - Dependency: func(body string) string { - return body - }, - Expected: newMsgBody, - }, - } - - testDependencies(t, tests) -} - -func testDependencies(t *testing.T, tests []testDependencyTest) { - t.Helper() - - c := New() - for i, tt := range tests { - d := c.Register(tt.Dependency) - - if d == nil { - t.Fatalf("[%d] expected %#+v to be converted to a valid dependency", i, tt) - } - - val, err := d.Handle(context.NewContext(nil), &Input{}) - - if expectError := isError(reflect.TypeOf(tt.Expected)); expectError { - val = reflect.ValueOf(err) - err = nil - } - - if err != nil { - t.Fatalf("[%d] expected a nil error but got: %v", i, err) - } - - if !val.CanInterface() { - t.Fatalf("[%d] expected output value to be accessible: %T", i, val) - } - - if expected, got := fmt.Sprintf("%#+v", tt.Expected), fmt.Sprintf("%#+v", val.Interface()); expected != got { - t.Fatalf("[%d] expected return value to be:\n%s\nbut got:\n%s", i, expected, got) - } - - // t.Logf("[%d] %s", i, d) - // t.Logf("[%d] output: %#+v", i, val.Interface()) - } -} - -func TestDependentDependencyInheritanceStatic(t *testing.T) { - // Tests the following case #1564: - // Logger - // func(Logger) S1 - // ^ Should be static because Logger - // is a structure, a static dependency. - // - // func(Logger) S2 - // func(S1, S2) S3 - // ^ Should be marked as static dependency - // because everything that depends on are static too. - - type S1 struct { - msg string - } - - type S2 struct { - msg2 string - } - - serviceDep := NewDependency(&testServiceImpl{prefix: "1"}) - d1 := NewDependency(func(t testService) S1 { - return S1{t.Say("2")} - }, serviceDep) - if !d1.Static { - t.Fatalf("d1 dependency should be static: %#+v", d1) - } - - d2 := NewDependency(func(t testService, s S1) S2 { - return S2{"3"} - }, serviceDep, d1) - if !d2.Static { - t.Fatalf("d2 dependency should be static: %#+v", d2) - } -} diff --git a/hero/func_result.go b/hero/func_result.go index 74bd56a3..6c25b6a6 100644 --- a/hero/func_result.go +++ b/hero/func_result.go @@ -4,7 +4,7 @@ import ( "reflect" "strings" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" "github.com/fatih/structs" "google.golang.org/protobuf/proto" diff --git a/hero/func_result_test.go b/hero/func_result_test.go deleted file mode 100644 index e89b80d8..00000000 --- a/hero/func_result_test.go +++ /dev/null @@ -1,281 +0,0 @@ -package hero_test - -import ( - "errors" - "fmt" - "net/http" - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/httptest" - - . "github.com/kataras/iris/v12/hero" -) - -func GetText() string { - return "text" -} - -func GetStatus() int { - return iris.StatusBadGateway -} - -func GetTextWithStatusOk() (string, int) { - return "OK", iris.StatusOK -} - -// tests should have output arguments mixed -func GetStatusWithTextNotOkBy(first string, second string) (int, string) { - return iris.StatusForbidden, "NOT_OK_" + first + second -} - -func GetTextAndContentType() (string, string) { - return "text", "text/html" -} - -type testCustomResult struct { - HTML string -} - -// The only one required function to make that a custom Response dispatcher. -func (r testCustomResult) Dispatch(ctx iris.Context) { - _, _ = ctx.HTML(r.HTML) -} - -func GetCustomResponse() testCustomResult { - return testCustomResult{"text"} -} - -func GetCustomResponseWithStatusOk() (testCustomResult, int) { - return testCustomResult{"OK"}, iris.StatusOK -} - -func GetCustomResponseWithStatusNotOk() (testCustomResult, int) { - return testCustomResult{"internal server error"}, iris.StatusInternalServerError -} - -type testCustomStruct struct { - Name string `json:"name" xml:"name"` - Age int `json:"age" xml:"age"` -} - -func GetCustomStruct() testCustomStruct { - return testCustomStruct{"Iris", 2} -} - -func GetCustomStructWithStatusNotOk() (testCustomStruct, int) { - return testCustomStruct{"Iris", 2}, iris.StatusInternalServerError -} - -func GetCustomStructWithContentType() (testCustomStruct, string) { - return testCustomStruct{"Iris", 2}, "text/xml" -} - -func GetCustomStructWithError(ctx iris.Context) (s testCustomStruct, err error) { - s = testCustomStruct{"Iris", 2} - if ctx.URLParamExists("err") { - err = errors.New("omit return of testCustomStruct and fire error") - } - - // it should send the testCustomStruct as JSON if error is nil - // otherwise it should fire the default error(BadRequest) with the error's text. - return -} - -type err struct { - Status int `json:"status_code"` - Message string `json:"message"` -} - -func (e err) Dispatch(ctx iris.Context) { - // write the status code based on the err's StatusCode. - ctx.StatusCode(e.Status) - // send to the client the whole object as json - _, _ = ctx.JSON(e) -} - -func GetCustomErrorAsDispatcher() err { - return err{iris.StatusBadRequest, "this is my error as json"} -} - -func GetCustomTypedNilEmptyResponse() iris.Map { - return nil -} - -func GetCustomTypedPtrNilEmptyResponse() *iris.Map { - return nil -} - -func GetCustomMapNilEmptyResponse() map[string]interface{} { - return nil -} - -func GetCustomPtrStructNilEmptyResponse() *testCustomStruct { - return nil -} - -func TestFuncResult(t *testing.T) { - app := iris.New() - h := New() - // for any 'By', by is not required but we use this suffix here, like controllers - // to make it easier for the future to resolve if any bug. - // add the binding for path parameters. - - app.Get("/text", h.Handler(GetText)) - app.Get("/status", h.Handler(GetStatus)) - app.Get("/text/with/status/ok", h.Handler(GetTextWithStatusOk)) - app.Get("/status/with/text/not/ok/{first}/{second}", h.Handler(GetStatusWithTextNotOkBy)) - app.Get("/text/and/content/type", h.Handler(GetTextAndContentType)) - // - app.Get("/custom/response", h.Handler(GetCustomResponse)) - app.Get("/custom/response/with/status/ok", h.Handler(GetCustomResponseWithStatusOk)) - app.Get("/custom/response/with/status/not/ok", h.Handler(GetCustomResponseWithStatusNotOk)) - // - app.Get("/custom/struct", h.Handler(GetCustomStruct)) - app.Get("/custom/struct/with/status/not/ok", h.Handler(GetCustomStructWithStatusNotOk)) - app.Get("/custom/struct/with/content/type", h.Handler(GetCustomStructWithContentType)) - app.Get("/custom/struct/with/error", h.Handler(GetCustomStructWithError)) - app.Get("/custom/error/as/dispatcher", h.Handler(GetCustomErrorAsDispatcher)) - - app.Get("/custom/nil/typed", h.Handler(GetCustomTypedNilEmptyResponse)) - app.Get("/custom/nil/typed/ptr", h.Handler(GetCustomTypedPtrNilEmptyResponse)) - app.Get("/custom/nil/map", h.Handler(GetCustomMapNilEmptyResponse)) - app.Get("/custom/nil/struct", h.Handler(GetCustomPtrStructNilEmptyResponse)) - - e := httptest.New(t, app) - - e.GET("/text").Expect().Status(iris.StatusOK). - Body().Equal("text") - - e.GET("/status").Expect().Status(iris.StatusBadGateway) - - e.GET("/text/with/status/ok").Expect().Status(iris.StatusOK). - Body().Equal("OK") - - e.GET("/status/with/text/not/ok/first/second").Expect().Status(iris.StatusForbidden). - Body().Equal("NOT_OK_firstsecond") - // Author's note: <-- if that fails means that the last binder called for both input args, - // see path_param_binder.go - - e.GET("/text/and/content/type").Expect().Status(iris.StatusOK). - ContentType("text/html", "utf-8"). - Body().Equal("text") - - e.GET("/custom/response").Expect().Status(iris.StatusOK). - ContentType("text/html", "utf-8"). - Body().Equal("text") - e.GET("/custom/response/with/status/ok").Expect().Status(iris.StatusOK). - ContentType("text/html", "utf-8"). - Body().Equal("OK") - e.GET("/custom/response/with/status/not/ok").Expect().Status(iris.StatusInternalServerError). - ContentType("text/html", "utf-8"). - Body().Equal("internal server error") - - expectedResultFromCustomStruct := map[string]interface{}{ - "name": "Iris", - "age": 2, - } - e.GET("/custom/struct").Expect().Status(iris.StatusOK). - JSON().Equal(expectedResultFromCustomStruct) - e.GET("/custom/struct/with/status/not/ok").Expect().Status(iris.StatusInternalServerError). - JSON().Equal(expectedResultFromCustomStruct) - e.GET("/custom/struct/with/content/type").Expect().Status(iris.StatusOK). - ContentType("text/xml", "utf-8") - e.GET("/custom/struct/with/error").Expect().Status(iris.StatusOK). - JSON().Equal(expectedResultFromCustomStruct) - e.GET("/custom/struct/with/error").WithQuery("err", true).Expect(). - Status(iris.StatusBadRequest). // the default status code if error is not nil - // the content should be not JSON it should be the status code's text - // it will fire the error's text - Body().Equal("omit return of testCustomStruct and fire error") - - e.GET("/custom/error/as/dispatcher").Expect(). - Status(iris.StatusBadRequest). // the default status code if error is not nil - // the content should be not JSON it should be the status code's text - // it will fire the error's text - JSON().Equal(err{iris.StatusBadRequest, "this is my error as json"}) - - // its result is nil should give an empty response but content-type is set correctly. - e.GET("/custom/nil/typed").Expect(). - Status(iris.StatusOK).ContentType(context.ContentJSONHeaderValue).Body().Empty() - e.GET("/custom/nil/typed/ptr").Expect(). - Status(iris.StatusOK).ContentType(context.ContentJSONHeaderValue).Body().Empty() - e.GET("/custom/nil/map").Expect(). - Status(iris.StatusOK).ContentType(context.ContentJSONHeaderValue).Body().Empty() - e.GET("/custom/nil/struct").Expect(). - Status(iris.StatusOK).ContentType(context.ContentJSONHeaderValue).Body().Empty() -} - -type ( - testPreflightRequest struct { - FailCode int `json:"fail_code"` // for the sake of the test. - } - - testPreflightResponse struct { - Code int - Message string - } -) - -func (r testPreflightResponse) Preflight(ctx iris.Context) error { - if r.Code == httptest.StatusInternalServerError { - return fmt.Errorf("custom error") - } - - ctx.StatusCode(r.Code) - return nil -} - -func TestPreflightResult(t *testing.T) { - app := iris.New() - c := New() - handler := c.Handler(func(in testPreflightRequest) testPreflightResponse { - return testPreflightResponse{Code: in.FailCode, Message: http.StatusText(in.FailCode)} - }) - app.Post("/", handler) - handler2 := c.Handler(func(in testInput) (int, testOutput) { - return httptest.StatusAccepted, testOutput{Name: in.Name} - }) - app.Post("/alternative", handler2) - - e := httptest.New(t, app) - - expected1 := testPreflightResponse{Code: httptest.StatusOK, Message: "OK"} - e.POST("/").WithJSON(testPreflightRequest{FailCode: expected1.Code}). - Expect().Status(httptest.StatusOK).JSON().Equal(expected1) - - expected2 := testPreflightResponse{Code: httptest.StatusBadRequest, Message: "Bad Request"} - e.POST("/").WithJSON(testPreflightRequest{FailCode: expected2.Code}). - Expect().Status(httptest.StatusBadRequest).JSON().Equal(expected2) - - // Test error returned from Preflight. - e.POST("/").WithJSON(testPreflightRequest{FailCode: httptest.StatusInternalServerError}). - Expect().Status(httptest.StatusBadRequest).Body().Equal("custom error") - - // Can be done without Preflight as the second output argument can be a status code. - expected4 := testOutput{Name: "my_name"} - e.POST("/alternative").WithJSON(testInput{expected4.Name}). - Expect().Status(httptest.StatusAccepted).JSON().Equal(expected4) -} - -func TestResponseErr(t *testing.T) { - app := iris.New() - var expectedErr = errors.New("response error") - - app.OnAnyErrorCode(func(ctx iris.Context) { - err := ctx.GetErr() - if err != expectedErr { - t.Fatalf("expected error value does not match") - } - - ctx.WriteString(err.Error()) - }) - - app.ConfigureContainer().Get("/", func() Response { - return Response{Code: iris.StatusBadGateway, Err: expectedErr} - }) - - e := httptest.New(t, app) - e.GET("/").Expect().Status(iris.StatusBadGateway).Body().Equal("response error") -} diff --git a/hero/handler.go b/hero/handler.go index 673a8ece..d3b02a8d 100644 --- a/hero/handler.go +++ b/hero/handler.go @@ -4,7 +4,7 @@ import ( "fmt" "reflect" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) type ( diff --git a/hero/handler_test.go b/hero/handler_test.go deleted file mode 100644 index f3923b25..00000000 --- a/hero/handler_test.go +++ /dev/null @@ -1,287 +0,0 @@ -package hero_test - -import ( - "fmt" - "testing" - - "github.com/kataras/iris/v12" - . "github.com/kataras/iris/v12/hero" - "github.com/kataras/iris/v12/httptest" -) - -// dynamic func -type testUserStruct struct { - ID int64 `json:"id" form:"id" url:"id"` - Username string `json:"username" form:"username" url:"username"` -} - -func testBinderFunc(ctx iris.Context) testUserStruct { - id, _ := ctx.Params().GetInt64("id") - username := ctx.Params().Get("username") - return testUserStruct{ - ID: id, - Username: username, - } -} - -// service -type ( - // these testService and testServiceImpl could be in lowercase, unexported - // but the `Say` method should be exported however we have those exported - // because of the controller handler test. - testService interface { - Say(string) string - } - testServiceImpl struct { - prefix string - } -) - -func (s *testServiceImpl) Say(message string) string { - return s.prefix + " " + message -} - -var ( - // binders, as user-defined - testBinderFuncUserStruct = testBinderFunc - testBinderService = &testServiceImpl{prefix: "say"} - testBinderFuncParam = func(ctx iris.Context) string { - return ctx.Params().Get("param") - } - - // consumers - // a context as first input arg, which is not needed to be binded manually, - // and a user struct which is binded to the input arg by the #1 func(ctx) any binder. - testConsumeUserHandler = func(ctx iris.Context, user testUserStruct) { - ctx.JSON(user) - } - - // just one input arg, the service which is binded by the #2 service binder. - testConsumeServiceHandler = func(service testService) string { - return service.Say("something") - } - // just one input arg, a standar string which is binded by the #3 func(ctx) any binder. - testConsumeParamHandler = func(myParam string) string { - return "param is: " + myParam - } -) - -func TestHandler(t *testing.T) { - Register(testBinderFuncUserStruct) - Register(testBinderService) - Register(testBinderFuncParam) - var ( - h1 = Handler(testConsumeUserHandler) - h2 = Handler(testConsumeServiceHandler) - h3 = Handler(testConsumeParamHandler) - ) - - testAppWithHeroHandlers(t, h1, h2, h3) -} - -func testAppWithHeroHandlers(t *testing.T, h1, h2, h3 iris.Handler) { - app := iris.New() - app.Get("/{id:int64}/{username:string}", h1) - app.Get("/service", h2) - app.Get("/param/{param:string}", h3) - - expectedUser := testUserStruct{ - ID: 42, - Username: "kataras", - } - - e := httptest.New(t, app) - // 1 - e.GET(fmt.Sprintf("/%d/%s", expectedUser.ID, expectedUser.Username)).Expect().Status(httptest.StatusOK). - JSON().Equal(expectedUser) - // 2 - e.GET("/service").Expect().Status(httptest.StatusOK). - Body().Equal("say something") - // 3 - e.GET("/param/the_param_value").Expect().Status(httptest.StatusOK). - Body().Equal("param is: the_param_value") -} - -// TestBindFunctionAsFunctionInputArgument tests to bind -// a whole dynamic function based on the current context -// as an input argument in the hero handler's function. -func TestBindFunctionAsFunctionInputArgument(t *testing.T) { - app := iris.New() - postsBinder := func(ctx iris.Context) func(string) string { - return ctx.PostValue // or FormValue, the same here. - } - - h := New(postsBinder).Handler(func(get func(string) string) string { - // send the `ctx.PostValue/FormValue("username")` value - // to the client. - return get("username") - }) - - app.Post("/", h) - - e := httptest.New(t, app) - - expectedUsername := "kataras" - e.POST("/").WithFormField("username", expectedUsername). - Expect().Status(iris.StatusOK).Body().Equal(expectedUsername) -} - -func TestPayloadBinding(t *testing.T) { - h := New() - - ptrHandler := h.Handler(func(input *testUserStruct /* ptr */) string { - return input.Username - }) - - valHandler := h.Handler(func(input testUserStruct) string { - return input.Username - }) - - app := iris.New() - app.Get("/", ptrHandler) - app.Post("/", ptrHandler) - app.Post("/2", valHandler) - - e := httptest.New(t, app) - - // JSON - e.POST("/").WithJSON(iris.Map{"username": "makis"}).Expect().Status(httptest.StatusOK).Body().Equal("makis") - e.POST("/2").WithJSON(iris.Map{"username": "kataras"}).Expect().Status(httptest.StatusOK).Body().Equal("kataras") - - // FORM (url-encoded) - e.POST("/").WithFormField("username", "makis").Expect().Status(httptest.StatusOK).Body().Equal("makis") - // FORM (multipart) - e.POST("/").WithMultipart().WithFormField("username", "makis").Expect().Status(httptest.StatusOK).Body().Equal("makis") - - // POST URL query. - e.POST("/").WithQuery("username", "makis").Expect().Status(httptest.StatusOK).Body().Equal("makis") - // GET URL query. - e.GET("/").WithQuery("username", "makis").Expect().Status(httptest.StatusOK).Body().Equal("makis") -} - -/* Author's notes: -If aksed or required by my company, make the following test to pass but think downsides of code complexity and performance-cost -before begin the implementation of it. -- Dependencies without depending on other values can be named "root-level dependencies" -- Dependencies could be linked (a new .DependsOn?) to a "root-level dependency"(or by theirs same-level deps too?) with much - more control if "root-level dependencies" are named, e.g.: - b.Register("db", &myDBImpl{}) - b.Register("user_dep", func(db myDB) User{...}).DependsOn("db") - b.Handler(func(user User) error{...}) - b.Handler(func(ctx iris.Context, reuseDB myDB) {...}) -Why linked over automatically? Because more than one dependency can implement the same input and -end-user does not care about ordering the registered ones. -Link with `DependsOn` SHOULD be optional, if exists then limit the available dependencies, -`DependsOn` SHOULD accept comma-separated values, e.g. "db, otherdep" and SHOULD also work -by calling it multiple times i.e `Depends("db").DependsOn("otherdep")`. -Handlers should also be able to explicitly limit the list of -their available dependencies per-handler, a `.DependsOn` feature SHOULD exist there too. - -Also, note that with the new implementation a `*hero.Input` value can be accepted on dynamic dependencies, -that value contains an `Options.Dependencies` field which lists all the registered dependencies, -so, in theory, end-developers could achieve same results by hand-code(inside the dependency's function body). - -26 Feb 2020. Gerasimos Maropoulos -______________________________________________ - -29 Feb 2020. It's done. -*/ - -type testMessage struct { - Body string -} - -func TestDependentDependencies(t *testing.T) { - b := New() - b.Register(&testServiceImpl{prefix: "prefix:"}) - b.Register(func(service testService) testMessage { - return testMessage{Body: service.Say("it is a deep") + " dependency"} - }) - var ( - h1 = b.Handler(func(msg testMessage) string { - return msg.Body - }) - h2 = b.Handler(func(reuse testService) string { - return reuse.Say("message") - }) - ) - - app := iris.New() - app.Get("/h1", h1) - app.Get("/h2", h2) - - e := httptest.New(t, app) - e.GET("/h1").Expect().Status(httptest.StatusOK).Body().Equal("prefix: it is a deep dependency") - e.GET("/h2").Expect().Status(httptest.StatusOK).Body().Equal("prefix: message") -} - -func TestHandlerPathParams(t *testing.T) { - // See white box `TestPathParams` test too. - // All cases should pass. - app := iris.New() - handler := func(id uint64) string { - return fmt.Sprintf("%d", id) - } - - app.Party("/users").ConfigureContainer(func(api *iris.APIContainer) { - api.Get("/{id:uint64}", handler) - }) - - app.Party("/editors/{id:uint64}").ConfigureContainer(func(api *iris.APIContainer) { - api.Get("/", handler) - }) - - // should receive the last one, as we expected only one useful for MVC (there is a similar test there too). - app.ConfigureContainer().Get("/{ownerID:uint64}/book/{booKID:uint64}", handler) - - e := httptest.New(t, app) - - for _, testReq := range []*httptest.Request{ - e.GET("/users/42"), - e.GET("/editors/42"), - e.GET("/1/book/42"), - } { - testReq.Expect().Status(httptest.StatusOK).Body().Equal("42") - } -} - -func TestRegisterDependenciesFromContext(t *testing.T) { - // Tests serve-time struct dependencies through a common Iris middleware. - app := iris.New() - app.Use(func(ctx iris.Context) { - ctx.RegisterDependency(testUserStruct{Username: "kataras"}) - ctx.Next() - }) - app.Use(func(ctx iris.Context) { - ctx.RegisterDependency(&testServiceImpl{prefix: "say"}) - ctx.Next() - }) - - app.ConfigureContainer(func(api *iris.APIContainer) { - api.Get("/", func(u testUserStruct) string { - return u.Username - }) - - api.Get("/service", func(s *testServiceImpl) string { - return s.Say("hello") - }) - - // Note: we are not allowed to pass the service as an interface here - // because the container will, correctly, panic because it will expect - // a dependency to be registered before server ran. - api.Get("/both", func(s *testServiceImpl, u testUserStruct) string { - return s.Say(u.Username) - }) - - api.Get("/non", func() string { - return "nothing" - }) - }) - - e := httptest.New(t, app) - - e.GET("/").Expect().Status(httptest.StatusOK).Body().Equal("kataras") - e.GET("/service").Expect().Status(httptest.StatusOK).Body().Equal("say hello") - e.GET("/both").Expect().Status(httptest.StatusOK).Body().Equal("say kataras") - e.GET("/non").Expect().Status(httptest.StatusOK).Body().Equal("nothing") -} diff --git a/hero/param_test.go b/hero/param_test.go deleted file mode 100644 index baa34d92..00000000 --- a/hero/param_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package hero - -import ( - "testing" - - "github.com/kataras/iris/v12/context" -) - -func TestPathParams(t *testing.T) { - got := "" - h := New() - handler := h.Handler(func(firstname string, lastname string) { - got = firstname + lastname - }) - - h.Register(func(ctx *context.Context) func() string { return func() string { return "" } }) - handlerWithOther := h.Handler(func(f func() string, firstname string, lastname string) { - got = f() + firstname + lastname - }) - - handlerWithOtherBetweenThem := h.Handler(func(firstname string, f func() string, lastname string) { - got = firstname + lastname - }) - - ctx := context.NewContext(nil) - ctx.Params().Set("firstname", "Gerasimos") - ctx.Params().Set("lastname", "Maropoulos") - handler(ctx) - expected := "GerasimosMaropoulos" - if got != expected { - t.Fatalf("[0] expected the params 'firstname' + 'lastname' to be '%s' but got '%s'", expected, got) - } - - got = "" - handlerWithOther(ctx) - expected = "GerasimosMaropoulos" - if got != expected { - t.Fatalf("[1] expected the params 'firstname' + 'lastname' to be '%s' but got '%s'", expected, got) - } - - got = "" - handlerWithOtherBetweenThem(ctx) - expected = "GerasimosMaropoulos" - if got != expected { - t.Fatalf("[2] expected the params 'firstname' + 'lastname' to be '%s' but got '%s'", expected, got) - } -} diff --git a/hero/reflect.go b/hero/reflect.go index f7c8b186..2102a73c 100644 --- a/hero/reflect.go +++ b/hero/reflect.go @@ -4,7 +4,7 @@ import ( "net" "reflect" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) func valueOf(v interface{}) reflect.Value { diff --git a/hero/reflect_test.go b/hero/reflect_test.go deleted file mode 100644 index 6f10772b..00000000 --- a/hero/reflect_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package hero - -import ( - "reflect" - "testing" -) - -type testInterface interface { - Get() string -} - -var testInterfaceTyp = reflect.TypeOf((*testInterface)(nil)).Elem() - -type testImplPtr struct{} - -func (*testImplPtr) Get() string { return "get_ptr" } - -type testImpl struct{} - -func (testImpl) Get() string { return "get" } - -func TestEqualTypes(t *testing.T) { - of := reflect.TypeOf - - var tests = map[reflect.Type]reflect.Type{ - of("string"): of("input"), - of(42): of(10), - testInterfaceTyp: testInterfaceTyp, - of(new(testImplPtr)): testInterfaceTyp, - of(new(testImpl)): testInterfaceTyp, - of(testImpl{}): testInterfaceTyp, - } - - for binding, input := range tests { - if !equalTypes(binding, input) { - t.Fatalf("expected type of: %s to be equal to the binded one of: %s", input, binding) - } - } -} diff --git a/hero/struct.go b/hero/struct.go index 2ee16f77..c0122ac2 100644 --- a/hero/struct.go +++ b/hero/struct.go @@ -4,7 +4,7 @@ import ( "fmt" "reflect" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) // Sorter is the type for sort customization of a struct's fields diff --git a/hero/struct_test.go b/hero/struct_test.go deleted file mode 100644 index 5401f7bd..00000000 --- a/hero/struct_test.go +++ /dev/null @@ -1,121 +0,0 @@ -package hero_test - -import ( - "errors" - "fmt" - "testing" - - "github.com/kataras/iris/v12" - . "github.com/kataras/iris/v12/hero" - "github.com/kataras/iris/v12/httptest" -) - -type testStruct struct { - Ctx iris.Context -} - -func (c *testStruct) MyHandler(name string) testOutput { - return fn(42, testInput{Name: name}) -} - -func (c *testStruct) MyHandler2(id int, in testInput) testOutput { - return fn(id, in) -} - -func (c *testStruct) MyHandler3(in testInput) testOutput { - return fn(42, in) -} - -func (c *testStruct) MyHandler4() { - c.Ctx.WriteString("MyHandler4") -} - -func TestStruct(t *testing.T) { - app := iris.New() - - b := New() - s := b.Struct(&testStruct{}, 0) - - postHandler := s.MethodHandler("MyHandler", 0) // fallbacks such as {path} and {string} should registered first when same path. - app.Post("/{name:string}", postHandler) - postHandler2 := s.MethodHandler("MyHandler2", 0) - app.Post("/{id:int}", postHandler2) - postHandler3 := s.MethodHandler("MyHandler3", 0) - app.Post("/myHandler3", postHandler3) - getHandler := s.MethodHandler("MyHandler4", 0) - app.Get("/myHandler4", getHandler) - - e := httptest.New(t, app) - e.POST("/" + input.Name).Expect().Status(httptest.StatusOK).JSON().Equal(expectedOutput) - path := fmt.Sprintf("/%d", expectedOutput.ID) - e.POST(path).WithJSON(input).Expect().Status(httptest.StatusOK).JSON().Equal(expectedOutput) - e.POST("/myHandler3").WithJSON(input).Expect().Status(httptest.StatusOK).JSON().Equal(expectedOutput) - e.GET("/myHandler4").Expect().Status(httptest.StatusOK).Body().Equal("MyHandler4") -} - -type testStructErrorHandler struct{} - -func (s *testStructErrorHandler) HandleError(ctx iris.Context, err error) { - ctx.StopWithError(httptest.StatusConflict, err) -} - -func (s *testStructErrorHandler) Handle(errText string) error { - return errors.New(errText) -} - -func TestStructErrorHandler(t *testing.T) { - b := New() - s := b.Struct(&testStructErrorHandler{}, 0) - - app := iris.New() - app.Get("/{errText:string}", s.MethodHandler("Handle", 0)) - - expectedErrText := "an error" - e := httptest.New(t, app) - e.GET("/" + expectedErrText).Expect().Status(httptest.StatusConflict).Body().Equal(expectedErrText) -} - -type ( - testServiceInterface1 interface { - Parse() string - } - - testServiceImpl1 struct { - inner string - } - - testServiceInterface2 interface { - } - - testServiceImpl2 struct { - tf int - } - - testControllerDependenciesSorter struct { - Service2 testServiceInterface2 - Service1 testServiceInterface1 - } -) - -func (s *testServiceImpl1) Parse() string { - return s.inner -} - -func (c *testControllerDependenciesSorter) Index() string { - return fmt.Sprintf("%#+v | %#+v", c.Service1, c.Service2) -} - -func TestStructFieldsSorter(t *testing.T) { // see https://github.com/kataras/iris/issues/1343 - b := New() - b.Register(&testServiceImpl1{"parser"}) - b.Register(&testServiceImpl2{24}) - s := b.Struct(&testControllerDependenciesSorter{}, 0) - - app := iris.New() - app.Get("/", s.MethodHandler("Index", 0)) - - e := httptest.New(t, app) - - expectedBody := `&hero_test.testServiceImpl1{inner:"parser"} | &hero_test.testServiceImpl2{tf:24}` - e.GET("/").Expect().Status(httptest.StatusOK).Body().Equal(expectedBody) -} diff --git a/httptest/httptest.go b/httptest/httptest.go index 379e385e..30383a53 100644 --- a/httptest/httptest.go +++ b/httptest/httptest.go @@ -6,9 +6,9 @@ import ( "net/http/httptest" "testing" - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/router" + "github.com/kataras/iris" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/router" "github.com/iris-contrib/httpexpect/v2" ) diff --git a/i18n/i18n.go b/i18n/i18n.go index 667d5c2c..75d59990 100644 --- a/i18n/i18n.go +++ b/i18n/i18n.go @@ -9,8 +9,8 @@ import ( "strings" "sync" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/router" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/router" "golang.org/x/text/language" ) diff --git a/i18n/loader.go b/i18n/loader.go index 5ef36934..501354d0 100644 --- a/i18n/loader.go +++ b/i18n/loader.go @@ -9,7 +9,7 @@ import ( "strings" "text/template" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" "github.com/BurntSushi/toml" "golang.org/x/text/language" diff --git a/iris.go b/iris.go index 5f84a3b4..2c835c36 100644 --- a/iris.go +++ b/iris.go @@ -13,22 +13,37 @@ import ( "sync" "time" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/errgroup" - "github.com/kataras/iris/v12/core/host" - "github.com/kataras/iris/v12/core/netutil" - "github.com/kataras/iris/v12/core/router" - "github.com/kataras/iris/v12/i18n" - requestLogger "github.com/kataras/iris/v12/middleware/logger" - "github.com/kataras/iris/v12/middleware/recover" - "github.com/kataras/iris/v12/view" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/errgroup" + "github.com/kataras/iris/core/host" + "github.com/kataras/iris/core/netutil" + "github.com/kataras/iris/core/router" + "github.com/kataras/iris/i18n" + requestLogger "github.com/kataras/iris/middleware/logger" + "github.com/kataras/iris/middleware/recover" + "github.com/kataras/iris/view" "github.com/kataras/golog" "github.com/kataras/tunnel" ) // Version is the current version number of the Iris Web Framework. -const Version = "12.2.0" +const Version = "stale" + +func init() { + golog.Fatal(`You have installed an invalid version. Install with: +go get -u github.com/kataras/iris/v12@latest + +If your Open Source project depends on that pre-go1.9 version please open an issue +at https://github.com/kataras/iris/issues/new and share your repository with us, +we will upgrade your project's code base to the latest version for free. + +If you have a commercial project that you cannot share publically, please contact with +@kataras at https://chat.iris-go.com. Assistance will be provided to you and your colleagues +for free. +`) + +} // Byte unit helpers. const ( @@ -408,7 +423,7 @@ func (app *Application) Shutdown(ctx stdContext.Context) error { // If error occurred while building the Application, the returns type of error will be an *errgroup.Group // which let the callers to inspect the errors and cause, usage: // -// import "github.com/kataras/iris/v12/core/errgroup" +// import "github.com/kataras/iris/core/errgroup" // // errgroup.Walk(app.Build(), func(typ interface{}, err error) { // app.Logger().Errorf("%s: %s", typ, err) diff --git a/macro/handler/handler.go b/macro/handler/handler.go index 42016cad..a8fe6a1f 100644 --- a/macro/handler/handler.go +++ b/macro/handler/handler.go @@ -3,9 +3,9 @@ package handler import ( - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/memstore" - "github.com/kataras/iris/v12/macro" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/memstore" + "github.com/kataras/iris/macro" ) // CanMakeHandler reports whether a macro template needs a special macro's evaluator handler to be validated diff --git a/macro/handler/handler_test.go b/macro/handler/handler_test.go deleted file mode 100644 index f2fed965..00000000 --- a/macro/handler/handler_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package handler - -import ( - "testing" - - "github.com/kataras/iris/v12/macro" -) - -func TestCanMakeHandler(t *testing.T) { - tests := []struct { - src string - needsHandler bool - }{ - {"/static/static", false}, - {"/{myparam}", false}, - {"/{myparam min(1)}", true}, - {"/{myparam else 500}", true}, - {"/{myparam else 404}", false}, - {"/{myparam:string}/static", false}, - {"/{myparam:int}", true}, - {"/static/{myparam:int}/static", true}, - {"/{myparam:path}", false}, - {"/{myparam:path min(1) else 404}", true}, - } - - availableMacros := *macro.Defaults - for i, tt := range tests { - tmpl, err := macro.Parse(tt.src, availableMacros) - if err != nil { - t.Fatalf("[%d] '%s' failed to be parsed: %v", i, tt.src, err) - } - - if got := CanMakeHandler(tmpl); got != tt.needsHandler { - if tt.needsHandler { - t.Fatalf("[%d] '%s' expected to be able to generate an evaluator handler instead of a nil one", i, tt.src) - } else { - t.Fatalf("[%d] '%s' should not need an evaluator handler", i, tt.src) - } - } - } -} diff --git a/macro/interpreter/lexer/lexer.go b/macro/interpreter/lexer/lexer.go index 76d91c4d..7bd288b6 100644 --- a/macro/interpreter/lexer/lexer.go +++ b/macro/interpreter/lexer/lexer.go @@ -1,7 +1,7 @@ package lexer import ( - "github.com/kataras/iris/v12/macro/interpreter/token" + "github.com/kataras/iris/macro/interpreter/token" ) // Lexer helps us to read/scan characters of a source and resolve their token types. diff --git a/macro/interpreter/lexer/lexer_test.go b/macro/interpreter/lexer/lexer_test.go deleted file mode 100644 index 6a6b8605..00000000 --- a/macro/interpreter/lexer/lexer_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package lexer - -import ( - "testing" - - "github.com/kataras/iris/v12/macro/interpreter/token" -) - -func TestNextToken(t *testing.T) { - input := `{id:int min(1) max(5) else 404}` - - tests := []struct { - expectedType token.Type - expectedLiteral string - }{ - {token.LBRACE, "{"}, // 0 - {token.IDENT, "id"}, // 1 - {token.COLON, ":"}, // 2 - {token.IDENT, "int"}, // 3 - {token.IDENT, "min"}, // 4 - {token.LPAREN, "("}, // 5 - {token.INT, "1"}, // 6 - {token.RPAREN, ")"}, // 7 - {token.IDENT, "max"}, // 8 - {token.LPAREN, "("}, // 9 - {token.INT, "5"}, // 10 - {token.RPAREN, ")"}, // 11 - {token.ELSE, "else"}, // 12 - {token.INT, "404"}, // 13 - {token.RBRACE, "}"}, // 14 - } - - l := New(input) - - for i, tt := range tests { - tok := l.NextToken() - - if tok.Type != tt.expectedType { - t.Fatalf("tests[%d] - tokentype wrong. expected=%q, got=%q", - i, tt.expectedType, tok.Type) - } - - if tok.Literal != tt.expectedLiteral { - t.Fatalf("tests[%d] - literal wrong. expected=%q, got=%q", - i, tt.expectedLiteral, tok.Literal) - } - - } -} - -// EMEINA STO: -// 30/232 selida apto making a interpeter in Go. -// den ekana to skipWhitespaces giati skeftomai -// an borei na to xreiastw 9a dw aurio. diff --git a/macro/interpreter/parser/parser.go b/macro/interpreter/parser/parser.go index ab199186..8c89202b 100644 --- a/macro/interpreter/parser/parser.go +++ b/macro/interpreter/parser/parser.go @@ -5,9 +5,9 @@ import ( "strconv" "strings" - "github.com/kataras/iris/v12/macro/interpreter/ast" - "github.com/kataras/iris/v12/macro/interpreter/lexer" - "github.com/kataras/iris/v12/macro/interpreter/token" + "github.com/kataras/iris/macro/interpreter/ast" + "github.com/kataras/iris/macro/interpreter/lexer" + "github.com/kataras/iris/macro/interpreter/token" ) // Parse takes a route "fullpath" diff --git a/macro/interpreter/parser/parser_test.go b/macro/interpreter/parser/parser_test.go deleted file mode 100644 index cfc152f8..00000000 --- a/macro/interpreter/parser/parser_test.go +++ /dev/null @@ -1,399 +0,0 @@ -package parser - -import ( - "fmt" - "reflect" - "strings" - "testing" - - "github.com/kataras/iris/v12/macro/interpreter/ast" -) - -type simpleParamType string - -func (pt simpleParamType) Indent() string { return string(pt) } - -type masterParamType simpleParamType - -func (pt masterParamType) Indent() string { return string(pt) } -func (pt masterParamType) Master() bool { return true } - -type wildcardParamType string - -func (pt wildcardParamType) Indent() string { return string(pt) } -func (pt wildcardParamType) Trailing() bool { return true } - -type aliasedParamType []string - -func (pt aliasedParamType) Indent() string { return string(pt[0]) } -func (pt aliasedParamType) Alias() string { return pt[1] } - -var ( - paramTypeString = masterParamType("string") - paramTypeNumber = aliasedParamType{"number", "int"} - paramTypeInt64 = aliasedParamType{"int64", "long"} - paramTypeUint8 = simpleParamType("uint8") - paramTypeUint64 = simpleParamType("uint64") - paramTypeBool = aliasedParamType{"bool", "boolean"} - paramTypeAlphabetical = simpleParamType("alphabetical") - paramTypeFile = simpleParamType("file") - paramTypePath = wildcardParamType("path") -) - -var testParamTypes = []ast.ParamType{ - paramTypeString, - paramTypeNumber, paramTypeInt64, paramTypeUint8, paramTypeUint64, - paramTypeBool, - paramTypeAlphabetical, paramTypeFile, paramTypePath, -} - -func TestParseParamError(t *testing.T) { - // fail - illegalChar := '$' - - input := "{id" + string(illegalChar) + "int range(1,5) else 404}" - p := NewParamParser(input) - - _, err := p.Parse(testParamTypes) - - if err == nil { - t.Fatalf("expecting not empty error on input '%s'", input) - } - - illIdx := strings.IndexRune(input, illegalChar) - expectedErr := fmt.Sprintf("[%d:%d] illegal token: %s", illIdx, illIdx, "$") - if got := err.Error(); got != expectedErr { - t.Fatalf("expecting error to be '%s' but got: %s", expectedErr, got) - } - // - - // success - input2 := "{id:uint64 range(1,5) else 404}" - p.Reset(input2) - _, err = p.Parse(testParamTypes) - - if err != nil { - t.Fatalf("expecting empty error on input '%s', but got: %s", input2, err.Error()) - } - // -} - -// mustLookupParamType same as `ast.LookupParamType` but it panics if "indent" does not match with a valid Param Type. -func mustLookupParamType(indent string) ast.ParamType { - pt, found := ast.LookupParamType(indent, testParamTypes...) - if !found { - panic("param type '" + indent + "' is not part of the provided param types") - } - - return pt -} - -func TestParseParam(t *testing.T) { - tests := []struct { - valid bool - expectedStatement ast.ParamStatement - }{ - { - true, - ast.ParamStatement{ - Src: "{id:int min(1) max(5) else 404}", - Name: "id", - Type: mustLookupParamType("number"), - Funcs: []ast.ParamFunc{ - { - Name: "min", - Args: []string{"1"}, - }, - { - Name: "max", - Args: []string{"5"}, - }, - }, - ErrorCode: 404, - }, - }, // 0 - - { - true, - ast.ParamStatement{ - // test alias of int. - Src: "{id:number range(1,5)}", - Name: "id", - Type: mustLookupParamType("number"), - Funcs: []ast.ParamFunc{ - { - Name: "range", - Args: []string{"1", "5"}, - }, - }, - ErrorCode: 404, - }, - }, // 1 - { - true, - ast.ParamStatement{ - Src: "{file:path contains(.)}", - Name: "file", - Type: mustLookupParamType("path"), - Funcs: []ast.ParamFunc{ - { - Name: "contains", - Args: []string{"."}, - }, - }, - ErrorCode: 404, - }, - }, // 2 - { - true, - ast.ParamStatement{ - Src: "{username:alphabetical}", - Name: "username", - Type: mustLookupParamType("alphabetical"), - ErrorCode: 404, - }, - }, // 3 - { - true, - ast.ParamStatement{ - Src: "{myparam}", - Name: "myparam", - Type: mustLookupParamType("string"), - ErrorCode: 404, - }, - }, // 4 - { - false, - ast.ParamStatement{ - Src: "{myparam_:thisianunexpected}", - Name: "myparam_", - Type: nil, - ErrorCode: 404, - }, - }, // 5 - { - true, - ast.ParamStatement{ - Src: "{myparam2}", - Name: "myparam2", // we now allow integers to the parameter names. - Type: ast.GetMasterParamType(testParamTypes...), - ErrorCode: 404, - }, - }, // 6 - { - true, - ast.ParamStatement{ - Src: "{id:int even()}", // test param funcs without any arguments (LPAREN peek for RPAREN) - Name: "id", - Type: mustLookupParamType("number"), - Funcs: []ast.ParamFunc{ - { - Name: "even", - }, - }, - ErrorCode: 404, - }, - }, // 7 - { - true, - ast.ParamStatement{ - Src: "{id:int64 else 404}", - Name: "id", - Type: mustLookupParamType("int64"), - ErrorCode: 404, - }, - }, // 8 - { - true, - ast.ParamStatement{ - Src: "{id:long else 404}", // backwards-compatible test. - Name: "id", - Type: mustLookupParamType("int64"), - ErrorCode: 404, - }, - }, // 9 - { - true, - ast.ParamStatement{ - Src: "{id:long else 404}", - Name: "id", - Type: mustLookupParamType("int64"), // backwards-compatible test of LookupParamType. - ErrorCode: 404, - }, - }, // 10 - { - true, - ast.ParamStatement{ - Src: "{has:bool else 404}", - Name: "has", - Type: mustLookupParamType("bool"), - ErrorCode: 404, - }, - }, // 11 - { - true, - ast.ParamStatement{ - Src: "{has:boolean else 404}", // backwards-compatible test. - Name: "has", - Type: mustLookupParamType("bool"), - ErrorCode: 404, - }, - }, // 12 - - } - - p := new(ParamParser) - for i, tt := range tests { - p.Reset(tt.expectedStatement.Src) - resultStmt, err := p.Parse(testParamTypes) - - if tt.valid && err != nil { - t.Fatalf("tests[%d] - error %s", i, err.Error()) - } else if !tt.valid && err == nil { - t.Fatalf("tests[%d] - expected to be a failure", i) - } - - if resultStmt != nil { // is valid here - if !reflect.DeepEqual(tt.expectedStatement, *resultStmt) { - t.Fatalf("tests[%d] - wrong statement, expected and result differs. Details:\n%#v\n%#v", i, tt.expectedStatement, *resultStmt) - } - } - - } -} - -func TestParse(t *testing.T) { - tests := []struct { - path string - valid bool - expectedStatements []ast.ParamStatement - }{ - { - "/api/users/{id:int min(1) max(5) else 404}", true, - []ast.ParamStatement{ - { - Src: "{id:int min(1) max(5) else 404}", - Name: "id", - Type: paramTypeNumber, - Funcs: []ast.ParamFunc{ - { - Name: "min", - Args: []string{"1"}, - }, - { - Name: "max", - Args: []string{"5"}, - }, - }, - ErrorCode: 404, - }, - }, - }, // 0 - { - "/admin/{id:uint64 range(1,5)}", true, - []ast.ParamStatement{ - { - Src: "{id:uint64 range(1,5)}", - Name: "id", - Type: paramTypeUint64, - Funcs: []ast.ParamFunc{ - { - Name: "range", - Args: []string{"1", "5"}, - }, - }, - ErrorCode: 404, - }, - }, - }, // 1 - { - "/files/{file:path contains(.)}", true, - []ast.ParamStatement{ - { - Src: "{file:path contains(.)}", - Name: "file", - Type: paramTypePath, - Funcs: []ast.ParamFunc{ - { - Name: "contains", - Args: []string{"."}, - }, - }, - ErrorCode: 404, - }, - }, - }, // 2 - { - "/profile/{username:alphabetical}", true, - []ast.ParamStatement{ - { - Src: "{username:alphabetical}", - Name: "username", - Type: paramTypeAlphabetical, - ErrorCode: 404, - }, - }, - }, // 3 - { - "/something/here/{myparam}", true, - []ast.ParamStatement{ - { - Src: "{myparam}", - Name: "myparam", - Type: paramTypeString, - ErrorCode: 404, - }, - }, - }, // 4 - { - "/unexpected/{myparam_:thisianunexpected}", false, - []ast.ParamStatement{ - { - Src: "{myparam_:thisianunexpected}", - Name: "myparam_", - Type: nil, - ErrorCode: 404, - }, - }, - }, // 5 - { - "/p2/{myparam2}", true, - []ast.ParamStatement{ - { - Src: "{myparam2}", - Name: "myparam2", // we now allow integers to the parameter names. - Type: paramTypeString, - ErrorCode: 404, - }, - }, - }, // 6 - { - "/assets/{file:path}/invalid", false, // path should be in the end segment - []ast.ParamStatement{ - { - Src: "{file:path}", - Name: "file", - Type: paramTypePath, - ErrorCode: 404, - }, - }, - }, // 7 - } - for i, tt := range tests { - statements, err := Parse(tt.path, testParamTypes) - - if tt.valid && err != nil { - t.Fatalf("tests[%d] - error %s", i, err.Error()) - } else if !tt.valid && err == nil { - t.Fatalf("tests[%d] - expected to be a failure", i) - } - for j := range statements { - for l := range tt.expectedStatements { - if !reflect.DeepEqual(tt.expectedStatements[l], *statements[j]) { - t.Fatalf("tests[%d] - wrong statements, expected and result differs. Details:\n%#v\n%#v", i, tt.expectedStatements[l], *statements[j]) - } - } - } - - } -} diff --git a/macro/macro_test.go b/macro/macro_test.go deleted file mode 100644 index 123ea69f..00000000 --- a/macro/macro_test.go +++ /dev/null @@ -1,471 +0,0 @@ -package macro - -import ( - "reflect" - "strconv" - "testing" -) - -// Most important tests to look: -// ../parser/parser_test.go -// ../lexer/lexer_test.go - -func TestGoodParamFunc(t *testing.T) { - good1 := func(min int, max int) func(string) bool { - return func(paramValue string) bool { - return true - } - } - - good2 := func(min uint64, max uint64) func(string) bool { - return func(paramValue string) bool { - return true - } - } - - notgood1 := func(min int, max int) bool { - return false - } - - if !goodParamFunc(reflect.TypeOf(good1)) { - t.Fatalf("expected good1 func to be good but it's not") - } - - if !goodParamFunc(reflect.TypeOf(good2)) { - t.Fatalf("expected good2 func to be good but it's not") - } - - if goodParamFunc(reflect.TypeOf(notgood1)) { - t.Fatalf("expected notgood1 func to be the worst") - } -} - -func TestGoodParamFuncName(t *testing.T) { - tests := []struct { - name string - good bool - }{ - {"range", true}, - {"_range", true}, - {"range_", true}, - {"r_ange", true}, - // numbers or other symbols are invalid. - {"range1", false}, - {"2range", false}, - {"r@nge", false}, - {"rang3", false}, - } - for i, tt := range tests { - isGood := goodParamFuncName(tt.name) - if tt.good && !isGood { - t.Fatalf("tests[%d] - expecting valid name but got invalid for name %s", i, tt.name) - } else if !tt.good && isGood { - t.Fatalf("tests[%d] - expecting invalid name but got valid for name %s", i, tt.name) - } - } -} - -func testEvaluatorRaw(t *testing.T, macroEvaluator *Macro, input string, expectedType reflect.Kind, pass bool, i int) { - if macroEvaluator.Evaluator == nil && pass { - return // if not evaluator defined then it should allow everything. - } - value, passed := macroEvaluator.Evaluator(input) - if pass != passed { - t.Fatalf("%s - tests[%d] - expecting[pass] %v but got %v", t.Name(), i, pass, passed) - } - - if !passed { - return - } - - if value == nil && expectedType != reflect.Invalid { - t.Fatalf("%s - tests[%d] - expecting[value] to not be nil", t.Name(), i) - } - - if v := reflect.ValueOf(value); v.Kind() != expectedType { - t.Fatalf("%s - tests[%d] - expecting[value.Kind] %v but got %v", t.Name(), i, expectedType, v.Kind()) - } -} - -func TestStringEvaluatorRaw(t *testing.T) { - tests := []struct { - pass bool - input string - }{ - {true, "astring"}, // 0 - {true, "astringwith_numb3rS_and_symbol$"}, // 1 - {true, "32321"}, // 2 - {true, "main.css"}, // 3 - {true, "/assets/main.css"}, // 4 - // false never - } // 0 - - for i, tt := range tests { - testEvaluatorRaw(t, String, tt.input, reflect.String, tt.pass, i) - } -} - -func TestIntEvaluatorRaw(t *testing.T) { - x64 := strconv.IntSize == 64 - - tests := []struct { - pass bool - input string - }{ - {false, "astring"}, // 0 - {false, "astringwith_numb3rS_and_symbol$"}, // 1 - {true, "32321"}, // 2 - {x64, "9223372036854775807" /* max int64 */}, // 3 - {x64, "-9223372036854775808" /* min int64 */}, // 4 - {false, "-18446744073709553213213213213213121615"}, // 5 - {false, "42 18446744073709551615"}, // 6 - {false, "--42"}, // 7 - {false, "+42"}, // 8 - {false, "main.css"}, // 9 - {false, "/assets/main.css"}, // 10 - } - - for i, tt := range tests { - testEvaluatorRaw(t, Int, tt.input, reflect.Int, tt.pass, i) - } -} - -func TestInt8EvaluatorRaw(t *testing.T) { - tests := []struct { - pass bool - input string - }{ - {false, "astring"}, // 0 - {false, "astringwith_numb3rS_and_symbol$"}, // 1 - {false, "32321"}, // 2 - {true, "127" /* max int8 */}, // 3 - {true, "-128" /* min int8 */}, // 4 - {false, "128"}, // 5 - {false, "-129"}, // 6 - {false, "-18446744073709553213213213213213121615"}, // 7 - {false, "42 18446744073709551615"}, // 8 - {false, "--42"}, // 9 - {false, "+42"}, // 10 - {false, "main.css"}, // 11 - {false, "/assets/main.css"}, // 12 - } - - for i, tt := range tests { - testEvaluatorRaw(t, Int8, tt.input, reflect.Int8, tt.pass, i) - } -} - -func TestInt16EvaluatorRaw(t *testing.T) { - tests := []struct { - pass bool - input string - }{ - {false, "astring"}, // 0 - {false, "astringwith_numb3rS_and_symbol$"}, // 1 - {true, "32321"}, // 2 - {true, "32767" /* max int16 */}, // 3 - {true, "-32768" /* min int16 */}, // 4 - {false, "-32769"}, // 5 - {false, "32768"}, // 6 - {false, "-18446744073709553213213213213213121615"}, // 7 - {false, "42 18446744073709551615"}, // 8 - {false, "--42"}, // 9 - {false, "+42"}, // 10 - {false, "main.css"}, // 11 - {false, "/assets/main.css"}, // 12 - } - - for i, tt := range tests { - testEvaluatorRaw(t, Int16, tt.input, reflect.Int16, tt.pass, i) - } -} - -func TestInt32EvaluatorRaw(t *testing.T) { - tests := []struct { - pass bool - input string - }{ - {false, "astring"}, // 0 - {false, "astringwith_numb3rS_and_symbol$"}, // 1 - {true, "32321"}, // 2 - {true, "1"}, // 3 - {true, "42"}, // 4 - {true, "2147483647" /* max int32 */}, // 5 - {true, "-2147483648" /* min int32 */}, // 6 - {false, "-2147483649"}, // 7 - {false, "2147483648"}, // 8 - {false, "-18446744073709553213213213213213121615"}, // 9 - {false, "42 18446744073709551615"}, // 10 - {false, "--42"}, // 11 - {false, "+42"}, // 12 - {false, "main.css"}, // 13 - {false, "/assets/main.css"}, // 14 - } - - for i, tt := range tests { - testEvaluatorRaw(t, Int32, tt.input, reflect.Int32, tt.pass, i) - } -} - -func TestInt64EvaluatorRaw(t *testing.T) { - tests := []struct { - pass bool - input string - }{ - {false, "astring"}, // 0 - {false, "astringwith_numb3rS_and_symbol$"}, // 1 - {false, "18446744073709551615"}, // 2 - {false, "92233720368547758079223372036854775807"}, // 3 - {false, "9223372036854775808 9223372036854775808"}, // 4 - {false, "main.css"}, // 5 - {false, "/assets/main.css"}, // 6 - {true, "9223372036854775807"}, // 7 - {true, "-9223372036854775808"}, // 8 - {true, "-0"}, // 9 - {true, "1"}, // 10 - {true, "-042"}, // 11 - {true, "142"}, // 12 - } - - for i, tt := range tests { - testEvaluatorRaw(t, Int64, tt.input, reflect.Int64, tt.pass, i) - } -} - -func TestUintEvaluatorRaw(t *testing.T) { - x64 := strconv.IntSize == 64 - - tests := []struct { - pass bool - input string - }{ - {false, "astring"}, // 0 - {false, "astringwith_numb3rS_and_symbol$"}, // 1 - {true, "32321"}, // 2 - {true, "1"}, // 3 - {true, "42"}, // 4 - {x64, "18446744073709551615" /* max uint64 */}, // 5 - {true, "4294967295" /* max uint32 */}, // 6 - {false, "-2147483649"}, // 7 - {true, "2147483648"}, // 8 - {false, "-18446744073709553213213213213213121615"}, // 9 - {false, "42 18446744073709551615"}, // 10 - {false, "--42"}, // 11 - {false, "+42"}, // 12 - {false, "main.css"}, // 13 - {false, "/assets/main.css"}, // 14 - } - - for i, tt := range tests { - testEvaluatorRaw(t, Uint, tt.input, reflect.Uint, tt.pass, i) - } -} - -func TestUint8EvaluatorRaw(t *testing.T) { - tests := []struct { - pass bool - input string - }{ - {false, "astring"}, // 0 - {false, "astringwith_numb3rS_and_symbol$"}, // 1 - {false, "-9223372036854775808"}, // 2 - {false, "main.css"}, // 3 - {false, "/assets/main.css"}, // 4 - {false, "92233720368547758079223372036854775807"}, // 5 - {false, "9223372036854775808 9223372036854775808"}, // 6 - {false, "-1"}, // 7 - {false, "-0"}, // 8 - {false, "+1"}, // 9 - {false, "18446744073709551615"}, // 10 - {false, "9223372036854775807"}, // 11 - {false, "021"}, // 12 - no leading zeroes are allowed. - {false, "300"}, // 13 - {true, "0"}, // 14 - {true, "255"}, // 15 - {true, "21"}, // 16 - } - - for i, tt := range tests { - testEvaluatorRaw(t, Uint8, tt.input, reflect.Uint8, tt.pass, i) - } -} - -func TestUint16EvaluatorRaw(t *testing.T) { - tests := []struct { - pass bool - input string - }{ - {false, "astring"}, // 0 - {false, "astringwith_numb3rS_and_symbol$"}, // 1 - {true, "32321"}, // 2 - {true, "65535" /* max uint16 */}, // 3 - {true, "0" /* min uint16 */}, // 4 - {false, "-32769"}, // 5 - {true, "32768"}, // 6 - {false, "-18446744073709553213213213213213121615"}, // 7 - {false, "42 18446744073709551615"}, // 8 - {false, "--42"}, // 9 - {false, "+42"}, // 10 - {false, "main.css"}, // 11 - {false, "/assets/main.css"}, // 12 - } - - for i, tt := range tests { - testEvaluatorRaw(t, Uint16, tt.input, reflect.Uint16, tt.pass, i) - } -} - -func TestUint32EvaluatorRaw(t *testing.T) { - tests := []struct { - pass bool - input string - }{ - {false, "astring"}, // 0 - {false, "astringwith_numb3rS_and_symbol$"}, // 1 - {true, "32321"}, // 2 - {true, "1"}, // 3 - {true, "42"}, // 4 - {true, "4294967295" /* max uint32*/}, // 5 - {true, "0" /* min uint32 */}, // 6 - {false, "-2147483649"}, // 7 - {true, "2147483648"}, // 8 - {false, "-18446744073709553213213213213213121615"}, // 9 - {false, "42 18446744073709551615"}, // 10 - {false, "--42"}, // 11 - {false, "+42"}, // 12 - {false, "main.css"}, // 13 - {false, "/assets/main.css"}, // 14 - } - - for i, tt := range tests { - testEvaluatorRaw(t, Uint32, tt.input, reflect.Uint32, tt.pass, i) - } -} - -func TestUint64EvaluatorRaw(t *testing.T) { - tests := []struct { - pass bool - input string - }{ - {false, "astring"}, // 0 - {false, "astringwith_numb3rS_and_symbol$"}, // 1 - {false, "-9223372036854775808"}, // 2 - {false, "main.css"}, // 3 - {false, "/assets/main.css"}, // 4 - {false, "92233720368547758079223372036854775807"}, // 5 - {false, "9223372036854775808 9223372036854775808"}, // 6 - {false, "-1"}, // 7 - {false, "-0"}, // 8 - {false, "+1"}, // 9 - {true, "18446744073709551615"}, // 10 - {true, "9223372036854775807"}, // 11 - {true, "0"}, // 12 - } - - for i, tt := range tests { - testEvaluatorRaw(t, Uint64, tt.input, reflect.Uint64, tt.pass, i) - } -} - -func TestAlphabeticalEvaluatorRaw(t *testing.T) { - tests := []struct { - pass bool - input string - }{ - {true, "astring"}, // 0 - {false, "astringwith_numb3rS_and_symbol$"}, // 1 - {false, "32321"}, // 2 - {false, "main.css"}, // 3 - {false, "/assets/main.css"}, // 4 - } - - for i, tt := range tests { - testEvaluatorRaw(t, Alphabetical, tt.input, reflect.String, tt.pass, i) - } -} - -func TestFileEvaluatorRaw(t *testing.T) { - tests := []struct { - pass bool - input string - }{ - {true, "astring"}, // 0 - {false, "astringwith_numb3rS_and_symbol$"}, // 1 - {true, "32321"}, // 2 - {true, "main.css"}, // 3 - {false, "/assets/main.css"}, // 4 - } - - for i, tt := range tests { - testEvaluatorRaw(t, File, tt.input, reflect.String, tt.pass, i) - } -} - -func TestPathEvaluatorRaw(t *testing.T) { - pathTests := []struct { - pass bool - input string - }{ - {true, "astring"}, // 0 - {true, "astringwith_numb3rS_and_symbol$"}, // 1 - {true, "32321"}, // 2 - {true, "main.css"}, // 3 - {true, "/assets/main.css"}, // 4 - {true, "disk/assets/main.css"}, // 5 - } - - for i, tt := range pathTests { - testEvaluatorRaw(t, Path, tt.input, reflect.String, tt.pass, i) - } -} - -func TestConvertBuilderFunc(t *testing.T) { - fn := func(min uint64, slice []string) func(string) bool { - return func(paramValue string) bool { - if expected, got := "ok", paramValue; expected != got { - t.Fatalf("paramValue is not the expected one: %s vs %s", expected, got) - } - - if expected, got := uint64(1), min; expected != got { - t.Fatalf("min argument is not the expected one: %d vs %d", expected, got) - } - - if expected, got := []string{"name1", "name2"}, slice; len(expected) == len(got) { - if expected, got := "name1", slice[0]; expected != got { - t.Fatalf("slice argument[%d] does not contain the expected value: %s vs %s", 0, expected, got) - } - - if expected, got := "name2", slice[1]; expected != got { - t.Fatalf("slice argument[%d] does not contain the expected value: %s vs %s", 1, expected, got) - } - } else { - t.Fatalf("slice argument is not the expected one, the length is difference: %d vs %d", len(expected), len(got)) - } - - return true - } - } - - evalFunc := convertBuilderFunc(fn) - if !evalFunc([]string{"1", "[name1,name2]"}).Call([]reflect.Value{reflect.ValueOf("ok")})[0].Interface().(bool) { - t.Fatalf("failed, it should fail already") - } - - fnSimplify := func(requestParamValue string) bool { - return requestParamValue == "kataras" - } - - evalFunc = convertBuilderFunc(fnSimplify) - if !evalFunc([]string{}).Call([]reflect.Value{reflect.ValueOf("kataras")})[0].Interface().(bool) { - t.Fatalf("it should pass, the combile arguments are empty and the given request value is the expected one") - } - - defer func() { - if r := recover(); r == nil { - t.Fatalf("it should panic, the combile arguments are more than one") - } - }() - - // should panic. - evalFunc([]string{"1"}).Call([]reflect.Value{reflect.ValueOf("kataras")}) -} diff --git a/macro/macros.go b/macro/macros.go index f88aca06..99637182 100644 --- a/macro/macros.go +++ b/macro/macros.go @@ -4,7 +4,7 @@ import ( "strconv" "strings" - "github.com/kataras/iris/v12/macro/interpreter/ast" + "github.com/kataras/iris/macro/interpreter/ast" ) var ( diff --git a/macro/template.go b/macro/template.go index 845646fc..d0bdd238 100644 --- a/macro/template.go +++ b/macro/template.go @@ -3,8 +3,8 @@ package macro import ( "reflect" - "github.com/kataras/iris/v12/macro/interpreter/ast" - "github.com/kataras/iris/v12/macro/interpreter/parser" + "github.com/kataras/iris/macro/interpreter/ast" + "github.com/kataras/iris/macro/interpreter/parser" ) // Template contains a route's path full parsed template. diff --git a/middleware/basicauth/basicauth.go b/middleware/basicauth/basicauth.go index 79831dfb..5c0c88b1 100644 --- a/middleware/basicauth/basicauth.go +++ b/middleware/basicauth/basicauth.go @@ -8,8 +8,8 @@ import ( "strconv" "time" - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris" + "github.com/kataras/iris/context" ) func init() { diff --git a/middleware/basicauth/config.go b/middleware/basicauth/config.go index 3b885b14..84467c43 100644 --- a/middleware/basicauth/config.go +++ b/middleware/basicauth/config.go @@ -3,7 +3,7 @@ package basicauth import ( "time" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) const ( diff --git a/middleware/grpc/grpc.go b/middleware/grpc/grpc.go index b073fdf1..46006791 100644 --- a/middleware/grpc/grpc.go +++ b/middleware/grpc/grpc.go @@ -4,7 +4,7 @@ import ( "net/http" "strings" - "github.com/kataras/iris/v12/core/router" + "github.com/kataras/iris/core/router" ) // New returns a new gRPC Iris router wrapper for a gRPC server. @@ -13,7 +13,7 @@ import ( // The Iris server SHOULD run under HTTP/2 and clients too. // // Usage: -// import grpcWrapper "github.com/kataras/iris/v12/middleware/grpc" +// import grpcWrapper "github.com/kataras/iris/middleware/grpc" // [...] // app := iris.New() // grpcServer := grpc.NewServer() diff --git a/middleware/hcaptcha/hcaptcha.go b/middleware/hcaptcha/hcaptcha.go index e6cb41a3..0a330bd3 100644 --- a/middleware/hcaptcha/hcaptcha.go +++ b/middleware/hcaptcha/hcaptcha.go @@ -7,7 +7,7 @@ import ( "net/http" "net/url" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) func init() { diff --git a/middleware/jwt/jwt.go b/middleware/jwt/jwt.go index 00df6663..411d8ead 100644 --- a/middleware/jwt/jwt.go +++ b/middleware/jwt/jwt.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" "github.com/square/go-jose/v3" "github.com/square/go-jose/v3/jwt" diff --git a/middleware/jwt/jwt_test.go b/middleware/jwt/jwt_test.go deleted file mode 100644 index 0d30d6fd..00000000 --- a/middleware/jwt/jwt_test.go +++ /dev/null @@ -1,139 +0,0 @@ -// Package jwt_test contains simple Iris jwt tests. Most of the jwt functionality is already tested inside the jose package itself. -package jwt_test - -import ( - "os" - "testing" - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/httptest" - "github.com/kataras/iris/v12/middleware/jwt" -) - -type userClaims struct { - jwt.Claims - Username string -} - -const testMaxAge = 3 * time.Second - -// Random RSA verification and encryption. -func TestRSA(t *testing.T) { - j := jwt.RSA(testMaxAge) - t.Cleanup(func() { - os.Remove(jwt.DefaultSignFilename) - os.Remove(jwt.DefaultEncFilename) - }) - testWriteVerifyToken(t, j) -} - -// HMAC verification and encryption. -func TestHMAC(t *testing.T) { - j := jwt.HMAC(testMaxAge, "secret", "itsa16bytesecret") - testWriteVerifyToken(t, j) -} - -func TestNew_HMAC(t *testing.T) { - j, err := jwt.New(testMaxAge, jwt.HS256, []byte("secret")) - if err != nil { - t.Fatal(err) - } - err = j.WithEncryption(jwt.A128GCM, jwt.DIRECT, []byte("itsa16bytesecret")) - if err != nil { - t.Fatal(err) - } - - testWriteVerifyToken(t, j) -} - -// HMAC verification only (unecrypted). -func TestVerify(t *testing.T) { - j, err := jwt.New(testMaxAge, jwt.HS256, []byte("another secret")) - if err != nil { - t.Fatal(err) - } - testWriteVerifyToken(t, j) -} - -func testWriteVerifyToken(t *testing.T, j *jwt.JWT) { - t.Helper() - - j.Extractors = append(j.Extractors, jwt.FromJSON("access_token")) - standardClaims := jwt.Claims{Issuer: "an-issuer", Audience: jwt.Audience{"an-audience"}} - expectedClaims := userClaims{ - Claims: j.Expiry(standardClaims), - Username: "kataras", - } - - app := iris.New() - app.Get("/auth", func(ctx iris.Context) { - j.WriteToken(ctx, expectedClaims) - }) - - app.Post("/restricted", func(ctx iris.Context) { - var claims userClaims - if err := j.VerifyToken(ctx, &claims); err != nil { - ctx.StopWithStatus(iris.StatusUnauthorized) - return - } - - ctx.JSON(claims) - }) - - app.Post("/restricted_middleware_readclaims", j.Verify, func(ctx iris.Context) { - var claims userClaims - if err := jwt.ReadClaims(ctx, &claims); err != nil { - ctx.StopWithStatus(iris.StatusUnauthorized) - return - } - - ctx.JSON(claims) - }) - - app.Post("/restricted_middleware_get", j.Verify, func(ctx iris.Context) { - claims, err := jwt.Get(ctx) - if err != nil { - ctx.StopWithStatus(iris.StatusUnauthorized) - return - } - - ctx.JSON(claims) - }) - - e := httptest.New(t, app) - - // Get token. - rawToken := e.GET("/auth").Expect().Status(httptest.StatusOK).Body().Raw() - if rawToken == "" { - t.Fatalf("empty token") - } - - restrictedPaths := [...]string{"/restricted", "/restricted_middleware_readclaims", "/restricted_middleware_get"} - - now := time.Now() - for _, path := range restrictedPaths { - // Authorization Header. - e.POST(path).WithHeader("Authorization", "Bearer "+rawToken).Expect(). - Status(httptest.StatusOK).JSON().Equal(expectedClaims) - - // URL Query. - e.POST(path).WithQuery("token", rawToken).Expect(). - Status(httptest.StatusOK).JSON().Equal(expectedClaims) - - // JSON Body. - e.POST(path).WithJSON(iris.Map{"access_token": rawToken}).Expect(). - Status(httptest.StatusOK).JSON().Equal(expectedClaims) - - // Missing "Bearer". - e.POST(path).WithHeader("Authorization", rawToken).Expect(). - Status(httptest.StatusUnauthorized) - } - expireRemDur := testMaxAge - time.Since(now) - - // Expiration. - time.Sleep(expireRemDur /* -end */) - for _, path := range restrictedPaths { - e.POST(path).WithQuery("token", rawToken).Expect().Status(httptest.StatusUnauthorized) - } -} diff --git a/middleware/logger/config.go b/middleware/logger/config.go index cf6ef601..138037cf 100644 --- a/middleware/logger/config.go +++ b/middleware/logger/config.go @@ -3,7 +3,7 @@ package logger import ( "time" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) // The SkipperFunc signature, used to serve the main request without logs. diff --git a/middleware/logger/logger.go b/middleware/logger/logger.go index af61b639..164d79a5 100644 --- a/middleware/logger/logger.go +++ b/middleware/logger/logger.go @@ -6,7 +6,7 @@ import ( "strconv" "time" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" "github.com/ryanuber/columnize" ) diff --git a/middleware/methodoverride/methodoverride.go b/middleware/methodoverride/methodoverride.go index d6c2fbce..6a891417 100644 --- a/middleware/methodoverride/methodoverride.go +++ b/middleware/methodoverride/methodoverride.go @@ -5,8 +5,8 @@ import ( "net/http" "strings" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/router" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/router" ) type options struct { diff --git a/middleware/methodoverride/methodoverride_test.go b/middleware/methodoverride/methodoverride_test.go deleted file mode 100644 index fe6ec92d..00000000 --- a/middleware/methodoverride/methodoverride_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package methodoverride_test - -import ( - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/httptest" - "github.com/kataras/iris/v12/middleware/methodoverride" -) - -func TestMethodOverrideWrapper(t *testing.T) { - app := iris.New() - - mo := methodoverride.New( - // Defaults to nil. - // - methodoverride.SaveOriginalMethod("_originalMethod"), - // Default values. - // - // methodoverride.Methods(http.MethodPost), - // methodoverride.Headers("X-HTTP-Method", "X-HTTP-Method-Override", "X-Method-Override"), - // methodoverride.FormField("_method"), - // methodoverride.Query("_method"), - ) - // Register it with `WrapRouter`. - app.WrapRouter(mo) - - var ( - expectedDelResponse = "delete resp" - expectedPostResponse = "post resp" - ) - - app.Post("/path", func(ctx iris.Context) { - ctx.WriteString(expectedPostResponse) - }) - - app.Delete("/path", func(ctx iris.Context) { - ctx.WriteString(expectedDelResponse) - }) - - app.Delete("/path2", func(ctx iris.Context) { - _, err := ctx.Writef("%s%s", expectedDelResponse, ctx.Request().Context().Value("_originalMethod")) - if err != nil { - t.Fatal(err) - } - }) - - e := httptest.New(t, app) - - // Test headers. - e.POST("/path").WithHeader("X-HTTP-Method", iris.MethodDelete).Expect(). - Status(iris.StatusOK).Body().Equal(expectedDelResponse) - e.POST("/path").WithHeader("X-HTTP-Method-Override", iris.MethodDelete).Expect(). - Status(iris.StatusOK).Body().Equal(expectedDelResponse) - e.POST("/path").WithHeader("X-Method-Override", iris.MethodDelete).Expect(). - Status(iris.StatusOK).Body().Equal(expectedDelResponse) - - // Test form field value. - e.POST("/path").WithFormField("_method", iris.MethodDelete).Expect(). - Status(iris.StatusOK).Body().Equal(expectedDelResponse) - - // Test URL Query (although it's the same as form field in this case). - e.POST("/path").WithQuery("_method", iris.MethodDelete).Expect(). - Status(iris.StatusOK).Body().Equal(expectedDelResponse) - - // Test saved original method and - // Test without registered "POST" route. - e.POST("/path2").WithQuery("_method", iris.MethodDelete).Expect(). - Status(iris.StatusOK).Body().Equal(expectedDelResponse + iris.MethodPost) - - // Test simple POST request without method override fields. - e.POST("/path").Expect().Status(iris.StatusOK).Body().Equal(expectedPostResponse) - - // Test simple DELETE request. - e.DELETE("/path").Expect().Status(iris.StatusOK).Body().Equal(expectedDelResponse) -} diff --git a/middleware/pprof/pprof.go b/middleware/pprof/pprof.go index a71b2b10..9496b4b3 100644 --- a/middleware/pprof/pprof.go +++ b/middleware/pprof/pprof.go @@ -7,8 +7,8 @@ import ( rpprof "runtime/pprof" "strings" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/handlerconv" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/handlerconv" ) func init() { diff --git a/middleware/rate/rate.go b/middleware/rate/rate.go index 1dedb8f0..d595b9ef 100644 --- a/middleware/rate/rate.go +++ b/middleware/rate/rate.go @@ -7,7 +7,7 @@ import ( "sync" "time" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" "golang.org/x/time/rate" ) diff --git a/middleware/recaptcha/recaptcha.go b/middleware/recaptcha/recaptcha.go index 291e0995..ca28c060 100644 --- a/middleware/recaptcha/recaptcha.go +++ b/middleware/recaptcha/recaptcha.go @@ -7,8 +7,8 @@ import ( "net/url" "time" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/netutil" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/netutil" ) func init() { diff --git a/middleware/recover/recover.go b/middleware/recover/recover.go index 9208093f..4b9d96be 100644 --- a/middleware/recover/recover.go +++ b/middleware/recover/recover.go @@ -6,7 +6,7 @@ import ( "runtime" "strconv" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) func init() { diff --git a/middleware/requestid/requestid.go b/middleware/requestid/requestid.go index 9c242454..e14dcb52 100644 --- a/middleware/requestid/requestid.go +++ b/middleware/requestid/requestid.go @@ -5,7 +5,7 @@ import ( "encoding/hex" "net/http/httputil" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" "github.com/google/uuid" ) diff --git a/middleware/requestid/requestid_test.go b/middleware/requestid/requestid_test.go deleted file mode 100644 index a5478d4b..00000000 --- a/middleware/requestid/requestid_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package requestid_test - -import ( - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/httptest" - "github.com/kataras/iris/v12/middleware/requestid" -) - -func TestRequestID(t *testing.T) { - app := iris.New() - h := func(ctx iris.Context) { - ctx.WriteString(requestid.Get(ctx)) - } - - def := app.Party("/default") - { - def.Use(requestid.New()) - def.Get("/", h) - } - - const expectedCustomID = "my_id" - custom := app.Party("/custom") - { - customGen := func(ctx *context.Context) string { - return expectedCustomID - } - - custom.Use(requestid.New(customGen)) - custom.Get("/", h) - } - - const expectedErrMsg = "no id" - customWithErr := app.Party("/custom_err") - { - customGen := func(ctx *context.Context) string { - ctx.StopWithText(iris.StatusUnauthorized, expectedErrMsg) - return "" - } - - customWithErr.Use(requestid.New(customGen)) - customWithErr.Get("/", h) - } - - const expectedCustomIDFromOtherMiddleware = "my custom id" - changeID := app.Party("/custom_change_id") - { - changeID.Use(func(ctx iris.Context) { - ctx.SetID(expectedCustomIDFromOtherMiddleware) - ctx.Next() - }) - changeID.Use(requestid.New()) - changeID.Get("/", h) - } - - e := httptest.New(t, app) - e.GET("/default").Expect().Status(httptest.StatusOK).Body().NotEmpty() - e.GET("/custom").Expect().Status(httptest.StatusOK).Body().Equal(expectedCustomID) - e.GET("/custom_err").Expect().Status(httptest.StatusUnauthorized).Body().Equal(expectedErrMsg) - e.GET("/custom_change_id").Expect().Status(httptest.StatusOK).Body().Equal(expectedCustomIDFromOtherMiddleware) -} diff --git a/mvc/aliases.go b/mvc/aliases.go index b8f87c86..911f2d6f 100644 --- a/mvc/aliases.go +++ b/mvc/aliases.go @@ -1,8 +1,8 @@ package mvc import ( - "github.com/kataras/iris/v12/hero" - "github.com/kataras/iris/v12/versioning" + "github.com/kataras/iris/hero" + "github.com/kataras/iris/versioning" ) type ( diff --git a/mvc/controller.go b/mvc/controller.go index 939a6dcb..cf9f1ec7 100644 --- a/mvc/controller.go +++ b/mvc/controller.go @@ -5,10 +5,10 @@ import ( "reflect" "strings" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/router" - "github.com/kataras/iris/v12/hero" - "github.com/kataras/iris/v12/macro" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/router" + "github.com/kataras/iris/hero" + "github.com/kataras/iris/macro" ) // BaseController is the optional controller interface, if it's diff --git a/mvc/controller_handle_test.go b/mvc/controller_handle_test.go deleted file mode 100644 index 59038b42..00000000 --- a/mvc/controller_handle_test.go +++ /dev/null @@ -1,201 +0,0 @@ -package mvc_test - -import ( - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/httptest" - - . "github.com/kataras/iris/v12/mvc" -) - -// service -type ( - // these testService and testServiceImpl could be in lowercase, unexported - // but the `Say` method should be exported however we have those exported - // because of the controller handler test. - testService interface { - Say(string) string - } - testServiceImpl struct { - prefix string - } -) - -func (s *testServiceImpl) Say(message string) string { - return s.prefix + " " + message -} - -type testControllerHandle struct { - Ctx *context.Context - Service testService - - reqField string -} - -func (c *testControllerHandle) BeforeActivation(b BeforeActivation) { - b.Handle("GET", "/histatic", "HiStatic") - b.Handle("GET", "/hiservice", "HiService") - b.Handle("GET", "/hiservice/{ps:string}", "HiServiceBy") - b.Handle("GET", "/hiparam/{ps:string}", "HiParamBy") - b.Handle("GET", "/hiparamempyinput/{ps:string}", "HiParamEmptyInputBy") - b.HandleMany("GET", "/custom/{ps:string} /custom2/{ps:string}", "CustomWithParameter") - b.HandleMany("GET", "/custom3/{ps:string}/{pssecond:string}", "CustomWithParameters") -} - -// test `GetRoute` for custom routes. -func (c *testControllerHandle) AfterActivation(a AfterActivation) { - // change automatic parser's route change name. - rget := a.GetRoute("Get") - if rget == nil { - panic("route from function name: 'Get' doesn't exist on `AfterActivation`") - } - rget.Name = "index_route" - - // change a custom route's name. - r := a.GetRoute("HiStatic") - if r == nil { - panic("route from function name: HiStatic doesn't exist on `AfterActivation`") - } - // change the name here, and test if name changed in the handler. - r.Name = "hi_static_route" -} - -func (c *testControllerHandle) BeginRequest(ctx iris.Context) { - c.reqField = ctx.URLParam("reqfield") -} - -func (c *testControllerHandle) EndRequest(ctx iris.Context) {} - -func (c *testControllerHandle) Get() string { - if c.Ctx.GetCurrentRoute().Name() != "index_route" { - return "Get's route's name didn't change on AfterActivation" - } - return "index" -} - -func (c *testControllerHandle) HiStatic() string { - if c.Ctx.GetCurrentRoute().Name() != "hi_static_route" { - return "HiStatic's route's name didn't change on AfterActivation" - } - - return c.reqField -} - -func (c *testControllerHandle) HiService() string { - return c.Service.Say("hi") -} - -func (c *testControllerHandle) HiServiceBy(v string) string { - return c.Service.Say("hi with param: " + v) -} - -func (c *testControllerHandle) HiParamBy(v string) string { - return v -} - -func (c *testControllerHandle) HiParamEmptyInputBy() string { - return "empty in but served with ctx.Params.Get('ps')=" + c.Ctx.Params().Get("ps") -} - -func (c *testControllerHandle) CustomWithParameter(param1 string) string { - return param1 -} - -func (c *testControllerHandle) CustomWithParameters(param1, param2 string) string { - return param1 + param2 -} - -type testSmallController struct{} - -// test ctx + id in the same time. -func (c *testSmallController) GetHiParamEmptyInputWithCtxBy(ctx *context.Context, id string) string { - return "empty in but served with ctx.Params.Get('param2')= " + ctx.Params().Get("param2") + " == id == " + id -} - -func TestControllerHandle(t *testing.T) { - app := iris.New() - m := New(app) - m.Register(&testServiceImpl{prefix: "service:"}) - m.Handle(new(testControllerHandle)) - m.Handle(new(testSmallController)) - - e := httptest.New(t, app) - - // test the index, is not part of the current package's implementation but do it. - e.GET("/").Expect().Status(httptest.StatusOK).Body().Equal("index") - - // the important things now. - - // this test ensures that the BeginRequest of the controller will be - // called correctly and also the controller is binded to the first input argument - // (which is the function's receiver, if any, in this case the *testController in go). - expectedReqField := "this is a request field filled by this url param" - e.GET("/histatic").WithQuery("reqfield", expectedReqField).Expect().Status(httptest.StatusOK). - Body().Equal(expectedReqField) - // this test makes sure that the binded values of the controller is handled correctly - // and can be used in a user-defined, dynamic "mvc handler". - e.GET("/hiservice").Expect().Status(httptest.StatusOK). - Body().Equal("service: hi") - e.GET("/hiservice/value").Expect().Status(httptest.StatusOK). - Body().Equal("service: hi with param: value") - // this worked with a temporary variadic on the resolvemethodfunc which is not - // correct design, I should split the path and params with the rest of implementation - // in order a simple template.Src can be given. - e.GET("/hiparam/value").Expect().Status(httptest.StatusOK). - Body().Equal("value") - e.GET("/hiparamempyinput/value").Expect().Status(httptest.StatusOK). - Body().Equal("empty in but served with ctx.Params.Get('ps')=value") - e.GET("/custom/value1").Expect().Status(httptest.StatusOK). - Body().Equal("value1") - e.GET("/custom2/value2").Expect().Status(httptest.StatusOK). - Body().Equal("value2") - e.GET("/custom3/value1/value2").Expect().Status(httptest.StatusOK). - Body().Equal("value1value2") - e.GET("/custom3/value1").Expect().Status(httptest.StatusNotFound) - - e.GET("/hi/param/empty/input/with/ctx/value").Expect().Status(httptest.StatusOK). - Body().Equal("empty in but served with ctx.Params.Get('param2')= value == id == value") -} - -type testControllerHandleWithDynamicPathPrefix struct { - Ctx iris.Context -} - -func (c *testControllerHandleWithDynamicPathPrefix) GetBy(id string) string { - params := c.Ctx.Params() - return params.Get("model") + params.Get("action") + id -} - -func TestControllerHandleWithDynamicPathPrefix(t *testing.T) { - app := iris.New() - New(app.Party("/api/data/{model:string}/{action:string}")).Handle(new(testControllerHandleWithDynamicPathPrefix)) - e := httptest.New(t, app) - e.GET("/api/data/mymodel/myaction/myid").Expect().Status(httptest.StatusOK). - Body().Equal("mymodelmyactionmyid") -} - -type testControllerGetBy struct{} - -func (c *testControllerGetBy) GetBy(age int64) *testCustomStruct { - return &testCustomStruct{ - Age: int(age), - Name: "name", - } -} - -func TestControllerGetByWithAllowMethods(t *testing.T) { - app := iris.New() - app.Configure(iris.WithFireMethodNotAllowed) - // ^ this 405 status will not be fired on POST: project/... because of - // .AllowMethods, but it will on PUT. - - New(app.Party("/project").AllowMethods(iris.MethodGet, iris.MethodPost)).Handle(new(testControllerGetBy)) - - e := httptest.New(t, app) - e.GET("/project/42").Expect().Status(httptest.StatusOK). - JSON().Equal(&testCustomStruct{Age: 42, Name: "name"}) - e.POST("/project/42").Expect().Status(httptest.StatusOK) - e.PUT("/project/42").Expect().Status(httptest.StatusMethodNotAllowed) -} diff --git a/mvc/controller_method_parser.go b/mvc/controller_method_parser.go index c5fcb7ba..70137a4c 100644 --- a/mvc/controller_method_parser.go +++ b/mvc/controller_method_parser.go @@ -8,8 +8,8 @@ import ( "strings" "unicode" - "github.com/kataras/iris/v12/core/router" - "github.com/kataras/iris/v12/macro" + "github.com/kataras/iris/core/router" + "github.com/kataras/iris/macro" ) const ( diff --git a/mvc/controller_method_result_test.go b/mvc/controller_method_result_test.go deleted file mode 100644 index 163bf1b1..00000000 --- a/mvc/controller_method_result_test.go +++ /dev/null @@ -1,271 +0,0 @@ -package mvc_test - -import ( - "errors" - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/httptest" - - . "github.com/kataras/iris/v12/mvc" -) - -type testControllerMethodResult struct { - Ctx *context.Context -} - -func (c *testControllerMethodResult) Get() Result { - return Response{ - Text: "Hello World!", - } -} - -func (c *testControllerMethodResult) GetWithStatus() Response { // or Result again, no problem. - return Response{ - Text: "This page doesn't exist", - Code: iris.StatusNotFound, - } -} - -type testCustomStruct struct { - Name string `json:"name" xml:"name"` - Age int `json:"age" xml:"age"` -} - -func (c *testControllerMethodResult) GetJson() Result { - var err error - if c.Ctx.URLParamExists("err") { - err = errors.New("error here") - } - return Response{ - Err: err, // if err != nil then it will fire the error's text with a BadRequest. - Object: testCustomStruct{Name: "Iris", Age: 2}, - } -} - -var things = []string{"thing 0", "thing 1", "thing 2"} - -func (c *testControllerMethodResult) GetThingWithTryBy(index int) Result { - failure := Response{ - Text: "thing does not exist", - Code: iris.StatusNotFound, - } - - return Try(func() Result { - // if panic because of index exceed the slice - // then the "failure" response will be returned instead. - return Response{Text: things[index]} - }, failure) -} - -func (c *testControllerMethodResult) GetThingWithTryDefaultBy(index int) Result { - return Try(func() Result { - // if panic because of index exceed the slice - // then the default failure response will be returned instead (400 bad request). - return Response{Text: things[index]} - }) -} - -func TestControllerMethodResult(t *testing.T) { - app := iris.New() - New(app).Handle(new(testControllerMethodResult)) - - e := httptest.New(t, app) - - e.GET("/").Expect().Status(iris.StatusOK). - Body().Equal("Hello World!") - - e.GET("/with/status").Expect().Status(iris.StatusNotFound). - Body().Equal("This page doesn't exist") - - e.GET("/json").Expect().Status(iris.StatusOK). - JSON().Equal(iris.Map{ - "name": "Iris", - "age": 2, - }) - - e.GET("/json").WithQuery("err", true).Expect(). - Status(iris.StatusBadRequest). - Body().Equal("error here") - - e.GET("/thing/with/try/1").Expect(). - Status(iris.StatusOK). - Body().Equal("thing 1") - // failure because of index exceed the slice - e.GET("/thing/with/try/3").Expect(). - Status(iris.StatusNotFound). - Body().Equal("thing does not exist") - - e.GET("/thing/with/try/default/3").Expect(). - Status(iris.StatusBadRequest). - Body().Equal("Bad Request") -} - -type testControllerMethodResultTypes struct { - Ctx *context.Context -} - -func (c *testControllerMethodResultTypes) GetText() string { - return "text" -} - -func (c *testControllerMethodResultTypes) GetStatus() int { - return iris.StatusBadGateway -} - -func (c *testControllerMethodResultTypes) GetTextWithStatusOk() (string, int) { - return "OK", iris.StatusOK -} - -// tests should have output arguments mixed -func (c *testControllerMethodResultTypes) GetStatusWithTextNotOkBy(first string, second string) (int, string) { - return iris.StatusForbidden, "NOT_OK_" + first + second -} - -func (c *testControllerMethodResultTypes) GetTextAndContentType() (string, string) { - return "text", "text/html" -} - -type testControllerMethodCustomResult struct { - HTML string -} - -// The only one required function to make that a custom Response dispatcher. -func (r testControllerMethodCustomResult) Dispatch(ctx *context.Context) { - ctx.HTML(r.HTML) -} - -func (c *testControllerMethodResultTypes) GetCustomResponse() testControllerMethodCustomResult { - return testControllerMethodCustomResult{"text"} -} - -func (c *testControllerMethodResultTypes) GetCustomResponseWithStatusOk() (testControllerMethodCustomResult, int) { - return testControllerMethodCustomResult{"OK"}, iris.StatusOK -} - -func (c *testControllerMethodResultTypes) GetCustomResponseWithStatusNotOk() (testControllerMethodCustomResult, int) { - return testControllerMethodCustomResult{"internal server error"}, iris.StatusInternalServerError -} - -func (c *testControllerMethodResultTypes) GetCustomStruct() testCustomStruct { - return testCustomStruct{"Iris", 2} -} - -func (c *testControllerMethodResultTypes) GetCustomStructWithStatusNotOk() (testCustomStruct, int) { - return testCustomStruct{"Iris", 2}, iris.StatusInternalServerError -} - -func (c *testControllerMethodResultTypes) GetCustomStructWithContentType() (testCustomStruct, string) { - return testCustomStruct{"Iris", 2}, "text/xml" -} - -func (c *testControllerMethodResultTypes) GetCustomStructWithError() (s testCustomStruct, err error) { - s = testCustomStruct{"Iris", 2} - if c.Ctx.URLParamExists("err") { - err = errors.New("omit return of testCustomStruct and fire error") - } - - // it should send the testCustomStruct as JSON if error is nil - // otherwise it should fire the default error(BadRequest) with the error's text. - return -} - -func TestControllerMethodResultTypes(t *testing.T) { - app := iris.New() - New(app).Handle(new(testControllerMethodResultTypes)) - - e := httptest.New(t, app) - - e.GET("/text").Expect().Status(iris.StatusOK). - Body().Equal("text") - - e.GET("/status").Expect().Status(iris.StatusBadGateway) - - e.GET("/text/with/status/ok").Expect().Status(iris.StatusOK). - Body().Equal("OK") - - e.GET("/status/with/text/not/ok/first/second").Expect().Status(iris.StatusForbidden). - Body().Equal("NOT_OK_firstsecond") - // Author's note: <-- if that fails means that the last binder called for both input args, - // see path_param_binder.go - - e.GET("/text/and/content/type").Expect().Status(iris.StatusOK). - ContentType("text/html", "utf-8"). - Body().Equal("text") - - e.GET("/custom/response").Expect().Status(iris.StatusOK). - ContentType("text/html", "utf-8"). - Body().Equal("text") - e.GET("/custom/response/with/status/ok").Expect().Status(iris.StatusOK). - ContentType("text/html", "utf-8"). - Body().Equal("OK") - e.GET("/custom/response/with/status/not/ok").Expect().Status(iris.StatusInternalServerError). - ContentType("text/html", "utf-8"). - Body().Equal("internal server error") - - expectedResultFromCustomStruct := map[string]interface{}{ - "name": "Iris", - "age": 2, - } - e.GET("/custom/struct").Expect().Status(iris.StatusOK). - JSON().Equal(expectedResultFromCustomStruct) - e.GET("/custom/struct/with/status/not/ok").Expect().Status(iris.StatusInternalServerError). - JSON().Equal(expectedResultFromCustomStruct) - e.GET("/custom/struct/with/content/type").Expect().Status(iris.StatusOK). - ContentType("text/xml", "utf-8") - e.GET("/custom/struct/with/error").Expect().Status(iris.StatusOK). - JSON().Equal(expectedResultFromCustomStruct) - e.GET("/custom/struct/with/error").WithQuery("err", true).Expect(). - Status(iris.StatusBadRequest). // the default status code if error is not nil - // the content should be not JSON it should be the status code's text - // it will fire the error's text - Body().Equal("omit return of testCustomStruct and fire error") -} - -type testControllerViewResultRespectCtxViewData struct { - T *testing.T -} - -func (t *testControllerViewResultRespectCtxViewData) BeginRequest(ctx *context.Context) { - ctx.ViewData("name_begin", "iris_begin") -} - -func (t *testControllerViewResultRespectCtxViewData) EndRequest(ctx *context.Context) { - // check if data is not overridden by return View {Data: context.Map...} - - dataWritten := ctx.GetViewData() - if dataWritten == nil { - t.T.Fatalf("view data is nil, both BeginRequest and Get failed to write the data") - return - } - - if dataWritten["name_begin"] == nil { - t.T.Fatalf(`view data[name_begin] is nil, - BeginRequest's ctx.ViewData call have been overridden by Get's return View {Data: }. - Total view data: %v`, dataWritten) - } - - if dataWritten["name"] == nil { - t.T.Fatalf("view data[name] is nil, Get's return View {Data: } didn't work. Total view data: %v", dataWritten) - } -} - -func (t *testControllerViewResultRespectCtxViewData) Get() Result { - return View{ - Name: "doesnt_exists.html", - Data: context.Map{"name": "iris"}, // we care about this only. - Code: iris.StatusInternalServerError, - } -} - -func TestControllerViewResultRespectCtxViewData(t *testing.T) { - app := iris.New() - m := New(app.Party("/")) - m.Register(t) - m.Handle(new(testControllerViewResultRespectCtxViewData)) - - e := httptest.New(t, app) - - e.GET("/").Expect().Status(iris.StatusInternalServerError) -} diff --git a/mvc/controller_test.go b/mvc/controller_test.go deleted file mode 100644 index 62233b35..00000000 --- a/mvc/controller_test.go +++ /dev/null @@ -1,758 +0,0 @@ -// black-box testing -package mvc_test - -import ( - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/router" - "github.com/kataras/iris/v12/hero" - "github.com/kataras/iris/v12/httptest" - - . "github.com/kataras/iris/v12/mvc" -) - -type testController struct { - Ctx *context.Context -} - -var writeMethod = func(ctx *context.Context) { - ctx.Writef(ctx.Method()) -} - -func (c *testController) Get() { - writeMethod(c.Ctx) -} - -func (c *testController) Post() { - writeMethod(c.Ctx) -} - -func (c *testController) Put() { - writeMethod(c.Ctx) -} - -func (c *testController) Delete() { - writeMethod(c.Ctx) -} - -func (c *testController) Connect() { - writeMethod(c.Ctx) -} - -func (c *testController) Head() { - writeMethod(c.Ctx) -} - -func (c *testController) Patch() { - writeMethod(c.Ctx) -} - -func (c *testController) Options() { - writeMethod(c.Ctx) -} - -func (c *testController) Trace() { - writeMethod(c.Ctx) -} - -type ( - testControllerAll struct{ Ctx *context.Context } - testControllerAny struct{ Ctx *context.Context } // exactly the same as All. -) - -func (c *testControllerAll) All() { - writeMethod(c.Ctx) -} - -func (c *testControllerAny) Any() { - writeMethod(c.Ctx) -} - -func TestControllerMethodFuncs(t *testing.T) { - app := iris.New() - - New(app).Handle(new(testController)) - New(app.Party("/all")).Handle(new(testControllerAll)) - New(app.Party("/any")).Handle(new(testControllerAny)) - - e := httptest.New(t, app) - for _, method := range router.AllMethods { - - e.Request(method, "/").Expect().Status(iris.StatusOK). - Body().Equal(method) - - e.Request(method, "/all").Expect().Status(iris.StatusOK). - Body().Equal(method) - - e.Request(method, "/any").Expect().Status(iris.StatusOK). - Body().Equal(method) - } -} - -type testControllerBeginAndEndRequestFunc struct { - Ctx *context.Context - - Username string -} - -// called before of every method (Get() or Post()). -// -// useful when more than one methods using the -// same request values or context's function calls. -func (c *testControllerBeginAndEndRequestFunc) BeginRequest(ctx *context.Context) { - c.Username = ctx.Params().Get("username") -} - -// called after every method (Get() or Post()). -func (c *testControllerBeginAndEndRequestFunc) EndRequest(ctx *context.Context) { - ctx.Writef("done") // append "done" to the response -} - -func (c *testControllerBeginAndEndRequestFunc) Get() { - c.Ctx.Writef(c.Username) -} - -func (c *testControllerBeginAndEndRequestFunc) Post() { - c.Ctx.Writef(c.Username) -} - -func TestControllerBeginAndEndRequestFunc(t *testing.T) { - app := iris.New() - New(app.Party("/profile/{username}")). - Handle(new(testControllerBeginAndEndRequestFunc)) - - e := httptest.New(t, app) - usernames := []string{ - "kataras", - "makis", - "efi", - "rg", - "bill", - "whoisyourdaddy", - } - doneResponse := "done" - - for _, username := range usernames { - e.GET("/profile/" + username).Expect().Status(iris.StatusOK). - Body().Equal(username + doneResponse) - e.POST("/profile/" + username).Expect().Status(iris.StatusOK). - Body().Equal(username + doneResponse) - } -} - -func TestControllerBeginAndEndRequestFuncBindMiddleware(t *testing.T) { - app := iris.New() - usernames := map[string]bool{ - "kataras": true, - "makis": false, - "efi": true, - "rg": false, - "bill": true, - "whoisyourdaddy": false, - } - middlewareCheck := func(ctx *context.Context) { - for username, allow := range usernames { - if ctx.Params().Get("username") == username && allow { - ctx.Next() - return - } - } - - ctx.StatusCode(iris.StatusForbidden) - ctx.Writef("forbidden") - } - - app.PartyFunc("/profile/{username}", func(r iris.Party) { - r.Use(middlewareCheck) - New(r).Handle(new(testControllerBeginAndEndRequestFunc)) - }) - - e := httptest.New(t, app) - - doneResponse := "done" - - for username, allow := range usernames { - getEx := e.GET("/profile/" + username).Expect() - if allow { - getEx.Status(iris.StatusOK). - Body().Equal(username + doneResponse) - } else { - getEx.Status(iris.StatusForbidden).Body().Equal("forbidden") - } - - postEx := e.POST("/profile/" + username).Expect() - if allow { - postEx.Status(iris.StatusOK). - Body().Equal(username + doneResponse) - } else { - postEx.Status(iris.StatusForbidden).Body().Equal("forbidden") - } - } -} - -type Model struct { - Username string -} - -type testControllerEndRequestAwareness struct { - Ctx *context.Context -} - -func (c *testControllerEndRequestAwareness) Get() { - username := c.Ctx.Params().Get("username") - c.Ctx.Values().Set(c.Ctx.Application().ConfigurationReadOnly().GetViewDataContextKey(), - map[string]interface{}{ - "TestModel": Model{Username: username}, - "myModel": Model{Username: username + "2"}, - }) -} - -func writeModels(ctx *context.Context, names ...string) { - if expected, got := len(names), len(ctx.GetViewData()); expected != got { - ctx.Writef("expected view data length: %d but got: %d for names: %s", expected, got, names) - return - } - - for _, name := range names { - - m, ok := ctx.GetViewData()[name] - if !ok { - ctx.Writef("fail load and set the %s", name) - return - } - - model, ok := m.(Model) - if !ok { - ctx.Writef("fail to override the %s' name by the tag", name) - return - } - - ctx.Writef(model.Username) - } -} - -func (c *testControllerEndRequestAwareness) BeginRequest(ctx *context.Context) {} -func (c *testControllerEndRequestAwareness) EndRequest(ctx *context.Context) { - writeModels(ctx, "TestModel", "myModel") -} - -func TestControllerEndRequestAwareness(t *testing.T) { - app := iris.New() - New(app.Party("/era/{username}")).Handle(new(testControllerEndRequestAwareness)) - - e := httptest.New(t, app) - usernames := []string{ - "kataras", - "makis", - } - - for _, username := range usernames { - e.GET("/era/" + username).Expect().Status(iris.StatusOK). - Body().Equal(username + username + "2") - } -} - -type testBindType struct { - title string -} - -type testControllerBindStruct struct { - Ctx *context.Context - - // should start with upper letter of course - TitlePointer *testBindType // should have the value of the "myTitlePtr" on test - TitleValue testBindType // should have the value of the "myTitleV" on test - Other string // just another type to check the field collection, should be empty -} - -func (t *testControllerBindStruct) Get() { - t.Ctx.Writef(t.TitlePointer.title + t.TitleValue.title + t.Other) -} - -// test if context can be binded to the controller's function -// without need to declare it to a struct if not needed. -func (t *testControllerBindStruct) GetCtx(ctx iris.Context) { - ctx.StatusCode(iris.StatusContinue) -} - -type testControllerBindDeep struct { - testControllerBindStruct -} - -func (t *testControllerBindDeep) BeforeActivation(b BeforeActivation) { - b.Dependencies().Register(func(ctx iris.Context) (v testCustomStruct, err error) { - err = ctx.ReadJSON(&v) - return - }) -} - -func (t *testControllerBindDeep) Get() { - // t.testControllerBindStruct.Get() - t.Ctx.Writef(t.TitlePointer.title + t.TitleValue.title + t.Other) -} - -func (t *testControllerBindDeep) Post(v testCustomStruct) string { - return v.Name -} - -func TestControllerDependencies(t *testing.T) { - app := iris.New() - // app.Logger().SetLevel("debug") - - t1, t2 := "my pointer title", "val title" - // test bind pointer to pointer of the correct type - myTitlePtr := &testBindType{title: t1} - // test bind value to value of the correct type - myTitleV := testBindType{title: t2} - m := New(app) - m.Register(myTitlePtr, myTitleV) - m.Handle(new(testControllerBindStruct)) - m.Clone(app.Party("/deep")).Handle(new(testControllerBindDeep)) - - e := httptest.New(t, app) - expected := t1 + t2 - e.GET("/").Expect().Status(iris.StatusOK). - Body().Equal(expected) - e.GET("/ctx").Expect().Status(iris.StatusContinue) - - e.GET("/deep").Expect().Status(iris.StatusOK). - Body().Equal(expected) - - e.POST("/deep").WithJSON(iris.Map{"name": "kataras"}).Expect().Status(iris.StatusOK). - Body().Equal("kataras") - - e.POST("/deep").Expect().Status(iris.StatusBadRequest). - Body().Equal("unexpected end of JSON input") -} - -type testCtrl0 struct { - testCtrl00 -} - -func (c *testCtrl0) Get() string { - return c.Ctx.Params().Get("username") -} - -func (c *testCtrl0) EndRequest(ctx *context.Context) { - if c.TitlePointer == nil { - ctx.Writef("\nTitlePointer is nil!\n") - } else { - ctx.Writef(c.TitlePointer.title) - } - - // should be the same as `.testCtrl000.testCtrl0000.EndRequest(ctx)` - c.testCtrl00.EndRequest(ctx) -} - -type testCtrl00 struct { - Ctx *context.Context - - testCtrl000 -} - -type testCtrl000 struct { - testCtrl0000 - - TitlePointer *testBindType -} - -type testCtrl0000 struct { -} - -func (c *testCtrl0000) BeginRequest(ctx *context.Context) {} -func (c *testCtrl0000) EndRequest(ctx *context.Context) { - ctx.Writef("finish") -} - -func TestControllerInsideControllerRecursively(t *testing.T) { - var ( - username = "gerasimos" - title = "mytitle" - expected = username + title + "finish" - ) - - app := iris.New() - m := New(app.Party("/user/{username}")) - m.Register(&testBindType{title: title}) - m.Handle(new(testCtrl0)) - - e := httptest.New(t, app) - e.GET("/user/" + username).Expect(). - Status(iris.StatusOK).Body().Equal(expected) -} - -type testControllerRelPathFromFunc struct{} - -func (c *testControllerRelPathFromFunc) BeginRequest(ctx *context.Context) {} -func (c *testControllerRelPathFromFunc) EndRequest(ctx *context.Context) { - ctx.Writef("%s:%s", ctx.Method(), ctx.Path()) -} - -func (c *testControllerRelPathFromFunc) Get() {} -func (c *testControllerRelPathFromFunc) GetBy(uint64) {} -func (c *testControllerRelPathFromFunc) GetUint8RatioBy(uint8) {} -func (c *testControllerRelPathFromFunc) GetInt64RatioBy(int64) {} -func (c *testControllerRelPathFromFunc) GetAnythingByWildcard(string) {} - -func (c *testControllerRelPathFromFunc) GetLogin() {} -func (c *testControllerRelPathFromFunc) PostLogin() {} - -func (c *testControllerRelPathFromFunc) GetAdminLogin() {} - -func (c *testControllerRelPathFromFunc) PutSomethingIntoThis() {} - -func (c *testControllerRelPathFromFunc) GetSomethingBy(bool) {} - -func (c *testControllerRelPathFromFunc) GetSomethingByBy(string, int) {} - -func (c *testControllerRelPathFromFunc) GetSomethingNewBy(string, int) {} // two input arguments, one By which is the latest word. -func (c *testControllerRelPathFromFunc) GetSomethingByElseThisBy(bool, int) {} // two input arguments - -func (c *testControllerRelPathFromFunc) GetLocationX() {} -func (c *testControllerRelPathFromFunc) GetLocationXY() {} -func (c *testControllerRelPathFromFunc) GetLocationZBy(int) {} - -func TestControllerRelPathFromFunc(t *testing.T) { - app := iris.New() - New(app).Handle(new(testControllerRelPathFromFunc)) - - e := httptest.New(t, app) - e.GET("/").Expect().Status(iris.StatusOK). - Body().Equal("GET:/") - - e.GET("/18446744073709551615").Expect().Status(iris.StatusOK). - Body().Equal("GET:/18446744073709551615") - e.GET("/uint8/ratio/255").Expect().Status(iris.StatusOK). - Body().Equal("GET:/uint8/ratio/255") - e.GET("/uint8/ratio/256").Expect().Status(iris.StatusNotFound) - e.GET("/int64/ratio/-42").Expect().Status(iris.StatusOK). - Body().Equal("GET:/int64/ratio/-42") - e.GET("/something/true").Expect().Status(iris.StatusOK). - Body().Equal("GET:/something/true") - e.GET("/something/false").Expect().Status(iris.StatusOK). - Body().Equal("GET:/something/false") - e.GET("/something/truee").Expect().Status(iris.StatusNotFound) - e.GET("/something/falsee").Expect().Status(iris.StatusNotFound) - e.GET("/something/kataras/42").Expect().Status(iris.StatusOK). - Body().Equal("GET:/something/kataras/42") - e.GET("/something/new/kataras/42").Expect().Status(iris.StatusOK). - Body().Equal("GET:/something/new/kataras/42") - e.GET("/something/true/else/this/42").Expect().Status(iris.StatusOK). - Body().Equal("GET:/something/true/else/this/42") - - e.GET("/login").Expect().Status(iris.StatusOK). - Body().Equal("GET:/login") - e.POST("/login").Expect().Status(iris.StatusOK). - Body().Equal("POST:/login") - e.GET("/admin/login").Expect().Status(iris.StatusOK). - Body().Equal("GET:/admin/login") - e.PUT("/something/into/this").Expect().Status(iris.StatusOK). - Body().Equal("PUT:/something/into/this") - e.GET("/42").Expect().Status(iris.StatusOK). - Body().Equal("GET:/42") - e.GET("/anything/here").Expect().Status(iris.StatusOK). - Body().Equal("GET:/anything/here") - - e.GET("/location/x").Expect().Status(iris.StatusOK). - Body().Equal("GET:/location/x") - e.GET("/location/x/y").Expect().Status(iris.StatusOK). - Body().Equal("GET:/location/x/y") - e.GET("/location/z/42").Expect().Status(iris.StatusOK). - Body().Equal("GET:/location/z/42") -} - -type testControllerActivateListener struct { - TitlePointer *testBindType -} - -func (c *testControllerActivateListener) BeforeActivation(b BeforeActivation) { - b.Dependencies().Register(&testBindType{title: "overrides the dependency but not the field"}) // overrides the `Register` previous calls. - - // b.Handle("POST", "/me/tos-read", "MeTOSRead") - // b.Handle("GET", "/me/tos-read", "MeTOSRead") - // OR: - b.HandleMany("GET POST", "/me/tos-read", "MeTOSRead") -} - -func (c *testControllerActivateListener) Get() string { - return c.TitlePointer.title -} - -func (c *testControllerActivateListener) MeTOSRead() string { - return "MeTOSRead" -} - -func TestControllerActivateListener(t *testing.T) { - app := iris.New() - New(app).Handle(new(testControllerActivateListener)) - m := New(app) - m.Register(&testBindType{ - title: "my title", - }) - m.Party("/manual").Handle(new(testControllerActivateListener)) - // or - m.Party("/manual2").Handle(&testControllerActivateListener{ - TitlePointer: &testBindType{ - title: "my manual title", - }, - }) - - e := httptest.New(t, app) - e.GET("/").Expect().Status(iris.StatusOK). - Body().Equal("overrides the dependency but not the field") - e.GET("/me/tos-read").Expect().Status(iris.StatusOK). - Body().Equal("MeTOSRead") - e.POST("/me/tos-read").Expect().Status(iris.StatusOK). - Body().Equal("MeTOSRead") - - e.GET("/manual").Expect().Status(iris.StatusOK). - Body().Equal("overrides the dependency but not the field") - e.GET("/manual2").Expect().Status(iris.StatusOK). - Body().Equal("my manual title") -} - -type testControllerNotCreateNewDueManuallySettingAllFields struct { - T *testing.T - - TitlePointer *testBindType -} - -func (c *testControllerNotCreateNewDueManuallySettingAllFields) AfterActivation(a AfterActivation) { - if n := len(a.DependenciesReadOnly()) - len(hero.BuiltinDependencies) - 1; /* Application */ n != 1 { - c.T.Fatalf(`expecting 1 dependency; -- the 'T' and the 'TitlePointer' are manually binded (nonzero fields on initilization) -- controller has no more than these two fields, it's a singleton -- however, the dependencies length here should be 1 because the injector's options handler dependencies contains the controller's value dependency itself --- got dependencies length: %d`, n) - } - - if !a.Singleton() { - c.T.Fatalf(`this controller should be tagged as Singleton. It shouldn't be tagged used as request scoped(create new instances on each request), - it doesn't contain any dynamic value or dependencies that should be binded via the iris mvc engine`) - } -} - -func (c *testControllerNotCreateNewDueManuallySettingAllFields) Get() string { - return c.TitlePointer.title -} - -func TestControllerNotCreateNewDueManuallySettingAllFields(t *testing.T) { - app := iris.New() - New(app).Handle(&testControllerNotCreateNewDueManuallySettingAllFields{ - T: t, - TitlePointer: &testBindType{ - title: "my title", - }, - }) - - e := httptest.New(t, app) - e.GET("/").Expect().Status(iris.StatusOK). - Body().Equal("my title") -} - -type testControllerRequestScopedDependencies struct { - MyContext *testMyContext - CustomStruct *testCustomStruct -} - -func (c *testControllerRequestScopedDependencies) Get() *testCustomStruct { - return c.CustomStruct -} - -func (c *testControllerRequestScopedDependencies) GetCustomContext() string { - return c.MyContext.OtherField -} - -func newRequestDep1(ctx *context.Context) *testCustomStruct { - return &testCustomStruct{ - Name: ctx.URLParam("name"), - Age: ctx.URLParamIntDefault("age", 0), - } -} - -type testMyContext struct { - Context *context.Context - OtherField string -} - -func newRequestDep2(ctx *context.Context) *testMyContext { - return &testMyContext{ - Context: ctx, - OtherField: "test", - } -} - -func TestControllerRequestScopedDependencies(t *testing.T) { - app := iris.New() - m := New(app) - m.Register(newRequestDep1) - m.Register(newRequestDep2) - m.Handle(new(testControllerRequestScopedDependencies)) - - e := httptest.New(t, app) - e.GET("/").WithQuery("name", "kataras").WithQuery("age", 27). - Expect().Status(httptest.StatusOK).JSON().Equal(&testCustomStruct{ - Name: "kataras", - Age: 27, - }) - e.GET("/custom/context").Expect().Status(httptest.StatusOK).Body().Equal("test") -} - -type ( - testServiceDoSomething struct{} - - TestControllerAsDeepDep struct { - Ctx iris.Context - Service *testServiceDoSomething - } - - FooController struct { - TestControllerAsDeepDep - } - - BarController struct { - FooController - } - - FinalController struct { - BarController - } -) - -func (s *testServiceDoSomething) DoSomething(ctx iris.Context) { - ctx.WriteString("foo bar") -} - -func (c *FinalController) GetSomething() { - c.Service.DoSomething(c.Ctx) -} - -func TestControllersInsideControllerDeep(t *testing.T) { - app := iris.New() - m := New(app) - m.Register(new(testServiceDoSomething)) - m.Handle(new(FinalController)) - - e := httptest.New(t, app) - e.GET("/something").Expect().Status(httptest.StatusOK).Body().Equal("foo bar") -} - -type testApplicationDependency struct { - App *Application -} - -func (c *testApplicationDependency) Get() string { - return c.App.Name -} - -func TestApplicationDependency(t *testing.T) { - app := iris.New() - m := New(app).SetName("app1") - m.Handle(new(testApplicationDependency)) - - m2 := m.Clone(app.Party("/other")).SetName("app2") - m2.Handle(new(testApplicationDependency)) - - e := httptest.New(t, app) - e.GET("/").Expect().Status(httptest.StatusOK).Body().Equal("app1") - e.GET("/other").Expect().Status(httptest.StatusOK).Body().Equal("app2") -} - -// Authenticated type. -type Authenticated int64 - -// BasePrivateController base controller for private controllers. -type BasePrivateController struct { - CurrentUserID Authenticated - Ctx iris.Context // not-used. -} - -type publicController struct { - Ctx iris.Context // not-used. -} - -func (c *publicController) Get() iris.Map { - return iris.Map{"data": "things"} -} - -type privateController struct{ BasePrivateController } - -func (c *privateController) Get() iris.Map { - return iris.Map{"id": c.CurrentUserID} -} - -func TestControllerOverlapping(t *testing.T) { - app := iris.New() - - m := New(app) - m.Router.SetRegisterRule(iris.RouteOverlap) - - m.Register(func(ctx iris.Context) Authenticated { - if ctx.URLParam("name") == "kataras" { - return 1 - } - - ctx.StopWithStatus(iris.StatusForbidden) - return -1 - }) - - // Order matters. - m.Handle(new(privateController)) - m.Handle(new(publicController)) - - e := httptest.New(t, app) - e.GET("/").WithQuery("name", "kataras").Expect().Status(httptest.StatusOK). - JSON().Equal(iris.Map{"id": 1}) - e.GET("/").Expect().Status(httptest.StatusOK). - JSON().Equal(iris.Map{"data": "things"}) -} - -type testControllerMethodHandlerBindStruct struct{} - -type bindStructData struct { - Name string `json:"name" url:"name"` -} - -func (*testControllerMethodHandlerBindStruct) Any(data bindStructData) bindStructData { - return data -} - -func (*testControllerMethodHandlerBindStruct) PostBySlice(id uint64, manyData []bindStructData) []bindStructData { - return manyData -} - -type dataSlice []bindStructData - -func (*testControllerMethodHandlerBindStruct) PostBySlicetype(id uint64, manyData dataSlice) dataSlice { - return manyData -} - -type dataSlicePtr []*bindStructData - -func (*testControllerMethodHandlerBindStruct) PostBySlicetypeptr(id uint64, manyData dataSlicePtr) dataSlicePtr { - return manyData -} - -func TestControllerMethodHandlerBindStruct(t *testing.T) { - app := iris.New() - - m := New(app.Party("/data")) - m.HandleError(func(ctx iris.Context, err error) { - t.Fatalf("Path: %s, Error: %v", ctx.Path(), err) - }) - - m.Handle(new(testControllerMethodHandlerBindStruct)) - - data := bindStructData{Name: "kataras"} - manyData := []bindStructData{data, {"john doe"}} - - e := httptest.New(t, app) - e.GET("/data").WithQueryObject(data).Expect().Status(httptest.StatusOK).JSON().Equal(data) - e.PATCH("/data").WithJSON(data).Expect().Status(httptest.StatusOK).JSON().Equal(data) - e.POST("/data/42/slice").WithJSON(manyData).Expect().Status(httptest.StatusOK).JSON().Equal(manyData) - e.POST("/data/42/slicetype").WithJSON(manyData).Expect().Status(httptest.StatusOK).JSON().Equal(manyData) - e.POST("/data/42/slicetypeptr").WithJSON(manyData).Expect().Status(httptest.StatusOK).JSON().Equal(manyData) - // more tests inside the hero package itself. -} diff --git a/mvc/grpc.go b/mvc/grpc.go index e488a74c..554e170f 100644 --- a/mvc/grpc.go +++ b/mvc/grpc.go @@ -4,7 +4,7 @@ import ( "net/http" "path" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) // GRPC registers a controller which serves gRPC clients. diff --git a/mvc/mvc.go b/mvc/mvc.go index 7309934d..cf59f1ef 100644 --- a/mvc/mvc.go +++ b/mvc/mvc.go @@ -4,10 +4,10 @@ import ( "reflect" "strings" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/router" - "github.com/kataras/iris/v12/hero" - "github.com/kataras/iris/v12/websocket" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/router" + "github.com/kataras/iris/hero" + "github.com/kataras/iris/websocket" "github.com/kataras/golog" ) diff --git a/mvc/versioning.go b/mvc/versioning.go index c16c2889..2d1cf0f2 100644 --- a/mvc/versioning.go +++ b/mvc/versioning.go @@ -1,9 +1,9 @@ package mvc import ( - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/router" - "github.com/kataras/iris/v12/versioning" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/router" + "github.com/kataras/iris/versioning" ) // Version returns a valid `Option` that can be passed to the `Application.Handle` method. diff --git a/sessions/config.go b/sessions/config.go index e673d50e..851092fc 100644 --- a/sessions/config.go +++ b/sessions/config.go @@ -3,7 +3,7 @@ package sessions import ( "time" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" "github.com/google/uuid" ) diff --git a/sessions/database.go b/sessions/database.go index a32f0fbd..c444b828 100644 --- a/sessions/database.go +++ b/sessions/database.go @@ -5,7 +5,7 @@ import ( "sync" "time" - "github.com/kataras/iris/v12/core/memstore" + "github.com/kataras/iris/core/memstore" ) // ErrNotImplemented is returned when a particular feature is not yet implemented yet. diff --git a/sessions/lifetime.go b/sessions/lifetime.go index b92c4d8d..08ef2290 100644 --- a/sessions/lifetime.go +++ b/sessions/lifetime.go @@ -4,7 +4,7 @@ import ( "sync" "time" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) // LifeTime controls the session expiration datetime. diff --git a/sessions/session.go b/sessions/session.go index f4110ec0..100b3e52 100644 --- a/sessions/session.go +++ b/sessions/session.go @@ -6,7 +6,7 @@ import ( "strconv" "sync" - "github.com/kataras/iris/v12/core/memstore" + "github.com/kataras/iris/core/memstore" ) type ( diff --git a/sessions/sessiondb/badger/database.go b/sessions/sessiondb/badger/database.go index c7accb7c..863c9712 100644 --- a/sessions/sessiondb/badger/database.go +++ b/sessions/sessiondb/badger/database.go @@ -8,7 +8,7 @@ import ( "sync/atomic" "time" - "github.com/kataras/iris/v12/sessions" + "github.com/kataras/iris/sessions" "github.com/dgraph-io/badger/v2" "github.com/kataras/golog" diff --git a/sessions/sessiondb/boltdb/database.go b/sessions/sessiondb/boltdb/database.go index 90e884b8..eb345775 100644 --- a/sessions/sessiondb/boltdb/database.go +++ b/sessions/sessiondb/boltdb/database.go @@ -7,7 +7,7 @@ import ( "runtime" "time" - "github.com/kataras/iris/v12/sessions" + "github.com/kataras/iris/sessions" "github.com/kataras/golog" bolt "go.etcd.io/bbolt" diff --git a/sessions/sessiondb/redis/database.go b/sessions/sessiondb/redis/database.go index b3453831..a4c2b825 100644 --- a/sessions/sessiondb/redis/database.go +++ b/sessions/sessiondb/redis/database.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "github.com/kataras/iris/v12/sessions" + "github.com/kataras/iris/sessions" "github.com/kataras/golog" ) diff --git a/sessions/sessions.go b/sessions/sessions.go index b95b03a2..3ee8ca01 100644 --- a/sessions/sessions.go +++ b/sessions/sessions.go @@ -4,7 +4,7 @@ import ( "net/http" "time" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) func init() { diff --git a/sessions/sessions_test.go b/sessions/sessions_test.go deleted file mode 100644 index f9c4b2cf..00000000 --- a/sessions/sessions_test.go +++ /dev/null @@ -1,326 +0,0 @@ -package sessions_test - -import ( - "sync" - "testing" - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/httptest" - "github.com/kataras/iris/v12/sessions" -) - -func TestSessions(t *testing.T) { - app := iris.New() - - sess := sessions.New(sessions.Config{Cookie: "mycustomsessionid"}) - app.Use(sess.Handler()) - - testSessions(t, app) -} - -const ( - testEnableSubdomain = true -) - -func testSessions(t *testing.T, app *iris.Application) { - values := map[string]interface{}{ - "Name": "iris", - "Months": "4", - "Secret": "dsads£2132215£%%Ssdsa", - } - - writeValues := func(ctx *context.Context) { - s := sessions.Get(ctx) - sessValues := s.GetAll() - - _, err := ctx.JSON(sessValues) - if err != nil { - t.Fatal(err) - } - } - - if testEnableSubdomain { - app.Party("subdomain.").Get("/get", writeValues) - } - - app.Post("/set", func(ctx *context.Context) { - s := sessions.Get(ctx) - vals := make(map[string]interface{}) - if err := ctx.ReadJSON(&vals); err != nil { - t.Fatalf("Cannot read JSON. Trace %s", err.Error()) - } - for k, v := range vals { - s.Set(k, v) - } - }) - - app.Get("/get", func(ctx *context.Context) { - writeValues(ctx) - }) - - app.Get("/clear", func(ctx *context.Context) { - sessions.Get(ctx).Clear() - writeValues(ctx) - }) - - app.Get("/destroy", func(ctx *context.Context) { - session := sessions.Get(ctx) - if session.IsNew() { - t.Fatal("expected session not to be nil on destroy") - } - - session.Man.Destroy(ctx) - - if sessions.Get(ctx) != nil { - t.Fatal("expected session inside Context to be nil after Manager's Destroy call") - } - - ctx.JSON(struct{}{}) - // the cookie and all values should be empty - }) - - // cookie should be new. - app.Get("/after_destroy_renew", func(ctx *context.Context) { - isNew := sessions.Get(ctx).IsNew() - ctx.Writef("%v", isNew) - }) - - app.Get("/multi_start_set_get", func(ctx *context.Context) { - s := sessions.Get(ctx) - s.Set("key", "value") - ctx.Next() - }, func(ctx *context.Context) { - s := sessions.Get(ctx) - _, err := ctx.Writef(s.GetString("key")) - if err != nil { - t.Fatal(err) - } - }) - - e := httptest.New(t, app, httptest.URL("http://example.com")) - - e.POST("/set").WithJSON(values).Expect().Status(iris.StatusOK).Cookies().NotEmpty() - e.GET("/get").Expect().Status(iris.StatusOK).JSON().Object().Equal(values) - if testEnableSubdomain { - es := e.Builder(func(req *httptest.Request) { - req.WithURL("http://subdomain.example.com") - }) - es.Request("GET", "/get").Expect().Status(iris.StatusOK).JSON().Object().Equal(values) - } - // test destroy which also clears first - d := e.GET("/destroy").Expect().Status(iris.StatusOK) - d.JSON().Object().Empty() - - d = e.GET("/after_destroy_renew").Expect().Status(iris.StatusOK) - d.Body().Equal("true") - d.Cookies().NotEmpty() - - // set and clear again - e.POST("/set").WithJSON(values).Expect().Status(iris.StatusOK) - e.GET("/clear").Expect().Status(iris.StatusOK).JSON().Object().Empty() - - // test start on the same request but more than one times - - e.GET("/multi_start_set_get").Expect().Status(iris.StatusOK).Body().Equal("value") -} - -func TestFlashMessages(t *testing.T) { - app := iris.New() - - sess := sessions.New(sessions.Config{Cookie: "mycustomsessionid"}) - - valueSingleKey := "Name" - valueSingleValue := "iris-sessions" - - values := map[string]interface{}{ - valueSingleKey: valueSingleValue, - "Days": "1", - "Secret": "dsads£2132215£%%Ssdsa", - } - - writeValues := func(ctx *context.Context, values map[string]interface{}) error { - _, err := ctx.JSON(values) - return err - } - - app.Post("/set", func(ctx *context.Context) { - vals := make(map[string]interface{}) - if err := ctx.ReadJSON(&vals); err != nil { - t.Fatalf("Cannot readjson. Trace %s", err.Error()) - } - s := sess.Start(ctx) - for k, v := range vals { - s.SetFlash(k, v) - } - - ctx.StatusCode(iris.StatusOK) - }) - - writeFlashValues := func(ctx *context.Context) { - s := sess.Start(ctx) - - flashes := s.GetFlashes() - if err := writeValues(ctx, flashes); err != nil { - t.Fatalf("While serialize the flash values: %s", err.Error()) - } - } - - app.Get("/get_single", func(ctx *context.Context) { - s := sess.Start(ctx) - flashMsgString := s.GetFlashString(valueSingleKey) - ctx.WriteString(flashMsgString) - }) - - app.Get("/get", func(ctx *context.Context) { - writeFlashValues(ctx) - }) - - app.Get("/clear", func(ctx *context.Context) { - s := sess.Start(ctx) - s.ClearFlashes() - writeFlashValues(ctx) - }) - - app.Get("/destroy", func(ctx *context.Context) { - sess.Destroy(ctx) - writeFlashValues(ctx) - ctx.StatusCode(iris.StatusOK) - // the cookie and all values should be empty - }) - - // request cookie should be empty - app.Get("/after_destroy", func(ctx *context.Context) { - ctx.StatusCode(iris.StatusOK) - }) - - e := httptest.New(t, app, httptest.URL("http://example.com")) - - e.POST("/set").WithJSON(values).Expect().Status(iris.StatusOK).Cookies().NotEmpty() - // get all - e.GET("/get").Expect().Status(iris.StatusOK).JSON().Object().Equal(values) - // get the same flash on other request should return nothing because the flash message is removed after fetch once - e.GET("/get").Expect().Status(iris.StatusOK).JSON().Object().Empty() - // test destroy which also clears first - d := e.GET("/destroy").Expect().Status(iris.StatusOK) - d.JSON().Object().Empty() - e.GET("/after_destroy").Expect().Status(iris.StatusOK).Cookies().Empty() - // set and clear again - e.POST("/set").WithJSON(values).Expect().Status(iris.StatusOK).Cookies().NotEmpty() - e.GET("/clear").Expect().Status(iris.StatusOK).JSON().Object().Empty() - - // set again in order to take the single one ( we don't test Cookies.NotEmpty because httpexpect default conf reads that from the request-only) - e.POST("/set").WithJSON(values).Expect().Status(iris.StatusOK) - e.GET("/get_single").Expect().Status(iris.StatusOK).Body().Equal(valueSingleValue) -} - -func TestSessionsUpdateExpiration(t *testing.T) { - app := iris.New() - - cookieName := "mycustomsessionid" - - sess := sessions.New(sessions.Config{ - Cookie: cookieName, - Expires: 30 * time.Minute, - AllowReclaim: true, - }) - - app.Use(sess.Handler()) - - type response struct { - SessionID string `json:"sessionID"` - Logged bool `json:"logged"` - } - - var writeResponse = func(ctx *context.Context) { - session := sessions.Get(ctx) - ctx.JSON(response{ - SessionID: session.ID(), - Logged: session.GetBooleanDefault("logged", false), - }) - } - - app.Get("/get", func(ctx *context.Context) { - writeResponse(ctx) - }) - - app.Get("/set", func(ctx iris.Context) { - sessions.Get(ctx).Set("logged", true) - writeResponse(ctx) - }) - - app.Post("/remember_me", func(ctx iris.Context) { - // re-sends the cookie with the new Expires and MaxAge fields, - // test checks that on same session id too. - sessions.Get(ctx).Man.UpdateExpiration(ctx, 24*time.Hour) - writeResponse(ctx) - }) - - app.Get("/destroy", func(ctx iris.Context) { - sessions.Get(ctx).Man.Destroy(ctx) // this will delete the cookie too. - }) - - e := httptest.New(t, app, httptest.URL("http://example.com")) - - tt := e.GET("/set").Expect().Status(httptest.StatusOK) - tt.Cookie(cookieName).MaxAge().InRange(29*time.Minute, 30*time.Minute) - sessionID := tt.JSON().Object().Raw()["sessionID"].(string) - - expectedResponse := response{SessionID: sessionID, Logged: true} - e.GET("/get").Expect().Status(httptest.StatusOK). - JSON().Equal(expectedResponse) - - tt = e.POST("/remember_me").Expect().Status(httptest.StatusOK) - tt.Cookie(cookieName).MaxAge().InRange(23*time.Hour, 24*time.Hour) - tt.JSON().Equal(expectedResponse) - - // Test call `UpdateExpiration` when cookie is firstly created. - e.GET("/destroy").Expect().Status(httptest.StatusOK) - e.POST("/remember_me").Expect().Status(httptest.StatusOK). - Cookie(cookieName).MaxAge().InRange(23*time.Hour, 24*time.Hour) -} - -// go test -v -count=100 -run=TestSessionsUpdateExpirationConcurrently$ -// #1488 -func TestSessionsUpdateExpirationConcurrently(t *testing.T) { - cookieName := "mycustomsessionid" - sess := sessions.New(sessions.Config{ - Cookie: cookieName, - Expires: 30 * time.Minute, - AllowReclaim: true, - }) - - app := iris.New() - app.Use(sess.Handler()) - app.Use(func(ctx iris.Context) { - // session will expire after 30 minute at the last visit - sess.UpdateExpiration(ctx, 30*time.Minute) - ctx.Next() - }) - - app.Get("/get", func(ctx iris.Context) { - ctx.WriteString(sessions.Get(ctx).ID()) - }) - - e := httptest.New(t, app, httptest.URL("http://example.com")) - - id := e.GET("/get").Expect().Status(httptest.StatusOK).Body().Raw() - - i := 0 - wg := sync.WaitGroup{} - wg.Add(1000) - for i < 1000 { - go func() { - tt := e.GET("/get").Expect().Status(httptest.StatusOK) - tt.Body().Equal(id) - tt.Cookie(cookieName).MaxAge().InRange(29*time.Minute, 30*time.Minute) - wg.Done() - }() - i++ - } - wg.Wait() - tt := e.GET("/get").Expect() - tt.Status(httptest.StatusOK).Body().Equal(id) - tt.Cookie(cookieName).MaxAge().InRange(29*time.Minute, 30*time.Minute) -} diff --git a/versioning/deprecation.go b/versioning/deprecation.go index 7e28d421..91274033 100644 --- a/versioning/deprecation.go +++ b/versioning/deprecation.go @@ -3,7 +3,7 @@ package versioning import ( "time" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) // DeprecationOptions describes the deprecation headers key-values. diff --git a/versioning/deprecation_test.go b/versioning/deprecation_test.go deleted file mode 100644 index 3dfd77b5..00000000 --- a/versioning/deprecation_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package versioning_test - -import ( - "testing" - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/httptest" - "github.com/kataras/iris/v12/versioning" -) - -func TestDeprecated(t *testing.T) { - app := iris.New() - - writeVesion := func(ctx iris.Context) { - ctx.WriteString(versioning.GetVersion(ctx)) - } - - opts := versioning.DeprecationOptions{ - WarnMessage: "deprecated, see ", - DeprecationDate: time.Now().UTC(), - DeprecationInfo: "a bigger version is available, see for more information", - } - app.Get("/", versioning.Deprecated(writeVesion, opts)) - - e := httptest.New(t, app) - - ex := e.GET("/").WithHeader(versioning.AcceptVersionHeaderKey, "1.0").Expect() - ex.Status(iris.StatusOK).Body().Equal("1.0") - ex.Header("X-API-Warn").Equal(opts.WarnMessage) - expectedDateStr := opts.DeprecationDate.Format(app.ConfigurationReadOnly().GetTimeFormat()) - ex.Header("X-API-Deprecation-Date").Equal(expectedDateStr) -} diff --git a/versioning/group.go b/versioning/group.go index 171d2af9..2df13378 100644 --- a/versioning/group.go +++ b/versioning/group.go @@ -1,8 +1,8 @@ package versioning import ( - "github.com/kataras/iris/v12/context" - "github.com/kataras/iris/v12/core/router" + "github.com/kataras/iris/context" + "github.com/kataras/iris/core/router" ) // Group is a group of version-based routes. diff --git a/versioning/version.go b/versioning/version.go index b5436d43..238a9b5a 100644 --- a/versioning/version.go +++ b/versioning/version.go @@ -4,7 +4,7 @@ import ( "errors" "strings" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) const ( diff --git a/versioning/version_test.go b/versioning/version_test.go deleted file mode 100644 index eab10ea9..00000000 --- a/versioning/version_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package versioning_test - -import ( - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/httptest" - "github.com/kataras/iris/v12/versioning" -) - -func TestGetVersion(t *testing.T) { - app := iris.New() - - writeVesion := func(ctx iris.Context) { - ctx.WriteString(versioning.GetVersion(ctx)) - } - - app.Get("/", writeVesion) - app.Get("/manual", func(ctx iris.Context) { - versioning.SetVersion(ctx, "11.0.5") - ctx.Next() - }, writeVesion) - - e := httptest.New(t, app) - - e.GET("/").WithHeader(versioning.AcceptVersionHeaderKey, "1.0").Expect(). - Status(iris.StatusOK).Body().Equal("1.0") - e.GET("/").WithHeader(versioning.AcceptHeaderKey, "application/vnd.api+json; version=2.1").Expect(). - Status(iris.StatusOK).Body().Equal("2.1") - e.GET("/").WithHeader(versioning.AcceptHeaderKey, "application/vnd.api+json; version=2.1 ;other=dsa").Expect(). - Status(iris.StatusOK).Body().Equal("2.1") - e.GET("/").WithHeader(versioning.AcceptHeaderKey, "version=2.1").Expect(). - Status(iris.StatusOK).Body().Equal("2.1") - e.GET("/").WithHeader(versioning.AcceptHeaderKey, "version=1").Expect(). - Status(iris.StatusOK).Body().Equal("1") - - // unknown versions. - e.GET("/").WithHeader(versioning.AcceptVersionHeaderKey, "").Expect(). - Status(iris.StatusOK).Body().Equal("") - e.GET("/").WithHeader(versioning.AcceptHeaderKey, "application/vnd.api+json; version=").Expect(). - Status(iris.StatusOK).Body().Equal("") - e.GET("/").WithHeader(versioning.AcceptHeaderKey, "application/vnd.api+json; version= ;other=dsa").Expect(). - Status(iris.StatusOK).Body().Equal("") - e.GET("/").WithHeader(versioning.AcceptHeaderKey, "version=").Expect(). - Status(iris.StatusOK).Body().Equal("") - - e.GET("/manual").Expect().Status(iris.StatusOK).Body().Equal("11.0.5") -} diff --git a/versioning/versioning.go b/versioning/versioning.go index fb4d702f..9b36b348 100644 --- a/versioning/versioning.go +++ b/versioning/versioning.go @@ -1,7 +1,7 @@ package versioning import ( - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" "github.com/hashicorp/go-version" ) diff --git a/versioning/versioning_test.go b/versioning/versioning_test.go deleted file mode 100644 index 536b39bc..00000000 --- a/versioning/versioning_test.go +++ /dev/null @@ -1,135 +0,0 @@ -package versioning_test - -import ( - "testing" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/httptest" - "github.com/kataras/iris/v12/versioning" -) - -func notFoundHandler(ctx iris.Context) { - ctx.NotFound() -} - -const ( - v10Response = "v1.0 handler" - v2Response = "v2.x handler" -) - -func sendHandler(contents string) iris.Handler { - return func(ctx iris.Context) { - ctx.WriteString(contents) - } -} - -func TestIf(t *testing.T) { - if expected, got := true, versioning.If("1.0", ">=1"); expected != got { - t.Fatalf("expected %s to be %s", "1.0", ">= 1") - } - if expected, got := true, versioning.If("1.2.3", "> 1.2"); expected != got { - t.Fatalf("expected %s to be %s", "1.2.3", "> 1.2") - } -} - -func TestNewMatcher(t *testing.T) { - app := iris.New() - - userAPI := app.Party("/api/user") - userAPI.Get("/", versioning.NewMatcher(versioning.Map{ - "1.0": sendHandler(v10Response), - ">= 2, < 3": sendHandler(v2Response), - versioning.NotFound: notFoundHandler, - })) - - // middleware as usual. - myMiddleware := func(ctx iris.Context) { - ctx.Header("X-Custom", "something") - ctx.Next() - } - myVersions := versioning.Map{ - "1.0": sendHandler(v10Response), - } - - userAPI.Get("/with_middleware", myMiddleware, versioning.NewMatcher(myVersions)) - - e := httptest.New(t, app) - - e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "1").Expect(). - Status(iris.StatusOK).Body().Equal(v10Response) - e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "2.0").Expect(). - Status(iris.StatusOK).Body().Equal(v2Response) - e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "2.1").Expect(). - Status(iris.StatusOK).Body().Equal(v2Response) - e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "2.9.9").Expect(). - Status(iris.StatusOK).Body().Equal(v2Response) - - // middleware as usual. - ex := e.GET("/api/user/with_middleware").WithHeader(versioning.AcceptVersionHeaderKey, "1.0").Expect() - ex.Status(iris.StatusOK).Body().Equal(v10Response) - ex.Header("X-Custom").Equal("something") - - e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "3.0").Expect(). - Status(iris.StatusNotFound).Body().Equal("Not Found") -} - -func TestNewGroup(t *testing.T) { - app := iris.New() - - userAPI := app.Party("/api/user") - // [... static serving, middlewares and etc goes here]. - - userAPIV10 := versioning.NewGroup(userAPI, "1.0").Deprecated(versioning.DefaultDeprecationOptions) - // V10middlewareResponse := "m1" - // userAPIV10.Use(func(ctx iris.Context) { - // println("exec userAPIV10.Use - midl1") - // sendHandler(V10middlewareResponse)(ctx) - // ctx.Next() - // }) - // userAPIV10.Use(func(ctx iris.Context) { - // println("exec userAPIV10.Use - midl2") - // sendHandler(V10middlewareResponse + "midl2")(ctx) - // ctx.Next() - // }) - // userAPIV10.Use(func(ctx iris.Context) { - // println("exec userAPIV10.Use - midl3") - // ctx.Next() - // }) - - userAPIV10.Get("/", sendHandler(v10Response)) - userAPIV2 := versioning.NewGroup(userAPI, ">= 2, < 3") - // V2middlewareResponse := "m2" - // userAPIV2.Use(func(ctx iris.Context) { - // println("exec userAPIV2.Use - midl1") - // sendHandler(V2middlewareResponse)(ctx) - // ctx.Next() - // }) - // userAPIV2.Use(func(ctx iris.Context) { - // println("exec userAPIV2.Use - midl2") - // ctx.Next() - // }) - - userAPIV2.Get("/", sendHandler(v2Response)) - userAPIV2.Post("/", sendHandler(v2Response)) - userAPIV2.Put("/other", sendHandler(v2Response)) - - e := httptest.New(t, app) - - ex := e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "1").Expect() - ex.Status(iris.StatusOK).Body().Equal(v10Response) - ex.Header("X-API-Warn").Equal(versioning.DefaultDeprecationOptions.WarnMessage) - - e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "2.0").Expect(). - Status(iris.StatusOK).Body().Equal(v2Response) - e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "2.1").Expect(). - Status(iris.StatusOK).Body().Equal(v2Response) - e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "2.9.9").Expect(). - Status(iris.StatusOK).Body().Equal(v2Response) - e.POST("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "2").Expect(). - Status(iris.StatusOK).Body().Equal(v2Response) - e.PUT("/api/user/other").WithHeader(versioning.AcceptVersionHeaderKey, "2.9").Expect(). - Status(iris.StatusOK).Body().Equal(v2Response) - - e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "3.0").Expect(). - Status(iris.StatusNotImplemented).Body().Equal("version not found") -} diff --git a/view/README.md b/view/README.md index 17599f3d..e98dec96 100644 --- a/view/README.md +++ b/view/README.md @@ -27,7 +27,7 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) files to // file: main.go package main -import "github.com/kataras/iris/v12" +import "github.com/kataras/iris" func main() { app := iris.New() @@ -74,7 +74,7 @@ func main() { ```go package main -import "github.com/kataras/iris/v12" +import "github.com/kataras/iris" func main() { app := iris.New() @@ -124,7 +124,7 @@ Example code: ```go package main -import "github.com/kataras/iris/v12" +import "github.com/kataras/iris" func main() { app := iris.New() diff --git a/view/django.go b/view/django.go index e77f8860..09813a14 100644 --- a/view/django.go +++ b/view/django.go @@ -11,7 +11,7 @@ import ( "strings" "sync" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" "github.com/iris-contrib/pongo2" ) diff --git a/view/jet.go b/view/jet.go index afab0c79..a1c5a5d3 100644 --- a/view/jet.go +++ b/view/jet.go @@ -9,7 +9,7 @@ import ( "reflect" "strings" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" "github.com/CloudyKit/jet/v4" ) diff --git a/view/view.go b/view/view.go index 05abdf78..5da05786 100644 --- a/view/view.go +++ b/view/view.go @@ -6,7 +6,7 @@ import ( "path/filepath" "strings" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" ) type ( diff --git a/websocket/websocket.go b/websocket/websocket.go index 5428baff..98c45a70 100644 --- a/websocket/websocket.go +++ b/websocket/websocket.go @@ -3,7 +3,7 @@ package websocket import ( "net/http" - "github.com/kataras/iris/v12/context" + "github.com/kataras/iris/context" "github.com/kataras/neffos" "github.com/kataras/neffos/gobwas"

      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π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 diff --git a/_examples/database/mongodb/3_get_movie.png b/_examples/database/mongodb/3_get_movie.png deleted file mode 100644 index 71eca41ed0130821a783a6e3707395a9e0f6cded..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 85269 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 z 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 diff --git a/_examples/database/mongodb/4_delete_movie.png b/_examples/database/mongodb/4_delete_movie.png deleted file mode 100644 index 185b730a711e86cb6fa3f2930c1e5decbeca2ab9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49580 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 diff --git a/_examples/database/mongodb/Dockerfile b/_examples/database/mongodb/Dockerfile deleted file mode 100644 index dec864fe..00000000 --- a/_examples/database/mongodb/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -# docker build -t myapp . -# docker run --rm -it -p 8080:8080 myapp:latest -FROM golang:latest AS builder -RUN apt-get update -ENV GO111MODULE=on \ - CGO_ENABLED=0 \ - GOOS=linux \ - GOARCH=amd64 -WORKDIR /go/src/app -COPY go.mod . -RUN go mod download -COPY . . -RUN go install - -FROM scratch -COPY --from=builder /go/bin/myapp . -ENTRYPOINT ["./myapp"] \ No newline at end of file diff --git a/_examples/database/mongodb/README.md b/_examples/database/mongodb/README.md deleted file mode 100644 index 4953dd17..00000000 --- a/_examples/database/mongodb/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# Build RESTful API with the official MongoDB Go Driver and Iris - -Article is coming soon, follow and stay tuned - -- -- - -Read [the fully functional example](main.go). - -## Run - -### Docker - -Install [Docker](https://www.docker.com/) and execute the command below - -```sh -$ docker-compose up -``` - -### Manually - -```sh -# .env file contents -PORT=8080 -DSN=mongodb://localhost:27017 -``` - -```sh -$ go run main.go -> 2019/01/28 05:17:59 Loading environment variables from file: .env -> 2019/01/28 05:17:59 ◽ Port=8080 -> 2019/01/28 05:17:59 ◽ DSN=mongodb://localhost:27017 -> Now listening on: http://localhost:8080 -``` - -```sh -GET : http://localhost:8080/api/store/movies -POST : http://localhost:8080/api/store/movies -GET : http://localhost:8080/api/store/movies/{id} -PUT : http://localhost:8080/api/store/movies/{id} -DELETE : http://localhost:8080/api/store/movies/{id} -``` - -## Screens - -### Add a Movie -![](0_create_movie.png) - -### Update a Movie - -![](1_update_movie.png) - -### Get all Movies - -![](2_get_all_movies.png) - -### Get a Movie by its ID - -![](3_get_movie.png) - -### Delete a Movie by its ID - -![](4_delete_movie.png) - diff --git a/_examples/database/mongodb/api/store/movie.go b/_examples/database/mongodb/api/store/movie.go deleted file mode 100644 index 3a2d9fb2..00000000 --- a/_examples/database/mongodb/api/store/movie.go +++ /dev/null @@ -1,101 +0,0 @@ -package storeapi - -import ( - "myapp/httputil" - "myapp/store" - - "github.com/kataras/iris/v12" -) - -type MovieHandler struct { - service store.MovieService -} - -func NewMovieHandler(service store.MovieService) *MovieHandler { - return &MovieHandler{service: service} -} - -func (h *MovieHandler) GetAll(ctx iris.Context) { - movies, err := h.service.GetAll(nil) - if err != nil { - httputil.InternalServerErrorJSON(ctx, err, "Server was unable to retrieve all movies") - return - } - - if movies == nil { - // will return "null" if empty, with this "trick" we return "[]" json. - movies = make([]store.Movie, 0) - } - - ctx.JSON(movies) -} - -func (h *MovieHandler) Get(ctx iris.Context) { - id := ctx.Params().Get("id") - - m, err := h.service.GetByID(nil, id) - if err != nil { - if err == store.ErrNotFound { - ctx.NotFound() - } else { - httputil.InternalServerErrorJSON(ctx, err, "Server was unable to retrieve movie [%s]", id) - } - return - } - - ctx.JSON(m) -} - -func (h *MovieHandler) Add(ctx iris.Context) { - m := new(store.Movie) - - err := ctx.ReadJSON(m) - if err != nil { - httputil.FailJSON(ctx, iris.StatusBadRequest, err, "Malformed request payload") - return - } - - err = h.service.Create(nil, m) - if err != nil { - httputil.InternalServerErrorJSON(ctx, err, "Server was unable to create a movie") - return - } - - ctx.StatusCode(iris.StatusCreated) - ctx.JSON(m) -} - -func (h *MovieHandler) Update(ctx iris.Context) { - id := ctx.Params().Get("id") - - var m store.Movie - err := ctx.ReadJSON(&m) - if err != nil { - httputil.FailJSON(ctx, iris.StatusBadRequest, err, "Malformed request payload") - return - } - - err = h.service.Update(nil, id, m) - if err != nil { - if err == store.ErrNotFound { - ctx.NotFound() - return - } - httputil.InternalServerErrorJSON(ctx, err, "Server was unable to update movie [%s]", id) - return - } -} - -func (h *MovieHandler) Delete(ctx iris.Context) { - id := ctx.Params().Get("id") - - err := h.service.Delete(nil, id) - if err != nil { - if err == store.ErrNotFound { - ctx.NotFound() - return - } - httputil.InternalServerErrorJSON(ctx, err, "Server was unable to delete movie [%s]", id) - return - } -} diff --git a/_examples/database/mongodb/docker-compose.yml b/_examples/database/mongodb/docker-compose.yml deleted file mode 100644 index a9eec93e..00000000 --- a/_examples/database/mongodb/docker-compose.yml +++ /dev/null @@ -1,18 +0,0 @@ -version: "3.1" - -services: - app: - build: . - environment: - Port: 8080 - DSN: db:27017 - ports: - - 8080:8080 - depends_on: - - db - db: - image: mongo - environment: - MONGO_INITDB_DATABASE: store - ports: - - 27017:27017 diff --git a/_examples/database/mongodb/env/env.go b/_examples/database/mongodb/env/env.go deleted file mode 100644 index 9f735b43..00000000 --- a/_examples/database/mongodb/env/env.go +++ /dev/null @@ -1,85 +0,0 @@ -package env - -import ( - "fmt" - "log" - "os" - "path/filepath" - "strings" - - "github.com/joho/godotenv" -) - -var ( - // Port is the PORT environment variable or 8080 if missing. - // Used to open the tcp listener for our web server. - Port string - // DSN is the DSN environment variable or mongodb://localhost:27017 if missing. - // Used to connect to the mongodb. - DSN string -) - -func parse() { - Port = getDefault("PORT", "8080") - DSN = getDefault("DSN", "mongodb://localhost:27017") - - log.Printf("• Port=%s\n", Port) - log.Printf("• DSN=%s\n", DSN) -} - -// Load loads environment variables that are being used across the whole app. -// Loading from file(s), i.e .env or dev.env -// -// Example of a 'dev.env': -// PORT=8080 -// DSN=mongodb://localhost:27017 -// -// After `Load` the callers can get an environment variable via `os.Getenv`. -func Load(envFileName string) { - if args := os.Args; len(args) > 1 && args[1] == "help" { - fmt.Fprintln(os.Stderr, "https://github.com/kataras/iris/blob/master/_examples/database/mongodb/README.md") - os.Exit(-1) - } - - // If more than one filename passed with comma separated then load from all - // of these, a env file can be a partial too. - envFiles := strings.Split(envFileName, ",") - for _, envFile := range envFiles { - if filepath.Ext(envFile) == "" { - envFile += ".env" - } - - if fileExists(envFile) { - log.Printf("Loading environment variables from file: %s\n", envFile) - - if err := godotenv.Load(envFile); err != nil { - panic(fmt.Sprintf("error loading environment variables from [%s]: %v", envFile, err)) - } - } - } - - // envMap, _ := godotenv.Read(envFiles...) - // for k, v := range envMap { - // log.Printf("◽ %s=%s\n", k, v) - // } - - parse() -} - -func getDefault(key string, def string) string { - value := os.Getenv(key) - if value == "" { - os.Setenv(key, def) - value = def - } - - return value -} - -func fileExists(filename string) bool { - info, err := os.Stat(filename) - if os.IsNotExist(err) { - return false - } - return !info.IsDir() -} diff --git a/_examples/database/mongodb/go.mod b/_examples/database/mongodb/go.mod deleted file mode 100644 index 511a8000..00000000 --- a/_examples/database/mongodb/go.mod +++ /dev/null @@ -1,9 +0,0 @@ -module myapp - -go 1.15 - -require ( - github.com/joho/godotenv v1.3.0 - github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd - go.mongodb.org/mongo-driver v1.3.4 -) diff --git a/_examples/database/mongodb/httputil/error.go b/_examples/database/mongodb/httputil/error.go deleted file mode 100644 index 4bcc740f..00000000 --- a/_examples/database/mongodb/httputil/error.go +++ /dev/null @@ -1,130 +0,0 @@ -package httputil - -import ( - "errors" - "fmt" - "io" - "net/http" - "os" - "runtime" - "runtime/debug" - "strings" - "time" - - "github.com/kataras/iris/v12" -) - -var validStackFuncs = []func(string) bool{ - func(file string) bool { - return strings.Contains(file, "/mongodb/api/") - }, -} - -// RuntimeCallerStack returns the app's `file:line` stacktrace -// to give more information about an error cause. -func RuntimeCallerStack() (s string) { - var pcs [10]uintptr - n := runtime.Callers(1, pcs[:]) - frames := runtime.CallersFrames(pcs[:n]) - - for { - frame, more := frames.Next() - for _, fn := range validStackFuncs { - if fn(frame.File) { - s += fmt.Sprintf("\n\t\t\t%s:%d", frame.File, frame.Line) - } - } - - if !more { - break - } - } - - return s -} - -// HTTPError describes an HTTP error. -type HTTPError struct { - error - Stack string `json:"-"` // the whole stacktrace. - CallerStack string `json:"-"` // the caller, file:lineNumber - When time.Time `json:"-"` // the time that the error occurred. - // ErrorCode int: maybe a collection of known error codes. - StatusCode int `json:"statusCode"` - // could be named as "reason" as well - // it's the message of the error. - Description string `json:"description"` -} - -func newError(statusCode int, err error, format string, args ...interface{}) HTTPError { - if format == "" { - format = http.StatusText(statusCode) - } - - desc := fmt.Sprintf(format, args...) - if err == nil { - err = errors.New(desc) - } - - return HTTPError{ - err, - string(debug.Stack()), - RuntimeCallerStack(), - time.Now(), - statusCode, - desc, - } -} - -func (err HTTPError) writeHeaders(ctx iris.Context) { - ctx.StatusCode(err.StatusCode) - ctx.Header("X-Content-Type-Options", "nosniff") -} - -// LogFailure will print out the failure to the "logger". -func LogFailure(logger io.Writer, ctx iris.Context, err HTTPError) { - timeFmt := err.When.Format("2006/01/02 15:04:05") - firstLine := fmt.Sprintf("%s %s: %s", timeFmt, http.StatusText(err.StatusCode), err.Error()) - whitespace := strings.Repeat(" ", len(timeFmt)+1) - fmt.Fprintf(logger, "%s\n%sIP: %s\n%sURL: %s\n%sSource: %s\n", - firstLine, whitespace, ctx.RemoteAddr(), whitespace, ctx.FullRequestURI(), whitespace, err.CallerStack) -} - -// Fail will send the status code, write the error's reason -// and return the HTTPError for further use, i.e logging, see `InternalServerError`. -func Fail(ctx iris.Context, statusCode int, err error, format string, args ...interface{}) HTTPError { - httpErr := newError(statusCode, err, format, args...) - httpErr.writeHeaders(ctx) - - ctx.WriteString(httpErr.Description) - return httpErr -} - -// FailJSON will send to the client the error data as JSON. -// Useful for APIs. -func FailJSON(ctx iris.Context, statusCode int, err error, format string, args ...interface{}) HTTPError { - httpErr := newError(statusCode, err, format, args...) - httpErr.writeHeaders(ctx) - - ctx.JSON(httpErr) - - return httpErr -} - -// InternalServerError logs to the server's terminal -// and dispatches to the client the 500 Internal Server Error. -// Internal Server errors are critical, so we log them to the `os.Stderr`. -func InternalServerError(ctx iris.Context, err error, format string, args ...interface{}) { - LogFailure(os.Stderr, ctx, Fail(ctx, iris.StatusInternalServerError, err, format, args...)) -} - -// InternalServerErrorJSON acts exactly like `InternalServerError` but instead it sends the data as JSON. -// Useful for APIs. -func InternalServerErrorJSON(ctx iris.Context, err error, format string, args ...interface{}) { - LogFailure(os.Stderr, ctx, FailJSON(ctx, iris.StatusInternalServerError, err, format, args...)) -} - -// UnauthorizedJSON sends JSON format of StatusUnauthorized(401) HTTPError value. -func UnauthorizedJSON(ctx iris.Context, err error, format string, args ...interface{}) HTTPError { - return FailJSON(ctx, iris.StatusUnauthorized, err, format, args...) -} diff --git a/_examples/database/mongodb/main.go b/_examples/database/mongodb/main.go deleted file mode 100644 index 185d08f6..00000000 --- a/_examples/database/mongodb/main.go +++ /dev/null @@ -1,83 +0,0 @@ -package main - -// go get -u go.mongodb.org/mongo-driver -// go get -u github.com/joho/godotenv - -import ( - "context" - "flag" - "fmt" - "log" - "os" - - // APIs - storeapi "myapp/api/store" - - // - "myapp/env" - "myapp/store" - - "github.com/kataras/iris/v12" - - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" -) - -const version = "0.0.1" - -func init() { - envFileName := ".env" - - flagset := flag.CommandLine - flagset.StringVar(&envFileName, "env", envFileName, "the env file which web app will use to extract its environment variables") - flagset.Parse(os.Args[1:]) - - env.Load(envFileName) -} - -func main() { - clientOptions := options.Client().SetHosts([]string{env.DSN}) - client, err := mongo.Connect(context.Background(), clientOptions) - if err != nil { - log.Fatal(err) - } - - err = client.Ping(context.Background(), nil) - if err != nil { - log.Fatal(err) - } - defer client.Disconnect(context.TODO()) - - db := client.Database("store") - - var ( - // Collections. - moviesCollection = db.Collection("movies") - - // Services. - movieService = store.NewMovieService(moviesCollection) - ) - - app := iris.New() - app.Use(func(ctx iris.Context) { - ctx.Header("Server", "Iris MongoDB/"+version) - ctx.Next() - }) - - storeAPI := app.Party("/api/store") - { - movieHandler := storeapi.NewMovieHandler(movieService) - storeAPI.Get("/movies", movieHandler.GetAll) - storeAPI.Post("/movies", movieHandler.Add) - storeAPI.Get("/movies/{id}", movieHandler.Get) - storeAPI.Put("/movies/{id}", movieHandler.Update) - storeAPI.Delete("/movies/{id}", movieHandler.Delete) - } - - // GET: http://localhost:8080/api/store/movies - // POST: http://localhost:8080/api/store/movies - // GET: http://localhost:8080/api/store/movies/{id} - // PUT: http://localhost:8080/api/store/movies/{id} - // DELETE: http://localhost:8080/api/store/movies/{id} - app.Listen(fmt.Sprintf(":%s", env.Port), iris.WithOptimizations) -} diff --git a/_examples/database/mongodb/store/movie.go b/_examples/database/mongodb/store/movie.go deleted file mode 100644 index 133cddc9..00000000 --- a/_examples/database/mongodb/store/movie.go +++ /dev/null @@ -1,180 +0,0 @@ -package store - -import ( - "context" - "errors" - - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - // up to you: - // "go.mongodb.org/mongo-driver/mongo/options" -) - -type Movie struct { - ID primitive.ObjectID `json:"_id" bson:"_id"` /* you need the bson:"_id" to be able to retrieve with ID filled */ - Name string `json:"name"` - Cover string `json:"cover"` - Description string `json:"description"` -} - -type MovieService interface { - GetAll(ctx context.Context) ([]Movie, error) - GetByID(ctx context.Context, id string) (Movie, error) - Create(ctx context.Context, m *Movie) error - Update(ctx context.Context, id string, m Movie) error - Delete(ctx context.Context, id string) error -} - -type movieService struct { - C *mongo.Collection -} - -var _ MovieService = (*movieService)(nil) - -func NewMovieService(collection *mongo.Collection) MovieService { - // up to you: - // indexOpts := new(options.IndexOptions) - // indexOpts.SetName("movieIndex"). - // SetUnique(true). - // SetBackground(true). - // SetSparse(true) - - // collection.Indexes().CreateOne(context.Background(), mongo.IndexModel{ - // Keys: []string{"_id", "name"}, - // Options: indexOpts, - // }) - - return &movieService{C: collection} -} - -func (s *movieService) GetAll(ctx context.Context) ([]Movie, error) { - // Note: - // The mongodb's go-driver's docs says that you can pass `nil` to "find all" but this gives NilDocument error, - // probably it's a bug or a documentation's mistake, you have to pass `bson.D{}` instead. - cur, err := s.C.Find(ctx, bson.D{}) - if err != nil { - return nil, err - } - defer cur.Close(ctx) - - var results []Movie - - for cur.Next(ctx) { - if err = cur.Err(); err != nil { - return nil, err - } - - // elem := bson.D{} - var elem Movie - err = cur.Decode(&elem) - if err != nil { - return nil, err - } - - // results = append(results, Movie{ID: elem[0].Value.(primitive.ObjectID)}) - - results = append(results, elem) - } - - return results, nil -} - -func matchID(id string) (bson.D, error) { - objectID, err := primitive.ObjectIDFromHex(id) - if err != nil { - return nil, err - } - - filter := bson.D{{Key: "_id", Value: objectID}} - return filter, nil -} - -var ErrNotFound = errors.New("not found") - -func (s *movieService) GetByID(ctx context.Context, id string) (Movie, error) { - var movie Movie - filter, err := matchID(id) - if err != nil { - return movie, err - } - - err = s.C.FindOne(ctx, filter).Decode(&movie) - if err == mongo.ErrNoDocuments { - return movie, ErrNotFound - } - return movie, err -} - -func (s *movieService) Create(ctx context.Context, m *Movie) error { - if m.ID.IsZero() { - m.ID = primitive.NewObjectID() - } - - _, err := s.C.InsertOne(ctx, m) - if err != nil { - return err - } - - // The following doesn't work if you have the `bson:"_id` on Movie.ID field, - // therefore we manually generate a new ID (look above). - // res, err := ...InsertOne - // objectID := res.InsertedID.(primitive.ObjectID) - // m.ID = objectID - return nil -} - -func (s *movieService) Update(ctx context.Context, id string, m Movie) error { - filter, err := matchID(id) - if err != nil { - return err - } - - // update := bson.D{ - // {Key: "$set", Value: m}, - // } - // ^ this will override all fields, you can do that, depending on your design. but let's check each field: - elem := bson.D{} - - if m.Name != "" { - elem = append(elem, bson.E{Key: "name", Value: m.Name}) - } - - if m.Description != "" { - elem = append(elem, bson.E{Key: "description", Value: m.Description}) - } - - if m.Cover != "" { - elem = append(elem, bson.E{Key: "cover", Value: m.Cover}) - } - - update := bson.D{ - {Key: "$set", Value: elem}, - } - - _, err = s.C.UpdateOne(ctx, filter, update) - if err != nil { - if err == mongo.ErrNoDocuments { - return ErrNotFound - } - return err - } - - return nil -} - -func (s *movieService) Delete(ctx context.Context, id string) error { - filter, err := matchID(id) - if err != nil { - return err - } - _, err = s.C.DeleteOne(ctx, filter) - if err != nil { - if err == mongo.ErrNoDocuments { - return ErrNotFound - } - return err - } - - return nil -} diff --git a/_examples/database/mysql/Dockerfile b/_examples/database/mysql/Dockerfile deleted file mode 100644 index dec864fe..00000000 --- a/_examples/database/mysql/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -# docker build -t myapp . -# docker run --rm -it -p 8080:8080 myapp:latest -FROM golang:latest AS builder -RUN apt-get update -ENV GO111MODULE=on \ - CGO_ENABLED=0 \ - GOOS=linux \ - GOARCH=amd64 -WORKDIR /go/src/app -COPY go.mod . -RUN go mod download -COPY . . -RUN go install - -FROM scratch -COPY --from=builder /go/bin/myapp . -ENTRYPOINT ["./myapp"] \ No newline at end of file diff --git a/_examples/database/mysql/README.md b/_examples/database/mysql/README.md deleted file mode 100644 index 25755226..00000000 --- a/_examples/database/mysql/README.md +++ /dev/null @@ -1,146 +0,0 @@ -# Iris, MySQL, Groupcache & Docker Example - -## 📘 Endpoints - -| Method | Path | Description | URL Parameters | Body | Auth Required | -|--------|---------------------|------------------------|--------------- |----------------------------|---------------| -| ANY | /token | Prints a new JWT Token | - | - | - | -| GET | /category | Lists a set of Categories | offset, limit, order | - | - | -| POST | /category | Creates a Category | - | JSON [Full Category](migration/api_category/create_category.json) | Token | -| PUT | /category | Fully-Updates a Category | - | JSON [Full Category](migration/api_category/update_category.json) | Token | -| PATCH | /category/{id} | Partially-Updates a Category | - | JSON [Partial Category](migration/api_category/update_partial_category.json) | Token | -| GET | /category/{id} | Prints a Category | - | - | - | -| DELETE | /category/{id} | Deletes a Category | - | - | Token | -| GET | /category/{id}/products | Lists all Products from a Category | offset, limit, order | - | - | -| POST | /category/{id}/products | (Batch) Assigns one or more Products to a Category | - | JSON [Products](migration/api_category/insert_products_category.json) | Token | -| GET | /product | Lists a set of Products (cache) | offset, limit, order | - | - | -| POST | /product | Creates a Product | - | JSON [Full Product](migration/api_product/create_product.json) | Token | -| PUT | /product | Fully-Updates a Product | - | JSON [Full Product](migration/api_product/update_product.json) | Token | -| PATCH | /product/{id} | Partially-Updates a Product | - | JSON [Partial Product](migration/api_product/update_partial_product.json) | Token | -| GET | /product/{id} | Prints a Product (cache) | - | - | - | -| DELETE | /product/{id} | Deletes a Product | - | - | Token | - - - -## 📑 Responses - -* **Content-Type** of `"application/json;charset=utf-8"`, snake_case naming (identical to the database columns) -* **Status Codes** - * 500 for server(db) errors, - * 422 for validation errors, e.g. - ```json - { - "code": 422, - "message": "required fields are missing", - "timestamp": 1589306271 - } - ``` - * 400 for malformed syntax, e.g. - ```json - { - "code": 400, - "message": "json: cannot unmarshal number -2 into Go struct field Category.position of type uint64", - "timestamp": 1589306325 - } - ``` - ```json - { - "code": 400, - "message": "json: unknown field \"field_not_exists\"", - "timestamp": 1589306367 - } - ``` - * 404 for entity not found, e.g. - ```json - { - "code": 404, - "message": "entity does not exist", - "timestamp": 1589306199 - } - ``` - * 304 for unaffected UPDATE or DELETE, - * 201 for CREATE with the last inserted ID, - * 200 for GET, UPDATE and DELETE - -## ⚡ Get Started - -Download the folder. - -### Install (Docker) - -Install [Docker](https://www.docker.com/) and execute the command below - -```sh -$ docker-compose up -``` - -### Install (Manually) - -Run `go build` or `go run main.go` and read below. - -#### MySQL - -Environment variables: - -```sh -MYSQL_USER=user_myapp -MYSQL_PASSWORD=dbpassword -MYSQL_HOST=localhost -MYSQL_DATABASE=myapp -``` - -Download the schema from [migration/myapp.sql](migration/myapp.sql) and execute it against your MySQL server instance. - -```sql -CREATE DATABASE IF NOT EXISTS myapp DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - -USE myapp; - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - -DROP TABLE IF EXISTS categories; -CREATE TABLE categories ( - id int(11) NOT NULL AUTO_INCREMENT, - title varchar(255) NOT NULL, - position int(11) NOT NULL, - image_url varchar(255) NOT NULL, - created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (id) -); - -DROP TABLE IF EXISTS products; -CREATE TABLE products ( - id int(11) NOT NULL AUTO_INCREMENT, - category_id int, - title varchar(255) NOT NULL, - image_url varchar(255) NOT NULL, - price decimal(10,2) NOT NULL, - description text NOT NULL, - created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (id), - FOREIGN KEY (category_id) REFERENCES categories(id) -); - -SET FOREIGN_KEY_CHECKS = 1; -``` - -### Requests - -Some request bodies can be found at: [migration/api_category](migration/api_category) and [migration/api_product](migration/api_product). **However** I've provided a [postman.json](migration/myapp_postman.json) Collection that you can import to your [POSTMAN](https://learning.postman.com/docs/postman/collections/importing-and-exporting-data/#collections) and start playing with the API. - -All write-access endpoints are "protected" via JWT, a client should "verify" itself. You'll need to manually take the **token** from the `http://localhost:8080/token` and put it on url parameter `?token=$token` or to the `Authentication: Bearer $token` request header. - -### Unit or End-To-End Testing? - -Testing is important. The code is written in a way that testing should be trivial (Pseudo/memory Database or SQLite local file could be integrated as well, for end-to-end tests a Docker image with MySQL and fire tests against that server). However, there is [nothing(?)](service/category_service_test.go) to see here. - -## Packages - -- https://github.com/dgrijalva/jwt-go (JWT parsing) -- https://github.com/go-sql-driver/mysql (Go Driver for MySQL) -- https://github.com/DATA-DOG/go-sqlmock (Testing DB see [service/category_service_test.go](service/category_service_test.go)) -- https://github.com/kataras/iris (HTTP) -- https://github.com/mailgun/groupcache (Caching) diff --git a/_examples/database/mysql/api/api.go b/_examples/database/mysql/api/api.go deleted file mode 100644 index 2691fdf4..00000000 --- a/_examples/database/mysql/api/api.go +++ /dev/null @@ -1,97 +0,0 @@ -// Package api contains the handlers for our HTTP Endpoints. -package api - -import ( - "time" - - "myapp/service" - "myapp/sql" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/jwt" - "github.com/kataras/iris/v12/middleware/requestid" -) - -// Router accepts any required dependencies and returns the main server's handler. -func Router(db sql.Database, secret string) func(iris.Party) { - return func(r iris.Party) { - j := jwt.HMAC(15*time.Minute, secret) - - r.Use(requestid.New()) - r.Use(verifyToken(j)) - // Generate a token for testing by navigating to - // http://localhost:8080/token endpoint. - // Copy-paste it to a ?token=$token url parameter or - // open postman and put an Authentication: Bearer $token to get - // access on create, update and delete endpoinds. - - r.Get("/token", writeToken(j)) - - var ( - categoryService = service.NewCategoryService(db) - productService = service.NewProductService(db) - ) - - cat := r.Party("/category") - { - // TODO: new Use to add middlewares to specific - // routes per METHOD ( we already have the per path through parties.) - handler := NewCategoryHandler(categoryService) - - cat.Get("/", handler.List) - cat.Post("/", handler.Create) - cat.Put("/", handler.Update) - - cat.Get("/{id:int64}", handler.GetByID) - cat.Patch("/{id:int64}", handler.PartialUpdate) - cat.Delete("/{id:int64}", handler.Delete) - /* You can also do something like that: - cat.PartyFunc("/{id:int64}", func(c iris.Party) { - c.Get("/", handler.GetByID) - c.Post("/", handler.PartialUpdate) - c.Delete("/", handler.Delete) - }) - */ - - cat.Get("/{id:int64}/products", handler.ListProducts) - cat.Post("/{id:int64}/products", handler.InsertProducts(productService)) - } - - prod := r.Party("/product") - { - handler := NewProductHandler(productService) - - prod.Get("/", handler.List) - prod.Post("/", handler.Create) - prod.Put("/", handler.Update) - - prod.Get("/{id:int64}", handler.GetByID) - prod.Patch("/{id:int64}", handler.PartialUpdate) - prod.Delete("/{id:int64}", handler.Delete) - } - - } -} - -func writeToken(j *jwt.JWT) iris.Handler { - return func(ctx iris.Context) { - claims := jwt.Claims{ - Issuer: "https://iris-go.com", - Audience: jwt.Audience{requestid.Get(ctx)}, - } - - j.WriteToken(ctx, claims) - } -} - -func verifyToken(j *jwt.JWT) iris.Handler { - return func(ctx iris.Context) { - // Allow all GET. - if ctx.Method() == iris.MethodGet { - ctx.Next() - return - } - - j.Verify(ctx) - } -} diff --git a/_examples/database/mysql/api/category_handler.go b/_examples/database/mysql/api/category_handler.go deleted file mode 100644 index 7e8c3f84..00000000 --- a/_examples/database/mysql/api/category_handler.go +++ /dev/null @@ -1,251 +0,0 @@ -package api - -import ( - "myapp/entity" - "myapp/service" - "myapp/sql" - - "github.com/kataras/iris/v12" -) - -// CategoryHandler is the http mux for categories. -type CategoryHandler struct { - // [...options] - - service *service.CategoryService -} - -// NewCategoryHandler returns the main controller for the categories API. -func NewCategoryHandler(service *service.CategoryService) *CategoryHandler { - return &CategoryHandler{service} -} - -// GetByID fetches a single record from the database and sends it to the client. -// Method: GET. -func (h *CategoryHandler) GetByID(ctx iris.Context) { - id := ctx.Params().GetInt64Default("id", 0) - - var cat entity.Category - err := h.service.GetByID(ctx.Request().Context(), &cat, id) - if err != nil { - if err == sql.ErrNoRows { - writeEntityNotFound(ctx) - return - } - - debugf("CategoryHandler.GetByID(id=%d): %v", id, err) - writeInternalServerError(ctx) - return - } - - ctx.JSON(cat) -} - -/* - -type ( - List struct { - Data interface{} `json:"data"` - Order string `json:"order"` - Next Range `json:"next,omitempty"` - Prev Range `json:"prev,omitempty"` - } - - Range struct { - Offset int64 `json:"offset"` - Limit int64 `json:"limit` - } -) -*/ - -// List lists a set of records from the database. -// Method: GET. -func (h *CategoryHandler) List(ctx iris.Context) { - q := ctx.Request().URL.Query() - opts := sql.ParseListOptions(q) - - // initialize here in order to return an empty json array `[]` instead of `null`. - categories := entity.Categories{} - err := h.service.List(ctx.Request().Context(), &categories, opts) - if err != nil && err != sql.ErrNoRows { - debugf("CategoryHandler.List(DB) (limit=%d offset=%d where=%s=%v): %v", - opts.Limit, opts.Offset, opts.WhereColumn, opts.WhereValue, err) - - writeInternalServerError(ctx) - return - } - - ctx.JSON(categories) -} - -// Create adds a record to the database. -// Method: POST. -func (h *CategoryHandler) Create(ctx iris.Context) { - var cat entity.Category - if err := ctx.ReadJSON(&cat); err != nil { - return - } - - id, err := h.service.Insert(ctx.Request().Context(), cat) - if err != nil { - if err == sql.ErrUnprocessable { - ctx.StopWithJSON(iris.StatusUnprocessableEntity, newError(iris.StatusUnprocessableEntity, ctx.Request().Method, ctx.Path(), "required fields are missing")) - return - } - - debugf("CategoryHandler.Create(DB): %v", err) - writeInternalServerError(ctx) - return - } - - // Send 201 with body of {"id":$last_inserted_id"}. - ctx.StatusCode(iris.StatusCreated) - ctx.JSON(iris.Map{cat.PrimaryKey(): id}) -} - -// Update performs a full-update of a record in the database. -// Method: PUT. -func (h *CategoryHandler) Update(ctx iris.Context) { - var cat entity.Category - if err := ctx.ReadJSON(&cat); err != nil { - return - } - - affected, err := h.service.Update(ctx.Request().Context(), cat) - if err != nil { - if err == sql.ErrUnprocessable { - ctx.StopWithJSON(iris.StatusUnprocessableEntity, newError(iris.StatusUnprocessableEntity, ctx.Request().Method, ctx.Path(), "required fields are missing")) - return - } - - debugf("CategoryHandler.Update(DB): %v", err) - writeInternalServerError(ctx) - return - } - - status := iris.StatusOK - if affected == 0 { - status = iris.StatusNotModified - } - - ctx.StatusCode(status) -} - -// PartialUpdate is the handler for partially update one or more fields of the record. -// Method: PATCH. -func (h *CategoryHandler) PartialUpdate(ctx iris.Context) { - id := ctx.Params().GetInt64Default("id", 0) - - var attrs map[string]interface{} - if err := ctx.ReadJSON(&attrs); err != nil { - return - } - - affected, err := h.service.PartialUpdate(ctx.Request().Context(), id, attrs) - if err != nil { - if err == sql.ErrUnprocessable { - ctx.StopWithJSON(iris.StatusUnprocessableEntity, newError(iris.StatusUnprocessableEntity, ctx.Request().Method, ctx.Path(), "unsupported value(s)")) - return - } - - debugf("CategoryHandler.PartialUpdate(DB): %v", err) - writeInternalServerError(ctx) - return - } - - status := iris.StatusOK - if affected == 0 { - status = iris.StatusNotModified - } - - ctx.StatusCode(status) -} - -// Delete removes a record from the database. -// Method: DELETE. -func (h *CategoryHandler) Delete(ctx iris.Context) { - id := ctx.Params().GetInt64Default("id", 0) - - affected, err := h.service.DeleteByID(ctx.Request().Context(), id) - if err != nil { - debugf("CategoryHandler.Delete(DB): %v", err) - writeInternalServerError(ctx) - return - } - - status := iris.StatusOK // StatusNoContent - if affected == 0 { - status = iris.StatusNotModified - } - - ctx.StatusCode(status) -} - -// Products. - -// ListProducts lists products of a Category. -// Example: from cheap to expensive: -// http://localhost:8080/category/3/products?offset=0&limit=30&by=price&order=asc -// Method: GET. -func (h *CategoryHandler) ListProducts(ctx iris.Context) { - id := ctx.Params().GetInt64Default("id", 0) - - // NOTE: could add cache here too. - - q := ctx.Request().URL.Query() - opts := sql.ParseListOptions(q).Where("category_id", id) - opts.Table = "products" - if opts.OrderByColumn == "" { - opts.OrderByColumn = "updated_at" - } - - var products entity.Products - err := h.service.List(ctx.Request().Context(), &products, opts) - if err != nil { - debugf("CategoryHandler.ListProducts(DB) (table=%s where=%s=%v limit=%d offset=%d): %v", - opts.Table, opts.WhereColumn, opts.WhereValue, opts.Limit, opts.Offset, err) - - writeInternalServerError(ctx) - return - } - - ctx.JSON(products) -} - -// InsertProducts assigns new products to a Category (accepts a list of products). -// Method: POST. -func (h *CategoryHandler) InsertProducts(productService *service.ProductService) iris.Handler { - return func(ctx iris.Context) { - categoryID := ctx.Params().GetInt64Default("id", 0) - - var products []entity.Product - if err := ctx.ReadJSON(&products); err != nil { - return - } - - for i := range products { - products[i].CategoryID = categoryID - } - - inserted, err := productService.BatchInsert(ctx.Request().Context(), products) - if err != nil { - if err == sql.ErrUnprocessable { - ctx.StopWithJSON(iris.StatusUnprocessableEntity, newError(iris.StatusUnprocessableEntity, ctx.Request().Method, ctx.Path(), "required fields are missing")) - return - } - - debugf("CategoryHandler.InsertProducts(DB): %v", err) - writeInternalServerError(ctx) - return - } - - if inserted == 0 { - ctx.StatusCode(iris.StatusNotModified) - return - } - - // Send 201 with body of {"inserted":$inserted"}. - ctx.StatusCode(iris.StatusCreated) - ctx.JSON(iris.Map{"inserted": inserted}) - } -} diff --git a/_examples/database/mysql/api/helper.go b/_examples/database/mysql/api/helper.go deleted file mode 100644 index 8ee14c0f..00000000 --- a/_examples/database/mysql/api/helper.go +++ /dev/null @@ -1,25 +0,0 @@ -package api - -import ( - "log" - - "github.com/kataras/iris/v12" -) - -const debug = true - -func debugf(format string, args ...interface{}) { - if !debug { - return - } - - log.Printf(format, args...) -} - -func writeInternalServerError(ctx iris.Context) { - ctx.StopWithJSON(iris.StatusInternalServerError, newError(iris.StatusInternalServerError, ctx.Request().Method, ctx.Path(), "")) -} - -func writeEntityNotFound(ctx iris.Context) { - ctx.StopWithJSON(iris.StatusNotFound, newError(iris.StatusNotFound, ctx.Request().Method, ctx.Path(), "entity does not exist")) -} diff --git a/_examples/database/mysql/api/httperror.go b/_examples/database/mysql/api/httperror.go deleted file mode 100644 index 7b599eeb..00000000 --- a/_examples/database/mysql/api/httperror.go +++ /dev/null @@ -1,60 +0,0 @@ -package api - -import ( - "fmt" - "time" - - "github.com/kataras/iris/v12" -) - -// Error holds the error sent by server to clients (JSON). -type Error struct { - StatusCode int `json:"code"` - Method string `json:"-"` - Path string `json:"-"` - Message string `json:"message"` - Timestamp int64 `json:"timestamp"` -} - -func newError(statusCode int, method, path, format string, args ...interface{}) Error { - msg := format - if len(args) > 0 { - // why we check for that? If the original error message came from our database - // and it contains fmt-reserved words - // like %s or %d we will get MISSING(=...) in our error message and we don't want that. - msg = fmt.Sprintf(msg, args...) - } - - if msg == "" { - msg = iris.StatusText(statusCode) - } - - return Error{ - StatusCode: statusCode, - Method: method, - Path: path, - Message: msg, - Timestamp: time.Now().Unix(), - } -} - -// Error implements the internal Go error interface. -func (e Error) Error() string { - return fmt.Sprintf("[%d] %s: %s: %s", e.StatusCode, e.Method, e.Path, e.Message) -} - -// Is implements the standard `errors.Is` internal interface. -// Usage: errors.Is(e, target) -func (e Error) Is(target error) bool { - if target == nil { - return false - } - - err, ok := target.(Error) - if !ok { - return false - } - - return (err.StatusCode == e.StatusCode || e.StatusCode == 0) && - (err.Message == e.Message || e.Message == "") -} diff --git a/_examples/database/mysql/api/middleware/.gitkeep b/_examples/database/mysql/api/middleware/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/_examples/database/mysql/api/product_handler.go b/_examples/database/mysql/api/product_handler.go deleted file mode 100644 index 31250bf3..00000000 --- a/_examples/database/mysql/api/product_handler.go +++ /dev/null @@ -1,173 +0,0 @@ -package api - -import ( - "time" - - "myapp/cache" - "myapp/entity" - "myapp/service" - "myapp/sql" - - "github.com/kataras/iris/v12" -) - -// ProductHandler is the http mux for products. -type ProductHandler struct { - service *service.ProductService - cache *cache.Cache -} - -// NewProductHandler returns the main controller for the products API. -func NewProductHandler(service *service.ProductService) *ProductHandler { - return &ProductHandler{ - service: service, - cache: cache.New(service, "products", time.Minute), - } -} - -// GetByID fetches a single record from the database and sends it to the client. -// Method: GET. -func (h *ProductHandler) GetByID(ctx iris.Context) { - id := ctx.Params().GetString("id") - - var product []byte - err := h.cache.GetByID(ctx.Request().Context(), id, &product) - if err != nil { - if err == sql.ErrNoRows { - writeEntityNotFound(ctx) - return - } - - debugf("ProductHandler.GetByID(id=%v): %v", id, err) - writeInternalServerError(ctx) - return - } - - ctx.ContentType("application/json") - ctx.Write(product) - - // ^ Could use our simple `noCache` or implement a Cache-Control (see kataras/iris/cache for that) - // but let's keep it simple. -} - -// List lists a set of records from the database. -// Method: GET. -func (h *ProductHandler) List(ctx iris.Context) { - key := ctx.Request().URL.RawQuery - - products := []byte("[]") - err := h.cache.List(ctx.Request().Context(), key, &products) - if err != nil && err != sql.ErrNoRows { - debugf("ProductHandler.List(DB) (%s): %v", - key, err) - - writeInternalServerError(ctx) - return - } - - ctx.ContentType("application/json") - ctx.Write(products) -} - -// Create adds a record to the database. -// Method: POST. -func (h *ProductHandler) Create(ctx iris.Context) { - var product entity.Product - if err := ctx.ReadJSON(&product); err != nil { - return - } - - id, err := h.service.Insert(ctx.Request().Context(), product) - if err != nil { - if err == sql.ErrUnprocessable { - ctx.StopWithJSON(iris.StatusUnprocessableEntity, newError(iris.StatusUnprocessableEntity, ctx.Request().Method, ctx.Path(), "required fields are missing")) - return - } - - debugf("ProductHandler.Create(DB): %v", err) - writeInternalServerError(ctx) - return - } - - // Send 201 with body of {"id":$last_inserted_id"}. - ctx.StatusCode(iris.StatusCreated) - ctx.JSON(iris.Map{product.PrimaryKey(): id}) -} - -// Update performs a full-update of a record in the database. -// Method: PUT. -func (h *ProductHandler) Update(ctx iris.Context) { - var product entity.Product - if err := ctx.ReadJSON(&product); err != nil { - return - } - - affected, err := h.service.Update(ctx.Request().Context(), product) - if err != nil { - if err == sql.ErrUnprocessable { - ctx.StopWithJSON(iris.StatusUnprocessableEntity, newError(iris.StatusUnprocessableEntity, ctx.Request().Method, ctx.Path(), "required fields are missing")) - return - } - - debugf("ProductHandler.Update(DB): %v", err) - writeInternalServerError(ctx) - return - } - - status := iris.StatusOK - if affected == 0 { - status = iris.StatusNotModified - } - - ctx.StatusCode(status) -} - -// PartialUpdate is the handler for partially update one or more fields of the record. -// Method: PATCH. -func (h *ProductHandler) PartialUpdate(ctx iris.Context) { - id := ctx.Params().GetInt64Default("id", 0) - - var attrs map[string]interface{} - if err := ctx.ReadJSON(&attrs); err != nil { - return - } - - affected, err := h.service.PartialUpdate(ctx.Request().Context(), id, attrs) - if err != nil { - if err == sql.ErrUnprocessable { - ctx.StopWithJSON(iris.StatusUnprocessableEntity, newError(iris.StatusUnprocessableEntity, ctx.Request().Method, ctx.Path(), "unsupported value(s)")) - return - } - - debugf("ProductHandler.PartialUpdate(DB): %v", err) - writeInternalServerError(ctx) - return - } - - status := iris.StatusOK - if affected == 0 { - status = iris.StatusNotModified - } - - ctx.StatusCode(status) -} - -// Delete removes a record from the database. -// Method: DELETE. -func (h *ProductHandler) Delete(ctx iris.Context) { - id := ctx.Params().GetInt64Default("id", 0) - - affected, err := h.service.DeleteByID(ctx.Request().Context(), id) - if err != nil { - debugf("ProductHandler.Delete(DB): %v", err) - writeInternalServerError(ctx) - return - } - - status := iris.StatusOK // StatusNoContent - if affected == 0 { - status = iris.StatusNotModified - } - - ctx.StatusCode(status) -} diff --git a/_examples/database/mysql/cache/groupcache.go b/_examples/database/mysql/cache/groupcache.go deleted file mode 100644 index 4fb4e30d..00000000 --- a/_examples/database/mysql/cache/groupcache.go +++ /dev/null @@ -1,120 +0,0 @@ -package cache - -import ( - "context" - "encoding/json" - "net/url" - "strconv" - "time" - - "myapp/entity" - "myapp/sql" - - "github.com/mailgun/groupcache/v2" -) - -// Service that cache will use to retrieve data. -type Service interface { - RecordInfo() sql.Record - GetByID(ctx context.Context, dest interface{}, id int64) error - List(ctx context.Context, dest interface{}, opts sql.ListOptions) error -} - -// Cache is a simple structure which holds the groupcache and the database service, exposes -// `GetByID` and `List` which returns cached (or stores new) items. -type Cache struct { - service Service - maxAge time.Duration - group *groupcache.Group -} - -// Size default size to use on groupcache, defaults to 3MB. -var Size int64 = 3 << (10 * 3) - -// New returns a new cache service which exposes `GetByID` and `List` methods to work with. -// The "name" should be unique, "maxAge" for cache expiration. -func New(service Service, name string, maxAge time.Duration) *Cache { - c := new(Cache) - c.service = service - c.maxAge = maxAge - c.group = groupcache.NewGroup(name, Size, c) - return c -} - -const ( - prefixID = "#" - prefixList = "[" -) - -// Get implements the groupcache.Getter interface. -// Use `GetByID` and `List` instead. -func (c *Cache) Get(ctx context.Context, key string, dest groupcache.Sink) error { - if len(key) < 2 { // empty or missing prefix+key, should never happen. - return sql.ErrUnprocessable - } - - var v interface{} - - prefix := key[0:1] - key = key[1:] - switch prefix { - case prefixID: - // Get by ID. - id, err := strconv.ParseInt(key, 10, 64) - if err != nil || id <= 0 { - return err - } - - switch c.service.RecordInfo().(type) { - case *entity.Category: - v = new(entity.Category) - case *entity.Product: - v = new(entity.Product) - } - - err = c.service.GetByID(ctx, v, id) - if err != nil { - return err - } - - case prefixList: - // Get a set of records, list. - q, err := url.ParseQuery(key) - if err != nil { - return err - } - opts := sql.ParseListOptions(q) - - switch c.service.RecordInfo().(type) { - case *entity.Category: - v = new(entity.Categories) - case *entity.Product: - v = new(entity.Products) - } - - err = c.service.List(ctx, v, opts) - if err != nil { - return err - } - - default: - return sql.ErrUnprocessable - } - - b, err := json.Marshal(v) - if err != nil { - return err - } - - return dest.SetBytes(b, time.Now().Add(c.maxAge)) -} - -// GetByID binds an item to "dest" an item based on its "id". -func (c *Cache) GetByID(ctx context.Context, id string, dest *[]byte) error { - return c.group.Get(ctx, prefixID+id, groupcache.AllocatingByteSliceSink(dest)) -} - -// List binds item to "dest" based on the "rawQuery" of `url.Values` for `ListOptions`. -func (c *Cache) List(ctx context.Context, rawQuery string, dest *[]byte) error { - return c.group.Get(ctx, prefixList+rawQuery, groupcache.AllocatingByteSliceSink(dest)) -} diff --git a/_examples/database/mysql/docker-compose.yml b/_examples/database/mysql/docker-compose.yml deleted file mode 100644 index 715a20d4..00000000 --- a/_examples/database/mysql/docker-compose.yml +++ /dev/null @@ -1,32 +0,0 @@ -version: '3.1' - -services: - db: - image: mysql - command: --default-authentication-plugin=mysql_native_password - environment: - MYSQL_ROOT_PASSWORD: dbpassword - MYSQL_DATABASE: myapp - MYSQL_USER: user_myapp - MYSQL_PASSWORD: dbpassword - tty: true - volumes: - - ./migration:/docker-entrypoint-initdb.d - app: - build: . - ports: - - 8080:8080 - environment: - PORT: 8080 - MYSQL_USER: user_myapp - MYSQL_PASSWORD: dbpassword - MYSQL_DATABASE: myapp - MYSQL_HOST: db - restart: on-failure - healthcheck: - test: ["CMD", "curl", "-f", "tcp://db:3306"] - interval: 30s - timeout: 10s - retries: 5 - depends_on: - - db \ No newline at end of file diff --git a/_examples/database/mysql/entity/category.go b/_examples/database/mysql/entity/category.go deleted file mode 100644 index 61dae29f..00000000 --- a/_examples/database/mysql/entity/category.go +++ /dev/null @@ -1,89 +0,0 @@ -package entity - -import ( - "database/sql" - "time" -) - -// Category represents the categories entity. -// Each product belongs to a category, see `Product.CategoryID` field. -// It implements the `sql.Record` and `sql.Sorted` interfaces. -type Category struct { - ID int64 `db:"id" json:"id"` - Title string `db:"title" json:"title"` - Position uint64 `db:"position" json:"position"` - ImageURL string `db:"image_url" json:"image_url"` - - // We could use: sql.NullTime or unix time seconds (as int64), - // note that the dsn parameter "parseTime=true" is required now in order to fill this field correctly. - CreatedAt *time.Time `db:"created_at" json:"created_at"` - UpdatedAt *time.Time `db:"updated_at" json:"updated_at"` -} - -// TableName returns the database table name of a Category. -func (c *Category) TableName() string { - return "categories" -} - -// PrimaryKey returns the primary key of a Category. -func (c *Category) PrimaryKey() string { - return "id" -} - -// SortBy returns the column name that -// should be used as a fallback for sorting a set of Category. -func (c *Category) SortBy() string { - return "position" -} - -// Scan binds mysql rows to this Category. -func (c *Category) Scan(rows *sql.Rows) error { - c.CreatedAt = new(time.Time) - c.UpdatedAt = new(time.Time) - return rows.Scan(&c.ID, &c.Title, &c.Position, &c.ImageURL, &c.CreatedAt, &c.UpdatedAt) -} - -// Categories a list of categories. Implements the `Scannable` interface. -type Categories []*Category - -// Scan binds mysql rows to this Categories. -func (cs *Categories) Scan(rows *sql.Rows) (err error) { - cp := *cs - for rows.Next() { - c := new(Category) - if err = c.Scan(rows); err != nil { - return - } - cp = append(cp, c) - } - - if len(cp) == 0 { - return sql.ErrNoRows - } - - *cs = cp - - return rows.Err() -} - -/* -// The requests. -type ( - CreateCategoryRequest struct { - Title string `json:"title"` // all required. - Position uint64 `json:"position"` - ImageURL string `json:"imageURL"` - } - - UpdateCategoryRequest CreateCategoryRequest // at least 1 required. - - GetCategoryRequest struct { - ID int64 `json:"id"` // required. - } - - DeleteCategoryRequest GetCategoryRequest - - GetCategoriesRequest struct { - // [limit, offset...] - } -)*/ diff --git a/_examples/database/mysql/entity/product.go b/_examples/database/mysql/entity/product.go deleted file mode 100644 index bb352fba..00000000 --- a/_examples/database/mysql/entity/product.go +++ /dev/null @@ -1,95 +0,0 @@ -package entity - -import ( - "database/sql" - "time" -) - -// Product represents the products entity. -// It implements the `sql.Record` and `sql.Sorted` interfaces. -type Product struct { - ID int64 `db:"id" json:"id"` - CategoryID int64 `db:"category_id" json:"category_id"` - Title string `db:"title" json:"title"` - ImageURL string `db:"image_url" json:"image_url"` - Price float32 `db:"price" json:"price"` - Description string `db:"description" json:"description"` - CreatedAt *time.Time `db:"created_at" json:"created_at"` - UpdatedAt *time.Time `db:"updated_at" json:"updated_at"` -} - -// TableName returns the database table name of a Product. -func (p Product) TableName() string { - return "products" -} - -// PrimaryKey returns the primary key of a Product. -func (p *Product) PrimaryKey() string { - return "id" -} - -// SortBy returns the column name that -// should be used as a fallback for sorting a set of Product. -func (p *Product) SortBy() string { - return "updated_at" -} - -// ValidateInsert simple check for empty fields that should be required. -func (p *Product) ValidateInsert() bool { - return p.CategoryID > 0 && p.Title != "" && p.ImageURL != "" && p.Price > 0 /* decimal* */ && p.Description != "" -} - -// Scan binds mysql rows to this Product. -func (p *Product) Scan(rows *sql.Rows) error { - p.CreatedAt = new(time.Time) - p.UpdatedAt = new(time.Time) - return rows.Scan(&p.ID, &p.CategoryID, &p.Title, &p.ImageURL, &p.Price, &p.Description, &p.CreatedAt, &p.UpdatedAt) -} - -// Products is a list of products. Implements the `Scannable` interface. -type Products []*Product - -// Scan binds mysql rows to this Categories. -func (ps *Products) Scan(rows *sql.Rows) (err error) { - cp := *ps - for rows.Next() { - p := new(Product) - if err = p.Scan(rows); err != nil { - return - } - cp = append(cp, p) - } - - if len(cp) == 0 { - return sql.ErrNoRows - } - - *ps = cp - - return rows.Err() -} - -/* -// The requests. -type ( - CreateProductRequest struct { // all required. - CategoryID int64 `json:"categoryID"` - Title string `json:"title"` - ImageURL string `json:"imageURL"` - Price float32 `json:"price"` - Description string `json:"description"` - } - - UpdateProductRequest CreateProductRequest // at least 1 required. - - GetProductRequest struct { - ID int64 `json:"id"` // required. - } - - DeleteProductRequest GetProductRequest - - GetProductsRequest struct { - // [page, offset...] - } -) -*/ diff --git a/_examples/database/mysql/go.mod b/_examples/database/mysql/go.mod deleted file mode 100644 index 3e7d3e76..00000000 --- a/_examples/database/mysql/go.mod +++ /dev/null @@ -1,9 +0,0 @@ -module myapp - -go 1.15 - -require ( - github.com/go-sql-driver/mysql v1.5.0 - github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd - github.com/mailgun/groupcache/v2 v2.1.0 -) diff --git a/_examples/database/mysql/main.go b/_examples/database/mysql/main.go deleted file mode 100644 index f7169c5d..00000000 --- a/_examples/database/mysql/main.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "fmt" - "log" - "os" - - "myapp/api" - "myapp/sql" - - "github.com/kataras/iris/v12" -) - -func main() { - dsn := fmt.Sprintf("%s:%s@tcp(%s:3306)/%s?parseTime=true&charset=utf8mb4&collation=utf8mb4_unicode_ci", - getenv("MYSQL_USER", "user_myapp"), - getenv("MYSQL_PASSWORD", "dbpassword"), - getenv("MYSQL_HOST", "localhost"), - getenv("MYSQL_DATABASE", "myapp"), - ) - - db, err := sql.ConnectMySQL(dsn) - if err != nil { - log.Fatalf("error connecting to the MySQL database: %v", err) - } - - secret := getenv("JWT_SECRET", "EbnJO3bwmX") - - app := iris.New() - subRouter := api.Router(db, secret) - app.PartyFunc("/", subRouter) - - addr := fmt.Sprintf(":%s", getenv("PORT", "8080")) - app.Listen(addr) -} - -func getenv(key string, def string) string { - v := os.Getenv(key) - if v == "" { - return def - } - - return v -} diff --git a/_examples/database/mysql/migration/api_category/create_category.json b/_examples/database/mysql/migration/api_category/create_category.json deleted file mode 100644 index 3ea1efa5..00000000 --- a/_examples/database/mysql/migration/api_category/create_category.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "title": "computer-internet", - "position": 2, - "image_url": "https://bp.pstatic.gr/public/dist/images/1mOPxYtw1k.webp" -} \ No newline at end of file diff --git a/_examples/database/mysql/migration/api_category/insert_products_category.json b/_examples/database/mysql/migration/api_category/insert_products_category.json deleted file mode 100644 index 02051b7d..00000000 --- a/_examples/database/mysql/migration/api_category/insert_products_category.json +++ /dev/null @@ -1,31 +0,0 @@ -[{ - "title": "product-1", - "image_url": "https://images.product1.png", - "price": 42.42, - "description": "a description for product-1" -}, { - "title": "product-2", - "image_url": "https://images.product2.png", - "price": 32.1, - "description": "a description for product-2" -}, { - "title": "product-3", - "image_url": "https://images.product3.png", - "price": 52321321.32, - "description": "a description for product-3" -}, { - "title": "product-4", - "image_url": "https://images.product4.png", - "price": 77.4221, - "description": "a description for product-4" -}, { - "title": "product-5", - "image_url": "https://images.product5.png", - "price": 55.1, - "description": "a description for product-5" -}, { - "title": "product-6", - "image_url": "https://images.product6.png", - "price": 53.32, - "description": "a description for product-6" -}] \ No newline at end of file diff --git a/_examples/database/mysql/migration/api_category/update_category.json b/_examples/database/mysql/migration/api_category/update_category.json deleted file mode 100644 index a3ea1397..00000000 --- a/_examples/database/mysql/migration/api_category/update_category.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "id": 2, - "position": 1, - "title": "computers", - "image_url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Desktop_computer_clipart_-_Yellow_theme.svg/1200px-Desktop_computer_clipart_-_Yellow_theme.svg.png" -} \ No newline at end of file diff --git a/_examples/database/mysql/migration/api_category/update_partial_category.json b/_examples/database/mysql/migration/api_category/update_partial_category.json deleted file mode 100644 index 730c7166..00000000 --- a/_examples/database/mysql/migration/api_category/update_partial_category.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "computers-technology" -} \ No newline at end of file diff --git a/_examples/database/mysql/migration/api_postman.json b/_examples/database/mysql/migration/api_postman.json deleted file mode 100644 index 1ef1eba0..00000000 --- a/_examples/database/mysql/migration/api_postman.json +++ /dev/null @@ -1,484 +0,0 @@ -{ - "info": { - "_postman_id": "d3a2fdf6-9ebd-4e85-827d-385592a71fd6", - "name": "myapp (api-test)", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "Category", - "item": [ - { - "name": "Create", - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODk2MzkzNjd9.cYohwgUpe-Z7ac0LPpz4Adi5QXJmtwD1ZRpXrMUMPN0", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"title\": \"computer-internet\",\r\n \"position\": 1,\r\n \"image_url\": \"https://bp.pstatic.gr/public/dist/images/1mOPxYtw1k.webp\"\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8080/category", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "category" - ] - }, - "description": "Create a Category" - }, - "response": [] - }, - { - "name": "Get By ID", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://localhost:8080/category/1", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "category", - "1" - ] - }, - "description": "Get By ID" - }, - "response": [] - }, - { - "name": "List", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "http://localhost:8080/category?offset=0&limit=30&order=asc", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "category" - ], - "query": [ - { - "key": "offset", - "value": "0" - }, - { - "key": "limit", - "value": "30" - }, - { - "key": "order", - "value": "asc" - } - ] - }, - "description": "Get many with limit offset" - }, - "response": [] - }, - { - "name": "Update (Full)", - "request": { - "method": "PUT", - "header": [ - { - "key": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODk1ODU1NjN9.PtfDS1niGoZ7pV6kplI-_q1fVKLnknQ3IwcrLZhoVCU", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n\t\"id\": 1,\r\n\t\"position\": 3,\r\n \"title\": \"computers\",\r\n \"image_url\":\"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Desktop_computer_clipart_-_Yellow_theme.svg/1200px-Desktop_computer_clipart_-_Yellow_theme.svg.png\"\r\n}" - }, - "url": { - "raw": "http://localhost:8080/category", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "category" - ], - "query": [ - { - "key": "", - "value": null, - "disabled": true - } - ] - }, - "description": "Update a Category (full update)" - }, - "response": [] - }, - { - "name": "Delete By ID", - "request": { - "method": "DELETE", - "header": [ - { - "key": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODk1ODU1NjN9.PtfDS1niGoZ7pV6kplI-_q1fVKLnknQ3IwcrLZhoVCU", - "type": "text" - } - ], - "url": { - "raw": "http://localhost:8080/category/1", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "category", - "1" - ] - }, - "description": "Delete a Category" - }, - "response": [] - }, - { - "name": "Update (Partial)", - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODk1ODU1NjN9.PtfDS1niGoZ7pV6kplI-_q1fVKLnknQ3IwcrLZhoVCU", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"title\": \"computers-technology\"\r\n}" - }, - "url": { - "raw": "http://localhost:8080/category/1", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "category", - "3" - ] - }, - "description": "Update a Category partially, e.g. title only" - }, - "response": [] - }, - { - "name": "List Products", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://localhost:8080/category/1/products?offset=0&limit=30&by=price&order=asc", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "category", - "3", - "products" - ], - "query": [ - { - "key": "offset", - "value": "0" - }, - { - "key": "limit", - "value": "30" - }, - { - "key": "by", - "value": "price" - }, - { - "key": "order", - "value": "asc" - } - ] - }, - "description": "Get products from cheap to expensive" - }, - "response": [] - }, - { - "name": "Insert Products", - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODk1ODU1NjN9.PtfDS1niGoZ7pV6kplI-_q1fVKLnknQ3IwcrLZhoVCU", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "[{\r\n \"title\": \"product-1\",\r\n \"image_url\": \"https://images.product1.png\",\r\n \"price\": 42.42,\r\n \"description\": \"a description for product-1\"\r\n}, {\r\n \"title\": \"product-2\",\r\n \"image_url\": \"https://images.product2.png\",\r\n \"price\": 32.1,\r\n \"description\": \"a description for product-2\"\r\n}, {\r\n \"title\": \"product-3\",\r\n \"image_url\": \"https://images.product3.png\",\r\n \"price\": 52321321.32,\r\n \"description\": \"a description for product-3\"\r\n}, {\r\n \"title\": \"product-4\",\r\n \"image_url\": \"https://images.product4.png\",\r\n \"price\": 77.4221,\r\n \"description\": \"a description for product-4\"\r\n}, {\r\n \"title\": \"product-5\",\r\n \"image_url\": \"https://images.product5.png\",\r\n \"price\": 55.1,\r\n \"description\": \"a description for product-5\"\r\n}, {\r\n \"title\": \"product-6\",\r\n \"image_url\": \"https://images.product6.png\",\r\n \"price\": 53.32,\r\n \"description\": \"a description for product-6\"\r\n}]" - }, - "url": { - "raw": "http://localhost:8080/category/1/products", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "category", - "3", - "products" - ] - }, - "description": "Batch Insert Products to a Category" - }, - "response": [] - } - ], - "protocolProfileBehavior": {} - }, - { - "name": "Product", - "item": [ - { - "name": "List", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://localhost:8080/product?offset=0&limit=30&by=price&order=asc", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "product" - ], - "query": [ - { - "key": "offset", - "value": "0" - }, - { - "key": "limit", - "value": "30" - }, - { - "key": "by", - "value": "price" - }, - { - "key": "order", - "value": "asc" - } - ] - }, - "description": "List products" - }, - "response": [] - }, - { - "name": "Get By ID", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://localhost:8080/product/1", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "product", - "1" - ] - }, - "description": "Get a Product" - }, - "response": [] - }, - { - "name": "Delete By ID", - "request": { - "method": "DELETE", - "header": [ - { - "key": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODk1ODU1NjN9.PtfDS1niGoZ7pV6kplI-_q1fVKLnknQ3IwcrLZhoVCU", - "type": "text" - } - ], - "url": { - "raw": "http://localhost:8080/product/3", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "product", - "3" - ] - }, - "description": "Delete a Product" - }, - "response": [] - }, - { - "name": "Create", - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODk1ODU1NjN9.PtfDS1niGoZ7pV6kplI-_q1fVKLnknQ3IwcrLZhoVCU", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"title\": \"product-1\",\r\n \"category_id\": 1,\r\n \"image_url\": \"https://images.product1.png\",\r\n \"price\": 42.42,\r\n \"description\": \"a description for product-1\"\r\n}" - }, - "url": { - "raw": "http://localhost:8080/product", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "product" - ] - }, - "description": "Create a Product (and assign a category)" - }, - "response": [] - }, - { - "name": "Update (Full)", - "request": { - "method": "PUT", - "header": [ - { - "key": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODk1ODU1NjN9.PtfDS1niGoZ7pV6kplI-_q1fVKLnknQ3IwcrLZhoVCU", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n\t\"id\":19,\r\n \"title\": \"product-9-new\",\r\n \"category_id\": 1,\r\n \"image_url\": \"https://images.product19.png\",\r\n \"price\": 20,\r\n \"description\": \"a description for product-9-new\"\r\n}" - }, - "url": { - "raw": "http://localhost:8080/product", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "product" - ] - }, - "description": "Update a Product (full-update)" - }, - "response": [] - }, - { - "name": "Update (Partial)", - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODk1ODU1NjN9.PtfDS1niGoZ7pV6kplI-_q1fVKLnknQ3IwcrLZhoVCU", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"title\": \"product-9-new-title\"\r\n}" - }, - "url": { - "raw": "http://localhost:8080/product/9", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "product", - "9" - ] - }, - "description": "Update a Product (partially)" - }, - "response": [] - } - ], - "description": "Product Client API", - "protocolProfileBehavior": {} - }, - { - "name": "Get Token", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://localhost:8080/token", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "token" - ] - }, - "description": "Get Token to access \"write\" (create, update and delete) endpoints" - }, - "response": [] - } - ], - "protocolProfileBehavior": {} -} \ No newline at end of file diff --git a/_examples/database/mysql/migration/api_product/create_product.json b/_examples/database/mysql/migration/api_product/create_product.json deleted file mode 100644 index 46b6a5c8..00000000 --- a/_examples/database/mysql/migration/api_product/create_product.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "title": "product-1", - "category_id": 3, - "image_url": "https://images.product1.png", - "price": 42.42, - "description": "a description for product-1" -} \ No newline at end of file diff --git a/_examples/database/mysql/migration/api_product/update_partial_product.json b/_examples/database/mysql/migration/api_product/update_partial_product.json deleted file mode 100644 index 71413c13..00000000 --- a/_examples/database/mysql/migration/api_product/update_partial_product.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "product-19-new-title" -} \ No newline at end of file diff --git a/_examples/database/mysql/migration/api_product/update_product.json b/_examples/database/mysql/migration/api_product/update_product.json deleted file mode 100644 index d8e52662..00000000 --- a/_examples/database/mysql/migration/api_product/update_product.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "id":19, - "title": "product-19", - "category_id": 3, - "image_url": "https://images.product19.png", - "price": 20, - "description": "a description for product-19" -} \ No newline at end of file diff --git a/_examples/database/mysql/migration/db.sql b/_examples/database/mysql/migration/db.sql deleted file mode 100644 index eab35314..00000000 --- a/_examples/database/mysql/migration/db.sql +++ /dev/null @@ -1,33 +0,0 @@ -CREATE DATABASE IF NOT EXISTS myapp DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - -USE myapp; - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - -DROP TABLE IF EXISTS categories; -CREATE TABLE categories ( - id int(11) NOT NULL AUTO_INCREMENT, - title varchar(255) NOT NULL, - position int(11) NOT NULL, - image_url varchar(255) NOT NULL, - created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (id) -); - -DROP TABLE IF EXISTS products; -CREATE TABLE products ( - id int(11) NOT NULL AUTO_INCREMENT, - category_id int, - title varchar(255) NOT NULL, - image_url varchar(255) NOT NULL, - price decimal(10,2) NOT NULL, - description text NOT NULL, - created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (id), - FOREIGN KEY (category_id) REFERENCES categories(id) -); - -SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file diff --git a/_examples/database/mysql/service/category_service.go b/_examples/database/mysql/service/category_service.go deleted file mode 100644 index 2a151d83..00000000 --- a/_examples/database/mysql/service/category_service.go +++ /dev/null @@ -1,74 +0,0 @@ -package service - -import ( - "context" - "fmt" - "reflect" - - "myapp/entity" - "myapp/sql" -) - -// CategoryService represents the category entity service. -// Note that the given entity (request) should be already validated -// before service's calls. -type CategoryService struct { - *sql.Service -} - -// NewCategoryService returns a new category service to communicate with the database. -func NewCategoryService(db sql.Database) *CategoryService { - return &CategoryService{Service: sql.NewService(db, new(entity.Category))} -} - -// Insert stores a category to the database and returns its ID. -func (s *CategoryService) Insert(ctx context.Context, e entity.Category) (int64, error) { - if e.Title == "" || e.ImageURL == "" { - return 0, sql.ErrUnprocessable - } - - q := fmt.Sprintf(`INSERT INTO %s (title, position, image_url) - VALUES (?,?,?);`, e.TableName()) - - res, err := s.DB().Exec(ctx, q, e.Title, e.Position, e.ImageURL) - if err != nil { - return 0, err - } - - return res.LastInsertId() -} - -// Update updates a category based on its `ID`. -func (s *CategoryService) Update(ctx context.Context, e entity.Category) (int, error) { - if e.ID == 0 || e.Title == "" || e.ImageURL == "" { - return 0, sql.ErrUnprocessable - } - - q := fmt.Sprintf(`UPDATE %s - SET - title = ?, - position = ?, - image_url = ? - WHERE %s = ?;`, e.TableName(), e.PrimaryKey()) - - res, err := s.DB().Exec(ctx, q, e.Title, e.Position, e.ImageURL, e.ID) - if err != nil { - return 0, err - } - - n := sql.GetAffectedRows(res) - return n, nil -} - -// The updatable fields, separately from that we create for any possible future necessities. -var categoryUpdateSchema = map[string]reflect.Kind{ - "title": reflect.String, - "image_url": reflect.String, - "position": reflect.Int, -} - -// PartialUpdate accepts a key-value map to -// update the record based on the given "id". -func (s *CategoryService) PartialUpdate(ctx context.Context, id int64, attrs map[string]interface{}) (int, error) { - return s.Service.PartialUpdate(ctx, id, categoryUpdateSchema, attrs) -} diff --git a/_examples/database/mysql/service/category_service_test.go b/_examples/database/mysql/service/category_service_test.go deleted file mode 100644 index 24c6ef86..00000000 --- a/_examples/database/mysql/service/category_service_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package service - -import ( - "context" - "testing" - - "myapp/entity" - "myapp/sql" - - "github.com/DATA-DOG/go-sqlmock" -) - -func TestCategoryServiceInsert(t *testing.T) { - conn, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) - if err != nil { - t.Fatal(err) - } - defer conn.Close() - - db := &sql.MySQL{Conn: conn} - service := NewCategoryService(db) - newCategory := entity.Category{ - Title: "computer-internet", - Position: 2, - ImageURL: "https://animage", - } - mock.ExpectExec("INSERT INTO categories (title, position, image_url) VALUES (?,?,?);"). - WithArgs(newCategory.Title, newCategory.Position, newCategory.ImageURL).WillReturnResult(sqlmock.NewResult(1, 1)) - - id, err := service.Insert(context.TODO(), newCategory) - if err != nil { - t.Fatal(err) - } - - if id != 1 { - t.Fatalf("expected ID to be 1 as this is the first entry") - } - - if err = mock.ExpectationsWereMet(); err != nil { - t.Fatal(err) - } -} diff --git a/_examples/database/mysql/service/product_service.go b/_examples/database/mysql/service/product_service.go deleted file mode 100644 index 15d7bfdc..00000000 --- a/_examples/database/mysql/service/product_service.go +++ /dev/null @@ -1,110 +0,0 @@ -package service - -import ( - "context" - "fmt" - "reflect" - "strings" - - "myapp/entity" - "myapp/sql" -) - -// ProductService represents the product entity service. -// Note that the given entity (request) should be already validated -// before service's calls. -type ProductService struct { - *sql.Service - rec sql.Record -} - -// NewProductService returns a new product service to communicate with the database. -func NewProductService(db sql.Database) *ProductService { - return &ProductService{Service: sql.NewService(db, new(entity.Product))} -} - -// Insert stores a product to the database and returns its ID. -func (s *ProductService) Insert(ctx context.Context, e entity.Product) (int64, error) { - if !e.ValidateInsert() { - return 0, sql.ErrUnprocessable - } - - q := fmt.Sprintf(`INSERT INTO %s (category_id, title, image_url, price, description) - VALUES (?,?,?,?,?);`, e.TableName()) - - res, err := s.DB().Exec(ctx, q, e.CategoryID, e.Title, e.ImageURL, e.Price, e.Description) - if err != nil { - return 0, err - } - - return res.LastInsertId() -} - -// BatchInsert inserts one or more products at once and returns the total length created. -func (s *ProductService) BatchInsert(ctx context.Context, products []entity.Product) (int, error) { - if len(products) == 0 { - return 0, nil - } - - var ( - valuesLines []string - args []interface{} - ) - - for _, p := range products { - if !p.ValidateInsert() { - // all products should be "valid", we don't skip, we cancel. - return 0, sql.ErrUnprocessable - } - - valuesLines = append(valuesLines, "(?,?,?,?,?)") - args = append(args, []interface{}{p.CategoryID, p.Title, p.ImageURL, p.Price, p.Description}...) - } - - q := fmt.Sprintf("INSERT INTO %s (category_id, title, image_url, price, description) VALUES %s;", - s.RecordInfo().TableName(), - strings.Join(valuesLines, ", ")) - - res, err := s.DB().Exec(ctx, q, args...) - if err != nil { - return 0, err - } - - n := sql.GetAffectedRows(res) - return n, nil -} - -// Update updates a product based on its `ID` from the database -// and returns the affected numbrer (0 when nothing changed otherwise 1). -func (s *ProductService) Update(ctx context.Context, e entity.Product) (int, error) { - q := fmt.Sprintf(`UPDATE %s - SET - category_id = ?, - title = ?, - image_url = ?, - price = ?, - description = ? - WHERE %s = ?;`, e.TableName(), e.PrimaryKey()) - - res, err := s.DB().Exec(ctx, q, e.CategoryID, e.Title, e.ImageURL, e.Price, e.Description, e.ID) - if err != nil { - return 0, err - } - - n := sql.GetAffectedRows(res) - return n, nil -} - -var productUpdateSchema = map[string]reflect.Kind{ - "category_id": reflect.Int, - "title": reflect.String, - "image_url": reflect.String, - "price": reflect.Float32, - "description": reflect.String, -} - -// PartialUpdate accepts a key-value map to -// update the record based on the given "id". -func (s *ProductService) PartialUpdate(ctx context.Context, id int64, attrs map[string]interface{}) (int, error) { - return s.Service.PartialUpdate(ctx, id, productUpdateSchema, attrs) -} diff --git a/_examples/database/mysql/sql/mysql.go b/_examples/database/mysql/sql/mysql.go deleted file mode 100644 index 9d93b5cd..00000000 --- a/_examples/database/mysql/sql/mysql.go +++ /dev/null @@ -1,123 +0,0 @@ -package sql - -import ( - "context" - "database/sql" - "fmt" - - _ "github.com/go-sql-driver/mysql" // lint: mysql driver. -) - -// MySQL holds the underline connection of a MySQL (or MariaDB) database. -// See the `ConnectMySQL` package-level function. -type MySQL struct { - Conn *sql.DB -} - -var _ Database = (*MySQL)(nil) - -var ( - // DefaultCharset default charset parameter for new databases. - DefaultCharset = "utf8mb4" - // DefaultCollation default collation parameter for new databases. - DefaultCollation = "utf8mb4_unicode_ci" -) - -// ConnectMySQL returns a new ready to use MySQL Database instance. -// Accepts a single argument of "dsn", i.e: -// username:password@tcp(localhost:3306)/myapp?parseTime=true&charset=utf8mb4&collation=utf8mb4_unicode_ci -func ConnectMySQL(dsn string) (*MySQL, error) { - conn, err := sql.Open("mysql", dsn) - if err != nil { - return nil, err - } - err = conn.Ping() - if err != nil { - conn.Close() - return nil, err - } - - return &MySQL{ - Conn: conn, - }, nil -} - -// CreateDatabase executes the CREATE DATABASE query. -func (db *MySQL) CreateDatabase(database string) error { - q := fmt.Sprintf("CREATE DATABASE %s DEFAULT CHARSET = %s COLLATE = %s;", database, DefaultCharset, DefaultCollation) - _, err := db.Conn.Exec(q) - return err -} - -// Drop executes the DROP DATABASE query. -func (db *MySQL) Drop(database string) error { - q := fmt.Sprintf("DROP DATABASE %s;", database) - _, err := db.Conn.Exec(q) - return err -} - -// Select performs the SELECT query for this database (dsn database name is required). -func (db *MySQL) Select(ctx context.Context, dest interface{}, query string, args ...interface{}) error { - rows, err := db.Conn.QueryContext(ctx, query, args...) - if err != nil { - return err - } - defer rows.Close() - - if scannable, ok := dest.(Scannable); ok { - return scannable.Scan(rows) - } - - if !rows.Next() { - return ErrNoRows - } - return rows.Scan(dest) - - /* Uncomment this and pass a slice if u want to see reflection powers <3 - v, ok := dest.(reflect.Value) - if !ok { - v = reflect.Indirect(reflect.ValueOf(dest)) - } - - sliceTyp := v.Type() - - if sliceTyp.Kind() != reflect.Slice { - sliceTyp = reflect.SliceOf(sliceTyp) - } - - sliceElementTyp := deref(sliceTyp.Elem()) - for rows.Next() { - obj := reflect.New(sliceElementTyp) - obj.Interface().(Scannable).Scan(rows) - if err != nil { - return err - } - - v.Set(reflect.Append(v, reflect.Indirect(obj))) - } - */ -} - -// Get same as `Select` but it moves the cursor to the first result. -func (db *MySQL) Get(ctx context.Context, dest interface{}, query string, args ...interface{}) error { - rows, err := db.Conn.QueryContext(ctx, query, args...) - if err != nil { - return err - } - defer rows.Close() - if !rows.Next() { - return ErrNoRows - } - - if scannable, ok := dest.(Scannable); ok { - return scannable.Scan(rows) - } - - return rows.Scan(dest) -} - -// Exec executes a query. It does not return any rows. -// Use the first output parameter to count the affected rows on UPDATE, INSERT, or DELETE. -func (db *MySQL) Exec(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { - return db.Conn.ExecContext(ctx, query, args...) -} diff --git a/_examples/database/mysql/sql/service.go b/_examples/database/mysql/sql/service.go deleted file mode 100644 index 153a2e6b..00000000 --- a/_examples/database/mysql/sql/service.go +++ /dev/null @@ -1,243 +0,0 @@ -package sql - -import ( - "context" - "database/sql" - "errors" - "fmt" - "net/url" - "reflect" - "strconv" - "strings" -) - -// Service holder for common queries. -// Note: each entity service keeps its own base Service instance. -type Service struct { - db Database - rec Record // see `Count`, `List` and `DeleteByID` methods. -} - -// NewService returns a new (SQL) base service for common operations. -func NewService(db Database, of Record) *Service { - return &Service{db: db, rec: of} -} - -// DB exposes the database instance. -func (s *Service) DB() Database { - return s.db -} - -// RecordInfo returns the record info provided through `NewService`. -func (s *Service) RecordInfo() Record { - return s.rec -} - -// ErrNoRows is returned when GET doesn't return a row. -// A shortcut of sql.ErrNoRows. -var ErrNoRows = sql.ErrNoRows - -// GetByID binds a single record from the databases to the "dest". -func (s *Service) GetByID(ctx context.Context, dest interface{}, id int64) error { - q := fmt.Sprintf("SELECT * FROM %s WHERE %s = ? LIMIT 1", s.rec.TableName(), s.rec.PrimaryKey()) - err := s.db.Get(ctx, dest, q, id) - return err - // if err != nil { - // if err == sql.ErrNoRows { - // return false, nil - // } - - // return false, err - // } - - // return true, nil -} - -// Count returns the total records count in the table. -func (s *Service) Count(ctx context.Context) (total int64, err error) { - q := fmt.Sprintf("SELECT COUNT(DISTINCT %s) FROM %s", s.rec.PrimaryKey(), s.rec.TableName()) - if err = s.db.Select(ctx, &total, q); err == sql.ErrNoRows { - err = nil - } - return -} - -// ListOptions holds the options to be passed on the `Service.List` method. -type ListOptions struct { - Table string // the table name. - Offset uint64 // inclusive. - Limit uint64 - OrderByColumn string - Order string // "ASC" or "DESC" (could be a bool type instead). - WhereColumn string - WhereValue interface{} -} - -// Where accepts a column name and column value to set -// on the WHERE clause of the result query. -// It returns a new `ListOptions` value. -// Note that this is a basic implementation which just takes care our current needs. -func (opt ListOptions) Where(colName string, colValue interface{}) ListOptions { - opt.WhereColumn = colName - opt.WhereValue = colValue - return opt -} - -// BuildQuery returns the query and the arguments that -// should be form a SELECT command. -func (opt ListOptions) BuildQuery() (q string, args []interface{}) { - q = fmt.Sprintf("SELECT * FROM %s", opt.Table) - - if opt.WhereColumn != "" && opt.WhereValue != nil { - q += fmt.Sprintf(" WHERE %s = ?", opt.WhereColumn) - args = append(args, opt.WhereValue) - } - - if opt.OrderByColumn != "" { - q += fmt.Sprintf(" ORDER BY %s %s", opt.OrderByColumn, ParseOrder(opt.Order)) - } - - if opt.Limit > 0 { - q += fmt.Sprintf(" LIMIT %d", opt.Limit) // offset below. - } - - if opt.Offset > 0 { - q += fmt.Sprintf(" OFFSET %d", opt.Offset) - } - - return -} - -// const defaultLimit = 30 // default limit if not set. - -// ParseListOptions returns a `ListOptions` from a map[string][]string. -func ParseListOptions(q url.Values) ListOptions { - offset, _ := strconv.ParseUint(q.Get("offset"), 10, 64) - limit, _ := strconv.ParseUint(q.Get("limit"), 10, 64) - order := q.Get("order") // empty, asc(...) or desc(...). - orderBy := q.Get("by") // e.g. price - - return ListOptions{Offset: offset, Limit: limit, Order: order, OrderByColumn: orderBy} -} - -// List binds one or more records from the database to the "dest". -// If the record supports ordering then it will sort by the `Sorted.OrderBy` column name(s). -// Use the "order" input parameter to set a descending order ("DESC"). -func (s *Service) List(ctx context.Context, dest interface{}, opts ListOptions) error { - // Set table and order by column from record info for `List` by options - // so it can be more flexible to perform read-only calls of other table's too. - if opts.Table == "" { - // If missing then try to set it by record info. - opts.Table = s.rec.TableName() - } - if opts.OrderByColumn == "" { - if b, ok := s.rec.(Sorted); ok { - opts.OrderByColumn = b.SortBy() - } - } - - q, args := opts.BuildQuery() - return s.db.Select(ctx, dest, q, args...) -} - -// DeleteByID removes a single record of "dest" from the database. -func (s *Service) DeleteByID(ctx context.Context, id int64) (int, error) { - q := fmt.Sprintf("DELETE FROM %s WHERE %s = ? LIMIT 1", s.rec.TableName(), s.rec.PrimaryKey()) - res, err := s.db.Exec(ctx, q, id) - if err != nil { - return 0, err - } - - return GetAffectedRows(res), nil -} - -// ErrUnprocessable indicates error caused by invalid entity (entity's key-values). -// The syntax of the request entity is correct, but it was unable to process the contained instructions -// e.g. empty or unsupported value. -// -// See `../service/XService.Insert` and `../service/XService.Update` -// and `PartialUpdate`. -var ErrUnprocessable = errors.New("invalid entity") - -// PartialUpdate accepts a columns schema and a key-value map to -// update the record based on the given "id". -// Note: Trivial string, int and boolean type validations are performed here. -func (s *Service) PartialUpdate(ctx context.Context, id int64, schema map[string]reflect.Kind, attrs map[string]interface{}) (int, error) { - if len(schema) == 0 || len(attrs) == 0 { - return 0, nil - } - - var ( - keyLines []string - values []interface{} - ) - - for key, kind := range schema { - v, ok := attrs[key] - if !ok { - continue - } - - switch v.(type) { - case string: - if kind != reflect.String { - return 0, ErrUnprocessable - } - case int: - if kind != reflect.Int { - return 0, ErrUnprocessable - } - case bool: - if kind != reflect.Bool { - return 0, ErrUnprocessable - } - } - - keyLines = append(keyLines, fmt.Sprintf("%s = ?", key)) - values = append(values, v) - } - - if len(values) == 0 { - return 0, nil - } - - q := fmt.Sprintf("UPDATE %s SET %s WHERE %s = ?;", - s.rec.TableName(), strings.Join(keyLines, ", "), s.rec.PrimaryKey()) - - res, err := s.DB().Exec(ctx, q, append(values, id)...) - if err != nil { - return 0, err - } - - n := GetAffectedRows(res) - return n, nil -} - -// GetAffectedRows returns the number of affected rows after -// a DELETE or UPDATE operation. -func GetAffectedRows(result sql.Result) int { - if result == nil { - return 0 - } - - n, _ := result.RowsAffected() - return int(n) -} - -const ( - ascending = "ASC" - descending = "DESC" -) - -// ParseOrder accept an order string and returns a valid mysql ORDER clause. -// Defaults to "ASC". Two possible outputs: "ASC" and "DESC". -func ParseOrder(order string) string { - order = strings.TrimSpace(order) - if len(order) >= 4 { - if strings.HasPrefix(strings.ToUpper(order), descending) { - return descending - } - } - - return ascending -} diff --git a/_examples/database/mysql/sql/sql.go b/_examples/database/mysql/sql/sql.go deleted file mode 100644 index 4ac6ec9c..00000000 --- a/_examples/database/mysql/sql/sql.go +++ /dev/null @@ -1,40 +0,0 @@ -package sql - -import ( - "context" - "database/sql" -) - -// Database is an interface which a database(sql) should implement. -type Database interface { - Get(ctx context.Context, dest interface{}, q string, args ...interface{}) error - Select(ctx context.Context, dest interface{}, q string, args ...interface{}) error - Exec(ctx context.Context, q string, args ...interface{}) (sql.Result, error) -} - -// Record should represent a database record. -// It holds the table name and the primary key. -// Entities should implement that -// in order to use the BaseService's methods. -type Record interface { - TableName() string // the table name which record belongs to. - PrimaryKey() string // the primary key of the record. -} - -// Sorted should represent a set of database records -// that should be rendered with order. -// -// It does NOT support the form of -// column1 ASC, -// column2 DESC -// The OrderBy method should return text in form of: -// column1 -// or column1, column2 -type Sorted interface { - SortBy() string // column names separated by comma. -} - -// Scannable for go structs to bind their fields. -type Scannable interface { - Scan(*sql.Rows) error -} diff --git a/_examples/database/orm/gorm/REAMDE.md b/_examples/database/orm/gorm/REAMDE.md deleted file mode 100644 index 7e684d63..00000000 --- a/_examples/database/orm/gorm/REAMDE.md +++ /dev/null @@ -1,5 +0,0 @@ -# GORM - -This example is pull by [#1275 PR](https://github.com/kataras/iris/pull/1275) by [@wuxiaoxiaoshen](https://github.com/wuxiaoxiaoshen). - -A more complete and real-world example can be found at the project created by [@snowlyg](https://github.com/snowlyg). diff --git a/_examples/database/orm/gorm/main.go b/_examples/database/orm/gorm/main.go deleted file mode 100644 index 00a10b3c..00000000 --- a/_examples/database/orm/gorm/main.go +++ /dev/null @@ -1,177 +0,0 @@ -package main - -import ( - "net/http" - "os" - "time" - - "github.com/jinzhu/gorm" - "github.com/kataras/iris/v12" - _ "github.com/mattn/go-sqlite3" -) - -type User struct { - gorm.Model - Salt string `gorm:"type:varchar(255)" json:"salt"` - Username string `gorm:"type:varchar(32)" json:"username"` - Password string `gorm:"type:varchar(200);column:password" json:"-"` - Languages string `gorm:"type:varchar(200);column:languages" json:"languages"` -} - -func (u User) TableName() string { - return "gorm_user" -} - -type UserSerializer struct { - ID uint `json:"id"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - Salt string `json:"salt"` - UserName string `json:"user_name"` - Password string `json:"-"` - Languages string `json:"languages"` -} - -func (self User) Serializer() UserSerializer { - return UserSerializer{ - ID: self.ID, - CreatedAt: self.CreatedAt.Truncate(time.Second), - UpdatedAt: self.UpdatedAt.Truncate(time.Second), - Salt: self.Salt, - Password: self.Password, - Languages: self.Languages, - UserName: self.Username, - } -} - -func main() { - app := iris.Default() - db, err := gorm.Open("sqlite3", "test.db") - db.LogMode(true) // show SQL logger - if err != nil { - app.Logger().Fatalf("connect to sqlite3 failed") - return - } - iris.RegisterOnInterrupt(func() { - defer db.Close() - }) - - if os.Getenv("ENV") != "" { - db.DropTableIfExists(&User{}) // drop table - } - db.AutoMigrate(&User{}) // create table: // AutoMigrate run auto migration for given models, will only add missing fields, won't delete/change current data - - app.Post("/post_user", func(ctx iris.Context) { - var user User - user = User{ - Username: "gorm", - Salt: "hash---", - Password: "admin", - Languages: "gorm", - } - if err := db.FirstOrCreate(&user); err == nil { - app.Logger().Fatalf("created one record failed: %s", err.Error) - ctx.JSON(iris.Map{ - "code": http.StatusBadRequest, - "error": err.Error, - }) - return - } - ctx.JSON( - iris.Map{ - "code": http.StatusOK, - "data": user.Serializer(), - }) - }) - - app.Get("/get_user/{id:uint}", func(ctx iris.Context) { - var user User - id, _ := ctx.Params().GetUint("id") - app.Logger().Println(id) - if err := db.Where("id = ?", int(id)).First(&user).Error; err != nil { - app.Logger().Fatalf("find one record failed: %t", err == nil) - ctx.JSON(iris.Map{ - "code": http.StatusBadRequest, - "error": err.Error, - }) - return - } - ctx.JSON(iris.Map{ - "code": http.StatusOK, - "data": user.Serializer(), - }) - }) - - app.Delete("/delete_user/{id:uint}", func(ctx iris.Context) { - id, _ := ctx.Params().GetUint("id") - if id == 0 { - ctx.JSON(iris.Map{ - "code": http.StatusOK, - "detail": "query param id should not be nil", - }) - return - } - var user User - if err := db.Where("id = ?", id).First(&user).Error; err != nil { - app.Logger().Fatalf("record not found") - ctx.JSON(iris.Map{ - "code": http.StatusOK, - "detail": err.Error, - }) - return - } - db.Delete(&user) - ctx.JSON(iris.Map{ - "code": http.StatusOK, - "data": user.Serializer(), - }) - }) - - app.Patch("/patch_user/{id:uint}", func(ctx iris.Context) { - id, _ := ctx.Params().GetUint("id") - if id == 0 { - ctx.JSON(iris.Map{ - "code": http.StatusOK, - "detail": "query param id should not be nil", - }) - return - } - var user User - tx := db.Begin() - if err := tx.Where("id = ?", id).First(&user).Error; err != nil { - app.Logger().Fatalf("record not found") - ctx.JSON(iris.Map{ - "code": http.StatusOK, - "detail": err.Error, - }) - return - } - - var body patchParam - ctx.ReadJSON(&body) - app.Logger().Println(body) - if err := tx.Model(&user).Updates(map[string]interface{}{"username": body.Data.UserName, "password": body.Data.Password}).Error; err != nil { - app.Logger().Fatalf("update record failed") - tx.Rollback() - ctx.JSON(iris.Map{ - "code": http.StatusBadRequest, - "error": err.Error, - }) - return - } - tx.Commit() - ctx.JSON(iris.Map{ - "code": http.StatusOK, - "data": user.Serializer(), - }) - }) - - app.Listen(":8080") -} - -type patchParam struct { - Data struct { - UserName string `json:"user_name" form:"user_name"` - Password string `json:"password" form:"password"` - } `json:"data"` -} diff --git a/_examples/database/orm/reform/controllers/person_controller.go b/_examples/database/orm/reform/controllers/person_controller.go deleted file mode 100644 index 97f9dbb6..00000000 --- a/_examples/database/orm/reform/controllers/person_controller.go +++ /dev/null @@ -1,47 +0,0 @@ -package controllers - -import ( - "net" - "time" - - "myapp/models" - - "github.com/kataras/golog" - "gopkg.in/reform.v1" -) - -// PersonController is the model.Person's web controller. -type PersonController struct { - DB *reform.DB - - // Logger and IP fields are automatically binded by the framework. - Logger *golog.Logger // binds to the application's logger. - IP net.IP // binds to the client's IP. -} - -// Get handles -// GET /persons -func (c *PersonController) Get() ([]reform.Struct, error) { - return c.DB.SelectAllFrom(models.PersonTable, "") -} - -// GetBy handles -// GET /persons/{ID} -func (c *PersonController) GetBy(id int32) (reform.Record, error) { - return c.DB.FindByPrimaryKeyFrom(models.PersonTable, id) -} - -// Post handles -// POST /persons with JSON request body of model.Person. -func (c *PersonController) Post(p *models.Person) int { - p.CreatedAt = time.Now() - - if err := c.DB.Save(p); err != nil { - c.Logger.Errorf("[%s] create person: %v", c.IP.String(), err) - return 500 // iris.StatusInternalServerError - } - - c.Logger.Debugf("[%s] create person [%s] succeed", c.IP.String(), p.Name) - - return 201 // iris.StatusCreated -} diff --git a/_examples/database/orm/reform/go.mod b/_examples/database/orm/reform/go.mod deleted file mode 100644 index 039ec25a..00000000 --- a/_examples/database/orm/reform/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module myapp - -go 1.15 - -require ( - github.com/kataras/iris/v12 v12.1.8 - github.com/mattn/go-sqlite3 v1.14.0 - gopkg.in/reform.v1 v1.4.0 -) - -replace github.com/kataras/iris/v12 => ../../../../ diff --git a/_examples/database/orm/reform/main.go b/_examples/database/orm/reform/main.go deleted file mode 100644 index 9be385b4..00000000 --- a/_examples/database/orm/reform/main.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -/* -$ go get gopkg.in/reform.v1/reform -$ go generate ./models -$ go run . - -Read more at: https://github.com/go-reform/reform -*/ - -import ( - "database/sql" - - "myapp/controllers" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/mvc" - - _ "github.com/mattn/go-sqlite3" - "gopkg.in/reform.v1" - "gopkg.in/reform.v1/dialects/sqlite3" -) - -func main() { - app := iris.New() - app.Logger().SetLevel("debug") - - sqlDB, err := sql.Open("sqlite3", "./myapp.db") - if err != nil { - panic(err) - } - defer sqlDB.Close() - sqlStmt := ` - drop table people; - create table people (id integer not null primary key, name text, email text, created_at datetime not null, updated_at datetime null); - delete from people; - ` - _, err = sqlDB.Exec(sqlStmt) - if err != nil { - panic(err) - } - - db := reform.NewDB(sqlDB, sqlite3.Dialect, reform.NewPrintfLogger(app.Logger().Debugf)) - - mvcApp := mvc.New(app.Party("/persons")) - mvcApp.Register(db) - mvcApp.Handle(new(controllers.PersonController)) - - app.Listen(":8080") -} diff --git a/_examples/database/orm/reform/models/person.go b/_examples/database/orm/reform/models/person.go deleted file mode 100644 index 6b852748..00000000 --- a/_examples/database/orm/reform/models/person.go +++ /dev/null @@ -1,13 +0,0 @@ -//go:generate reform -package models - -import "time" - -//reform:people -type Person struct { - ID int32 `reform:"id,pk" json:"id"` - Name string `reform:"name" json:"name"` - Email *string `reform:"email" json:"email"` - CreatedAt time.Time `reform:"created_at" json:"created_at"` - UpdatedAt *time.Time `reform:"updated_at" json:"updated_at"` -} diff --git a/_examples/database/orm/reform/models/person_reform.go b/_examples/database/orm/reform/models/person_reform.go deleted file mode 100644 index 537d2b5d..00000000 --- a/_examples/database/orm/reform/models/person_reform.go +++ /dev/null @@ -1,136 +0,0 @@ -// Code generated by gopkg.in/reform.v1. DO NOT EDIT. - -package models - -import ( - "fmt" - "strings" - - "gopkg.in/reform.v1" - "gopkg.in/reform.v1/parse" -) - -type personTableType struct { - s parse.StructInfo - z []interface{} -} - -// Schema returns a schema name in SQL database (""). -func (v *personTableType) Schema() string { - return v.s.SQLSchema -} - -// Name returns a view or table name in SQL database ("people"). -func (v *personTableType) Name() string { - return v.s.SQLName -} - -// Columns returns a new slice of column names for that view or table in SQL database. -func (v *personTableType) Columns() []string { - return []string{"id", "name", "email", "created_at", "updated_at"} -} - -// NewStruct makes a new struct for that view or table. -func (v *personTableType) NewStruct() reform.Struct { - return new(Person) -} - -// NewRecord makes a new record for that table. -func (v *personTableType) NewRecord() reform.Record { - return new(Person) -} - -// PKColumnIndex returns an index of primary key column for that table in SQL database. -func (v *personTableType) PKColumnIndex() uint { - return uint(v.s.PKFieldIndex) -} - -// PersonTable represents people view or table in SQL database. -var PersonTable = &personTableType{ - s: parse.StructInfo{Type: "Person", SQLSchema: "", SQLName: "people", Fields: []parse.FieldInfo{{Name: "ID", Type: "int32", Column: "id"}, {Name: "Name", Type: "string", Column: "name"}, {Name: "Email", Type: "*string", Column: "email"}, {Name: "CreatedAt", Type: "time.Time", Column: "created_at"}, {Name: "UpdatedAt", Type: "*time.Time", Column: "updated_at"}}, PKFieldIndex: 0}, - z: new(Person).Values(), -} - -// String returns a string representation of this struct or record. -func (s Person) String() string { - res := make([]string, 5) - res[0] = "ID: " + reform.Inspect(s.ID, true) - res[1] = "Name: " + reform.Inspect(s.Name, true) - res[2] = "Email: " + reform.Inspect(s.Email, true) - res[3] = "CreatedAt: " + reform.Inspect(s.CreatedAt, true) - res[4] = "UpdatedAt: " + reform.Inspect(s.UpdatedAt, true) - return strings.Join(res, ", ") -} - -// Values returns a slice of struct or record field values. -// Returned interface{} values are never untyped nils. -func (s *Person) Values() []interface{} { - return []interface{}{ - s.ID, - s.Name, - s.Email, - s.CreatedAt, - s.UpdatedAt, - } -} - -// Pointers returns a slice of pointers to struct or record fields. -// Returned interface{} values are never untyped nils. -func (s *Person) Pointers() []interface{} { - return []interface{}{ - &s.ID, - &s.Name, - &s.Email, - &s.CreatedAt, - &s.UpdatedAt, - } -} - -// View returns View object for that struct. -func (s *Person) View() reform.View { - return PersonTable -} - -// Table returns Table object for that record. -func (s *Person) Table() reform.Table { - return PersonTable -} - -// PKValue returns a value of primary key for that record. -// Returned interface{} value is never untyped nil. -func (s *Person) PKValue() interface{} { - return s.ID -} - -// PKPointer returns a pointer to primary key field for that record. -// Returned interface{} value is never untyped nil. -func (s *Person) PKPointer() interface{} { - return &s.ID -} - -// HasPK returns true if record has non-zero primary key set, false otherwise. -func (s *Person) HasPK() bool { - return s.ID != PersonTable.z[PersonTable.s.PKFieldIndex] -} - -// SetPK sets record primary key. -func (s *Person) SetPK(pk interface{}) { - if i64, ok := pk.(int64); ok { - s.ID = int32(i64) - } else { - s.ID = pk.(int32) - } -} - -// check interfaces -var ( - _ reform.View = PersonTable - _ reform.Struct = (*Person)(nil) - _ reform.Table = PersonTable - _ reform.Record = (*Person)(nil) - _ fmt.Stringer = (*Person)(nil) -) - -func init() { - parse.AssertUpToDate(&PersonTable.s, new(Person)) -} diff --git a/_examples/database/orm/reform/postman_collection.json b/_examples/database/orm/reform/postman_collection.json deleted file mode 100644 index b72a9bd5..00000000 --- a/_examples/database/orm/reform/postman_collection.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "info": { - "_postman_id": "6b66000d-9c04-4d0a-b55c-8a493bf59015", - "name": "iris-reform-example", - "description": "Example API calls for iris reform example.", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "http://localhost:8080/persons", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"name\": \"John\",\r\n \"email\": \"example@example.com\"\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8080/persons", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "persons" - ] - } - }, - "response": [] - }, - { - "name": "http://localhost:8080/persons", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://localhost:8080/persons", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "persons" - ] - } - }, - "response": [] - } - ], - "protocolProfileBehavior": {} -} \ No newline at end of file diff --git a/_examples/database/orm/xorm/main.go b/_examples/database/orm/xorm/main.go deleted file mode 100644 index 2419977a..00000000 --- a/_examples/database/orm/xorm/main.go +++ /dev/null @@ -1,74 +0,0 @@ -// Package main shows how an orm can be used within your web app -// it just inserts a column and select the first. -package main - -import ( - "time" - - "github.com/kataras/iris/v12" - - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -/* - go get -u github.com/mattn/go-sqlite3 - go get -u github.com/go-xorm/xorm - - If you're on win64 and you can't install go-sqlite3: - 1. Download: https://sourceforge.net/projects/mingw-w64/files/latest/download - 2. Select "x86_x64" and "posix" - 3. Add C:\Program Files\mingw-w64\x86_64-7.1.0-posix-seh-rt_v5-rev1\mingw64\bin - to your PATH env variable. - - Docs: http://xorm.io/docs/ -*/ - -// User is our user table structure. -type User struct { - ID int64 // auto-increment by-default by xorm - Version string `xorm:"varchar(200)"` - Salt string - Username string - Password string `xorm:"varchar(200)"` - Languages string `xorm:"varchar(200)"` - CreatedAt time.Time `xorm:"created"` - UpdatedAt time.Time `xorm:"updated"` -} - -func main() { - app := iris.New() - - orm, err := xorm.NewEngine("sqlite3", "./test.db") - if err != nil { - app.Logger().Fatalf("orm failed to initialized: %v", err) - } - - iris.RegisterOnInterrupt(func() { - orm.Close() - }) - - err = orm.Sync2(new(User)) - - if err != nil { - app.Logger().Fatalf("orm failed to initialized User table: %v", err) - } - - app.Get("/insert", func(ctx iris.Context) { - user := &User{Username: "kataras", Salt: "hash---", Password: "hashed", CreatedAt: time.Now(), UpdatedAt: time.Now()} - orm.Insert(user) - - ctx.Writef("user inserted: %#v", user) - }) - - app.Get("/get", func(ctx iris.Context) { - user := User{ID: 1} - if ok, _ := orm.Get(&user); ok { - ctx.Writef("user found: %#v", user) - } - }) - - // http://localhost:8080/insert - // http://localhost:8080/get - app.Listen(":8080") -} diff --git a/_examples/dependency-injection/basic/main.go b/_examples/dependency-injection/basic/main.go deleted file mode 100644 index 58138fa5..00000000 --- a/_examples/dependency-injection/basic/main.go +++ /dev/null @@ -1,47 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - - "github.com/go-playground/validator/v10" -) - -type ( - testInput struct { - Email string `json:"email" validate:"required"` - } - - testOutput struct { - ID int `json:"id"` - Name string `json:"name"` - } -) - -func handler(id int, in testInput) testOutput { - return testOutput{ - ID: id, - Name: in.Email, - } -} - -func configureAPI(api *iris.APIContainer) { - /* Here is how you can inject a return value from a handler, - in this case the "testOutput": - api.UseResultHandler(func(next iris.ResultHandler) iris.ResultHandler { - return func(ctx iris.Context, v interface{}) error { - return next(ctx, map[string]interface{}{"injected": true}) - } - }) - */ - - api.Post("/{id:int}", handler) -} - -func main() { - app := iris.New() - app.Validator = validator.New() - app.Logger().SetLevel("debug") - - app.ConfigureContainer(configureAPI) - app.Listen(":8080") -} diff --git a/_examples/dependency-injection/basic/middleware/main.go b/_examples/dependency-injection/basic/middleware/main.go deleted file mode 100644 index 6faf607d..00000000 --- a/_examples/dependency-injection/basic/middleware/main.go +++ /dev/null @@ -1,64 +0,0 @@ -package main - -import ( - "errors" - - "github.com/kataras/iris/v12" -) - -type ( - testInput struct { - Email string `json:"email"` - } - - testOutput struct { - ID int `json:"id"` - Name string `json:"name"` - } -) - -func handler(id int, in testInput) testOutput { - return testOutput{ - ID: id, - Name: in.Email, - } -} - -var errCustom = errors.New("my_error") - -func middleware(in testInput) (int, error) { - if in.Email == "invalid" { - // stop the execution and don't continue to "handler" - // without firing an error. - return iris.StatusAccepted, iris.ErrStopExecution - } else if in.Email == "error" { - // stop the execution and fire a custom error. - return iris.StatusConflict, errCustom - } - - return iris.StatusOK, nil -} - -func newApp() *iris.Application { - app := iris.New() - - // handle the route, respond with - // a JSON and 200 status code - // or 202 status code and empty body - // or a 409 status code and "my_error" body. - app.ConfigureContainer(func(api *iris.APIContainer) { - api.Use(middleware) - api.Post("/{id:int}", handler) - }) - - app.Configure( - iris.WithOptimizations, /* optional */ - iris.WithoutBodyConsumptionOnUnmarshal /* required when more than one handler is consuming request payload(testInput) */) - - return app -} - -func main() { - app := newApp() - app.Listen(":8080") -} diff --git a/_examples/dependency-injection/basic/middleware/main_test.go b/_examples/dependency-injection/basic/middleware/main_test.go deleted file mode 100644 index eb90c87b..00000000 --- a/_examples/dependency-injection/basic/middleware/main_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import ( - "testing" - - "github.com/kataras/iris/v12/httptest" -) - -func TestDependencyInjectionBasic_Middleware(t *testing.T) { - app := newApp() - - e := httptest.New(t, app) - e.POST("/42").WithJSON(testInput{Email: "my_email"}).Expect(). - Status(httptest.StatusOK). - JSON().Equal(testOutput{ID: 42, Name: "my_email"}) - - // it should stop the execution at the middleware and return the middleware's status code, - // because the error is `ErrStopExecution`. - e.POST("/42").WithJSON(testInput{Email: "invalid"}).Expect(). - Status(httptest.StatusAccepted).Body().Empty() - - // it should stop the execution at the middleware and return the error's text. - e.POST("/42").WithJSON(testInput{Email: "error"}).Expect(). - Status(httptest.StatusConflict).Body().Equal("my_error") -} diff --git a/_examples/dependency-injection/context-register-dependency/main.go b/_examples/dependency-injection/context-register-dependency/main.go deleted file mode 100644 index 8d73bbae..00000000 --- a/_examples/dependency-injection/context-register-dependency/main.go +++ /dev/null @@ -1,95 +0,0 @@ -package main - -import "github.com/kataras/iris/v12" - -func main() { - app := iris.New() - app.Use(RoleMiddleware) - - app.Get("/", commonHandler) - c := app.ConfigureContainer() - /* - When you do NOT have access to the middleware code itself - then you can register a request dependency - which retrieves the value from the Context - and returns it, so handler/function's input arguments - with that `Role` type can be binded. - - c.RegisterDependency(func(ctx iris.Context) Role { - role, ok := GetRole(ctx) - if !ok { - // This codeblock will never be executed here - // but you can stop executing a handler which depends on - // that dependency with `ctx.StopExecution/ctx.StopWithXXX` methods - // or by returning a second output argument of `error` type. - ctx.StopExecution() - return Role{} - } - - return role - }) - */ - c.Get("/dep", handlerWithDependencies) - - // http://localhost:8080?name=kataras - // http://localhost:8080/dep?name=kataras - app.Listen(":8080") -} - -func commonHandler(ctx iris.Context) { - role, _ := GetRole(ctx) - ctx.WriteString(role.Name) -} - -func handlerWithDependencies(role Role) string { - return role.Name -} - -// Code for an example middleware. - -// Role struct value example. -type Role struct { - Name string -} - -const roleContextKey = "myapp.role" - -// RoleMiddleware example of a custom middleware. -func RoleMiddleware(ctx iris.Context) { - // [do it yourself: extract the role from the request...] - if ctx.URLParam("name") != "kataras" { - ctx.StopWithStatus(iris.StatusUnauthorized) - return - } - // - - role := Role{Name: "admin"} - - ctx.Values().Set(roleContextKey, role) - - // When you have access to the middleware itself: - // Use the `RegisterDependency` to register - // struct type values as dependencies at request-time for - // any potential dependency injection-ed user handler. - // This way the user of your middleware can get rid of - // manually register a dependency for that `Role` type with calls of - // `APIContainer.RegisterDependency` (and `mvc.Application.Register`). - ctx.RegisterDependency(role) - - ctx.Next() -} - -// GetRole returns the role inside the context values, -// the `roleMiddleware` should be executed first. -func GetRole(ctx iris.Context) (Role, bool) { - v := ctx.Values().Get(roleContextKey) - if v != nil { - if role, ok := v.(Role); ok { - return role, true - } - } - - return Role{}, false -} - -// End Code of our example middleware. diff --git a/_examples/dependency-injection/jwt/contrib/go.mod b/_examples/dependency-injection/jwt/contrib/go.mod deleted file mode 100644 index 228fc139..00000000 --- a/_examples/dependency-injection/jwt/contrib/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/kataras/iris/_examples/dependency-injection/jwt/contrib - -go 1.15 - -require github.com/iris-contrib/middleware/jwt v0.0.0-20200710202437-92b01b85baaf diff --git a/_examples/dependency-injection/jwt/contrib/main.go b/_examples/dependency-injection/jwt/contrib/main.go deleted file mode 100644 index 171f2ed1..00000000 --- a/_examples/dependency-injection/jwt/contrib/main.go +++ /dev/null @@ -1,66 +0,0 @@ -package main - -import ( - "github.com/kataras/iris/v12" - - "github.com/iris-contrib/middleware/jwt" -) - -var secret = []byte("My Secret Key") - -func main() { - app := iris.New() - app.ConfigureContainer(register) - - app.Listen(":8080") -} - -func register(api *iris.APIContainer) { - j := jwt.New(jwt.Config{ - // Extract by "token" url parameter. - Extractor: jwt.FromFirst(jwt.FromParameter("token"), jwt.FromAuthHeader), - ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { - return secret, nil - }, - SigningMethod: jwt.SigningMethodHS256, - }) - - api.Get("/authenticate", writeToken) - // This works as usually: - api.Get("/restricted", j.Serve, restrictedPage) - - // You can also bind the *jwt.Token (see `verifiedWithBindedTokenPage`) - // by registering a *jwt.Token dependency. - // - // api.RegisterDependency(func(ctx iris.Context) *jwt.Token { - // if err := j.CheckJWT(ctx); err != nil { - // ctx.StopWithStatus(iris.StatusUnauthorized) - // return nil - // } - // - // token := j.Get(ctx) - // return token - // }) - // ^ You can do the same with MVC too, as the container is shared and works - // the same way in both functions-as-handlers and structs-as-controllers. - // - // api.Get("/", restrictedPageWithBindedTokenPage) -} - -func writeToken() string { - token := jwt.NewTokenWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ - "foo": "bar", - }) - - tokenString, _ := token.SignedString(secret) - return tokenString -} - -func restrictedPage() string { - return "This page can only be seen by verified clients" -} - -func restrictedPageWithBindedTokenPage(token *jwt.Token) string { - // Token[foo] value: bar - return "Token[foo] value: " + token.Claims.(jwt.MapClaims)["foo"].(string) -} diff --git a/_examples/dependency-injection/jwt/main.go b/_examples/dependency-injection/jwt/main.go deleted file mode 100644 index c705fac9..00000000 --- a/_examples/dependency-injection/jwt/main.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "time" - - "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/middleware/jwt" -) - -func main() { - app := iris.New() - app.ConfigureContainer(register) - - app.Listen(":8080") -} - -func register(api *iris.APIContainer) { - j := jwt.HMAC(15*time.Minute, "secret", "secretforencrypt") - - api.RegisterDependency(func(ctx iris.Context) (claims userClaims) { - if err := j.VerifyToken(ctx, &claims); err != nil { - ctx.StopWithError(iris.StatusUnauthorized, err) - return - } - - return - }) - - api.Get("/authenticate", writeToken(j)) - api.Get("/restricted", restrictedPage) -} - -type userClaims struct { - jwt.Claims - Username string -} - -func writeToken(j *jwt.JWT) iris.Handler { - return func(ctx iris.Context) { - j.WriteToken(ctx, userClaims{ - Claims: j.Expiry(jwt.Claims{Issuer: "an-issuer"}), - Username: "kataras", - }) - } -} - -func restrictedPage(claims userClaims) string { - // userClaims.Username: kataras - return "userClaims.Username: " + claims.Username -} diff --git a/_examples/dependency-injection/overview/datamodels/movie.go b/_examples/dependency-injection/overview/datamodels/movie.go deleted file mode 100644 index 1b25d127..00000000 --- a/_examples/dependency-injection/overview/datamodels/movie.go +++ /dev/null @@ -1,18 +0,0 @@ -// file: datamodels/movie.go - -package datamodels - -// Movie is our sample data structure. -// Keep note that the tags for public-use (for our web app) -// should be kept in other file like "web/viewmodels/movie.go" -// which could wrap by embedding the datamodels.Movie or -// declare new fields instead butwe will use this datamodel -// as the only one Movie model in our application, -// for the sake of simplicty. -type Movie struct { - ID uint64 `json:"id"` - Name string `json:"name"` - Year int `json:"year"` - Genre string `json:"genre"` - Poster string `json:"poster"` -} diff --git a/_examples/dependency-injection/overview/datasource/movies.go b/_examples/dependency-injection/overview/datasource/movies.go deleted file mode 100644 index 4b5fbf31..00000000 --- a/_examples/dependency-injection/overview/datasource/movies.go +++ /dev/null @@ -1,44 +0,0 @@ -// file: datasource/movies.go - -package datasource - -import "github.com/kataras/iris/v12/_examples/dependency-injection/overview/datamodels" - -// Movies is our imaginary data source. -var Movies = map[uint64]datamodels.Movie{ - 1: { - ID: 1, - Name: "Casablanca", - Year: 1942, - Genre: "Romance", - Poster: "https://iris-go.com/images/examples/mvc-movies/1.jpg", - }, - 2: { - ID: 2, - Name: "Gone with the Wind", - Year: 1939, - Genre: "Romance", - Poster: "https://iris-go.com/images/examples/mvc-movies/2.jpg", - }, - 3: { - ID: 3, - Name: "Citizen Kane", - Year: 1941, - Genre: "Mystery", - Poster: "https://iris-go.com/images/examples/mvc-movies/3.jpg", - }, - 4: { - ID: 4, - Name: "The Wizard of Oz", - Year: 1939, - Genre: "Fantasy", - Poster: "https://iris-go.com/images/examples/mvc-movies/4.jpg", - }, - 5: { - ID: 5, - Name: "North by Northwest", - Year: 1959, - Genre: "Thriller", - Poster: "https://iris-go.com/images/examples/mvc-movies/5.jpg", - }, -} diff --git a/_examples/dependency-injection/overview/main.go b/_examples/dependency-injection/overview/main.go deleted file mode 100644 index 8386aaae..00000000 --- a/_examples/dependency-injection/overview/main.go +++ /dev/null @@ -1,55 +0,0 @@ -// file: main.go - -package main - -import ( - "github.com/kataras/iris/v12/_examples/dependency-injection/overview/datasource" - "github.com/kataras/iris/v12/_examples/dependency-injection/overview/repositories" - "github.com/kataras/iris/v12/_examples/dependency-injection/overview/services" - "github.com/kataras/iris/v12/_examples/dependency-injection/overview/web/middleware" - "github.com/kataras/iris/v12/_examples/dependency-injection/overview/web/routes" - - "github.com/kataras/iris/v12" -) - -func main() { - app := iris.New() - app.Logger().SetLevel("debug") - - // Load the template files. - app.RegisterView(iris.HTML("./web/views", ".html")) - - // Create our movie repository with some (memory) data from the datasource. - repo := repositories.NewMovieRepository(datasource.Movies) - - app.Party("/hello").ConfigureContainer(func(r *iris.APIContainer) { - r.Get("/", routes.Hello) - r.Get("/{name}", routes.HelloName) - }) - - app.Party("/movies").ConfigureContainer(func(r *iris.APIContainer) { - // Create our movie service, we will bind it to the movie app's dependencies. - movieService := services.NewMovieService(repo) - r.RegisterDependency(movieService) - - // Add the basic authentication(admin:password) middleware - // for the /movies based requests. - r.Use(middleware.BasicAuth) - - r.Get("/", routes.Movies) - r.Get("/{id:uint64}", routes.MovieByID) - r.Put("/{id:uint64}", routes.UpdateMovieByID) - r.Delete("/{id:uint64}", routes.DeleteMovieByID) - }) - - // http://localhost:8080/hello - // http://localhost:8080/hello/iris - // http://localhost:8080/movies ("admin": "password") - // http://localhost:8080/movies/1 - app.Listen( - // Start the web server at localhost:8080 - "localhost:8080", - // enables faster json serialization and more: - iris.WithOptimizations, - ) -} diff --git a/_examples/dependency-injection/overview/repositories/movie_repository.go b/_examples/dependency-injection/overview/repositories/movie_repository.go deleted file mode 100644 index 0a46cb1b..00000000 --- a/_examples/dependency-injection/overview/repositories/movie_repository.go +++ /dev/null @@ -1,176 +0,0 @@ -// file: repositories/movie_repository.go - -package repositories - -import ( - "errors" - "sync" - - "github.com/kataras/iris/v12/_examples/dependency-injection/overview/datamodels" -) - -// Query represents the visitor and action queries. -type Query func(datamodels.Movie) bool - -// MovieRepository handles the basic operations of a movie entity/model. -// It's an interface in order to be testable, i.e a memory movie repository or -// a connected to an sql database. -type MovieRepository interface { - Exec(query Query, action Query, limit int, mode int) (ok bool) - - Select(query Query) (movie datamodels.Movie, found bool) - SelectMany(query Query, limit int) (results []datamodels.Movie) - - InsertOrUpdate(movie datamodels.Movie) (updatedMovie datamodels.Movie, err error) - Delete(query Query, limit int) (deleted bool) -} - -// NewMovieRepository returns a new movie memory-based repository, -// the one and only repository type in our example. -func NewMovieRepository(source map[uint64]datamodels.Movie) MovieRepository { - return &movieMemoryRepository{source: source} -} - -// movieMemoryRepository is a "MovieRepository" -// which manages the movies using the memory data source (map). -type movieMemoryRepository struct { - source map[uint64]datamodels.Movie - mu sync.RWMutex -} - -const ( - // ReadOnlyMode will RLock(read) the data . - ReadOnlyMode = iota - // ReadWriteMode will Lock(read/write) the data. - ReadWriteMode -) - -func (r *movieMemoryRepository) Exec(query Query, action Query, actionLimit int, mode int) (ok bool) { - loops := 0 - - if mode == ReadOnlyMode { - r.mu.RLock() - defer r.mu.RUnlock() - } else { - r.mu.Lock() - defer r.mu.Unlock() - } - - for _, movie := range r.source { - ok = query(movie) - if ok { - if action(movie) { - loops++ - if actionLimit >= loops { - break // break - } - } - } - } - - return -} - -// Select receives a query function -// which is fired for every single movie model inside -// our imaginary data source. -// When that function returns true then it stops the iteration. -// -// It returns the query's return last known "found" value -// and the last known movie model -// to help callers to reduce the LOC. -// -// It's actually a simple but very clever prototype function -// I'm using everywhere since I firstly think of it, -// hope you'll find it very useful as well. -func (r *movieMemoryRepository) Select(query Query) (movie datamodels.Movie, found bool) { - found = r.Exec(query, func(m datamodels.Movie) bool { - movie = m - return true - }, 1, ReadOnlyMode) - - // set an empty datamodels.Movie if not found at all. - if !found { - movie = datamodels.Movie{} - } - - return -} - -// SelectMany same as Select but returns one or more datamodels.Movie as a slice. -// If limit <=0 then it returns everything. -func (r *movieMemoryRepository) SelectMany(query Query, limit int) (results []datamodels.Movie) { - r.Exec(query, func(m datamodels.Movie) bool { - results = append(results, m) - return true - }, limit, ReadOnlyMode) - - return -} - -// InsertOrUpdate adds or updates a movie to the (memory) storage. -// -// Returns the new movie and an error if any. -func (r *movieMemoryRepository) InsertOrUpdate(movie datamodels.Movie) (datamodels.Movie, error) { - id := movie.ID - - if id == 0 { // Create new action - var lastID uint64 - // find the biggest ID in order to not have duplications - // in productions apps you can use a third-party - // library to generate a UUID as string. - r.mu.RLock() - for _, item := range r.source { - if item.ID > lastID { - lastID = item.ID - } - } - r.mu.RUnlock() - - id = lastID + 1 - movie.ID = id - - // map-specific thing - r.mu.Lock() - r.source[id] = movie - r.mu.Unlock() - - return movie, nil - } - - // Update action based on the movie.ID, - // here we will allow updating the poster and genre if not empty. - // Alternatively we could do pure replace instead: - // r.source[id] = movie - // and comment the code below; - current, exists := r.Select(func(m datamodels.Movie) bool { - return m.ID == id - }) - - if !exists { // ID is not a real one, return an error. - return datamodels.Movie{}, errors.New("failed to update a nonexistent movie") - } - - // or comment these and r.source[id] = m for pure replace - if movie.Poster != "" { - current.Poster = movie.Poster - } - - if movie.Genre != "" { - current.Genre = movie.Genre - } - - // map-specific thing - r.mu.Lock() - r.source[id] = current - r.mu.Unlock() - - return movie, nil -} - -func (r *movieMemoryRepository) Delete(query Query, limit int) bool { - return r.Exec(query, func(m datamodels.Movie) bool { - delete(r.source, m.ID) - return true - }, limit, ReadWriteMode) -} diff --git a/_examples/dependency-injection/overview/services/movie_service.go b/_examples/dependency-injection/overview/services/movie_service.go deleted file mode 100644 index 6835a9b5..00000000 --- a/_examples/dependency-injection/overview/services/movie_service.go +++ /dev/null @@ -1,65 +0,0 @@ -// file: services/movie_service.go - -package services - -import ( - "github.com/kataras/iris/v12/_examples/dependency-injection/overview/datamodels" - "github.com/kataras/iris/v12/_examples/dependency-injection/overview/repositories" -) - -// MovieService handles some of the CRUID operations of the movie datamodel. -// It depends on a movie repository for its actions. -// It's here to decouple the data source from the higher level compoments. -// As a result a different repository type can be used with the same logic without any aditional changes. -// It's an interface and it's used as interface everywhere -// because we may need to change or try an experimental different domain logic at the future. -type MovieService interface { - GetAll() []datamodels.Movie - GetByID(id uint64) (datamodels.Movie, bool) - DeleteByID(id uint64) bool - UpdatePosterAndGenreByID(id uint64, poster string, genre string) (datamodels.Movie, error) -} - -// NewMovieService returns the default movie service. -func NewMovieService(repo repositories.MovieRepository) MovieService { - return &movieService{ - repo: repo, - } -} - -type movieService struct { - repo repositories.MovieRepository -} - -// GetAll returns all movies. -func (s *movieService) GetAll() []datamodels.Movie { - return s.repo.SelectMany(func(_ datamodels.Movie) bool { - return true - }, -1) -} - -// GetByID returns a movie based on its id. -func (s *movieService) GetByID(id uint64) (datamodels.Movie, bool) { - return s.repo.Select(func(m datamodels.Movie) bool { - return m.ID == id - }) -} - -// UpdatePosterAndGenreByID updates a movie's poster and genre. -func (s *movieService) UpdatePosterAndGenreByID(id uint64, poster string, genre string) (datamodels.Movie, error) { - // update the movie and return it. - return s.repo.InsertOrUpdate(datamodels.Movie{ - ID: id, - Poster: poster, - Genre: genre, - }) -} - -// DeleteByID deletes a movie by its id. -// -// Returns true if deleted otherwise false. -func (s *movieService) DeleteByID(id uint64) bool { - return s.repo.Delete(func(m datamodels.Movie) bool { - return m.ID == id - }, 1) -} diff --git a/_examples/dependency-injection/overview/web/middleware/basicauth.go b/_examples/dependency-injection/overview/web/middleware/basicauth.go deleted file mode 100644 index 5d61fc72..00000000 --- a/_examples/dependency-injection/overview/web/middleware/basicauth.go +++ /dev/null @@ -1,12 +0,0 @@ -// file: web/middleware/basicauth.go - -package middleware - -import "github.com/kataras/iris/v12/middleware/basicauth" - -// BasicAuth middleware sample. -var BasicAuth = basicauth.New(basicauth.Config{ - Users: map[string]string{ - "admin": "password", - }, -}) diff --git a/_examples/dependency-injection/overview/web/routes/hello.go b/_examples/dependency-injection/overview/web/routes/hello.go deleted file mode 100644 index e0c4a029..00000000 --- a/_examples/dependency-injection/overview/web/routes/hello.go +++ /dev/null @@ -1,50 +0,0 @@ -// file: web/routes/hello.go - -package routes - -import ( - "errors" - - "github.com/kataras/iris/v12/hero" -) - -var helloView = hero.View{ - Name: "hello/index.html", - Data: map[string]interface{}{ - "Title": "Hello Page", - "MyMessage": "Welcome to my awesome website", - }, -} - -// Hello will return a predefined view with bind data. -// -// `hero.Result` is just an interface with a `Dispatch` function. -// `hero.Response` and `hero.View` are the builtin result type dispatchers -// you can even create custom response dispatchers by -// implementing the `github.com/kataras/iris/hero#Result` interface. -func Hello() hero.Result { - return helloView -} - -// you can define a standard error in order to re-use anywhere in your app. -var errBadName = errors.New("bad name") - -// you can just return it as error or even better -// wrap this error with an hero.Response to make it an hero.Result compatible type. -var badName = hero.Response{Err: errBadName, Code: 400} - -// HelloName returns a "Hello {name}" response. -// Demos: -// curl -i http://localhost:8080/hello/iris -// curl -i http://localhost:8080/hello/anything -func HelloName(name string) hero.Result { - if name != "iris" { - return badName - } - - // return hero.Response{Text: "Hello " + name} OR: - return hero.View{ - Name: "hello/name.html", - Data: name, - } -} diff --git a/_examples/dependency-injection/overview/web/routes/movies.go b/_examples/dependency-injection/overview/web/routes/movies.go deleted file mode 100644 index d6b902d9..00000000 --- a/_examples/dependency-injection/overview/web/routes/movies.go +++ /dev/null @@ -1,59 +0,0 @@ -// file: web/routes/movie.go - -package routes - -import ( - "errors" - - "github.com/kataras/iris/v12/_examples/dependency-injection/overview/datamodels" - "github.com/kataras/iris/v12/_examples/dependency-injection/overview/services" - - "github.com/kataras/iris/v12" -) - -// Movies returns list of the movies. -// Demo: -// curl -i http://localhost:8080/movies -func Movies(service services.MovieService) (results []datamodels.Movie) { - return service.GetAll() -} - -// MovieByID returns a movie. -// Demo: -// curl -i http://localhost:8080/movies/1 -func MovieByID(service services.MovieService, id uint64) (movie datamodels.Movie, found bool) { - return service.GetByID(id) // it will throw 404 if not found. -} - -// UpdateMovieByID updates a movie. -// Demo: -// curl -i -X PUT -F "genre=Thriller" -F "poster=@/Users/kataras/Downloads/out.gif" http://localhost:8080/movies/1 -func UpdateMovieByID(ctx iris.Context, service services.MovieService, id uint64) (datamodels.Movie, error) { - // get the request data for poster and genre - file, info, err := ctx.FormFile("poster") - if err != nil { - return datamodels.Movie{}, errors.New("failed due form file 'poster' missing") - } - // we don't need the file so close it now. - file.Close() - - // imagine that is the url of the uploaded file... - poster := info.Filename - genre := ctx.FormValue("genre") - - return service.UpdatePosterAndGenreByID(id, poster, genre) -} - -// DeleteMovieByID deletes a movie. -// Demo: -// curl -i -X DELETE -u admin:password http://localhost:8080/movies/1 -func DeleteMovieByID(service services.MovieService, id uint64) interface{} { - wasDel := service.DeleteByID(id) - if wasDel { - // return the deleted movie's ID - return iris.Map{"deleted": id} - } - // right here we can see that a method function can return any of those two types(map or int), - // we don't have to specify the return type to a specific type. - return iris.StatusBadRequest -} diff --git a/_examples/dependency-injection/overview/web/views/hello/index.html b/_examples/dependency-injection/overview/web/views/hello/index.html deleted file mode 100644 index 9e7b03d6..00000000 --- a/_examples/dependency-injection/overview/web/views/hello/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - {{.Title}} - My App - - - -