{"id":17972433,"url":"https://github.com/inphinit/teeny","last_synced_at":"2025-03-25T12:33:00.961Z","repository":{"id":56991885,"uuid":"178430937","full_name":"inphinit/teeny","owner":"inphinit","description":"A teeny route system PHP 5.3 to PHP 8","archived":false,"fork":false,"pushed_at":"2024-12-08T03:53:51.000Z","size":209,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-20T07:51:31.213Z","etag":null,"topics":["composer","http-router","php","php7","php8","routing"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/inphinit.png","metadata":{"files":{"readme":"README.html","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-03-29T15:28:05.000Z","updated_at":"2024-12-08T03:53:55.000Z","dependencies_parsed_at":"2023-12-19T11:02:59.864Z","dependency_job_id":"c3b42fdf-0620-489b-a3c6-6e986f3c9e3c","html_url":"https://github.com/inphinit/teeny","commit_stats":{"total_commits":46,"total_committers":1,"mean_commits":46.0,"dds":0.0,"last_synced_commit":"ab54f0112759c47b33bd2a806c050326f7d0e25f"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inphinit%2Fteeny","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inphinit%2Fteeny/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inphinit%2Fteeny/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inphinit%2Fteeny/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/inphinit","download_url":"https://codeload.github.com/inphinit/teeny/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245462971,"owners_count":20619587,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["composer","http-router","php","php7","php8","routing"],"created_at":"2024-10-29T16:16:09.209Z","updated_at":"2025-03-25T12:33:00.929Z","avatar_url":"https://github.com/inphinit.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!DOCTYPE html\u003e\u003chtml\u003e\u003chead\u003e\u003cmeta charset=\"utf-8\"\u003e\u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\"\u003e\u003cstyle\u003ebody {\n  max-width: 980px;\n  margin: 16px auto;\n}\n\nbody .markdown-body\n{\n  padding: 45px;\n}\n\n@font-face {\n  font-family: fontawesome-mini;\n  src: url(data:font/woff;charset=utf-8;base64,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) format('woff');\n}\n\n.markdown-body {\n  font-family: sans-serif;\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n  color: #333333;\n  overflow: hidden;\n  font-family: \"Helvetica Neue\", Helvetica, \"Segoe UI\", Arial, freesans, sans-serif;\n  font-size: 16px;\n  line-height: 1.6;\n  word-wrap: break-word;\n}\n\n.markdown-body a {\n  background: transparent;\n}\n\n.markdown-body a:active,\n.markdown-body a:hover {\n  outline: 0;\n}\n\n.markdown-body b,\n.markdown-body strong {\n  font-weight: bold;\n}\n\n.markdown-body mark {\n  background: #ff0;\n  color: #000;\n  font-style: italic;\n  font-weight: bold;\n}\n\n.markdown-body sub,\n.markdown-body sup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n.markdown-body sup {\n  top: -0.5em;\n}\n.markdown-body sub {\n  bottom: -0.25em;\n}\n\n.markdown-body h1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n.markdown-body img {\n  border: 0;\n}\n\n.markdown-body hr {\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n  height: 0;\n}\n\n.markdown-body pre {\n  overflow: auto;\n}\n\n.markdown-body code,\n.markdown-body kbd,\n.markdown-body pre,\n.markdown-body samp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\n.markdown-body input {\n  color: inherit;\n  font: inherit;\n  margin: 0;\n}\n\n.markdown-body html input[disabled] {\n  cursor: default;\n}\n\n.markdown-body input {\n  line-height: normal;\n}\n\n.markdown-body input[type=\"checkbox\"] {\n  box-sizing: border-box;\n  padding: 0;\n}\n\n.markdown-body table {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\n.markdown-body td,\n.markdown-body th {\n  padding: 0;\n}\n\n.markdown-body .codehilitetable,\n.markdown-body .highlighttable {\n  border: 0;\n  border-spacing: 0;\n}\n\n.markdown-body .codehilitetable tr,\n.markdown-body .highlighttable {\n  border: 0;\n}\n\n.markdown-body .codehilitetable pre,\n.markdown-body .codehilitetable div.codehilite,\n.markdown-body .highlighttable pre,\n.markdown-body .highlighttable div.highlight {\n  margin: 0;\n}\n\n.markdown-body .linenos,\n.markdown-body .code,\n.markdown-body .codehilitetable td,\n.markdown-body .highlighttable td {\n  border: 0;\n  padding: 0;\n}\n\n.markdown-body td:not(.linenos) .linenodiv {\n  padding: 0 !important;\n}\n\n.markdown-body .code {\n  width: 100%;\n}\n\n.markdown-body .linenos div pre,\n.markdown-body .linenodiv pre,\n.markdown-body .linenodiv {\n  border: 0;\n  -webkit-border-radius: 0;\n  -moz-border-radius: 0;\n  border-radius: 0;\n  -webkit-border-top-left-radius: 3px;\n  -webkit-border-bottom-left-radius: 3px;\n  -moz-border-radius-topleft: 3px;\n  -moz-border-radius-bottomleft: 3px;\n  border-top-left-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n\n.markdown-body .code div pre,\n.markdown-body .code div {\n  border: 0;\n  -webkit-border-radius: 0;\n  -moz-border-radius: 0;\n  border-radius: 0;\n  -webkit-border-top-right-radius: 3px;\n  -webkit-border-bottom-right-radius: 3px;\n  -moz-border-radius-topright: 3px;\n  -moz-border-radius-bottomright: 3px;\n  border-top-right-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n\n.markdown-body * {\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\n.markdown-body input {\n  font: 13px Helvetica, arial, freesans, clean, sans-serif, \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n  line-height: 1.4;\n}\n\n.markdown-body a {\n  color: #4183c4;\n  text-decoration: none;\n}\n\n.markdown-body a:hover,\n.markdown-body a:focus,\n.markdown-body a:active {\n  text-decoration: underline;\n}\n\n.markdown-body hr {\n  height: 0;\n  margin: 15px 0;\n  overflow: hidden;\n  background: transparent;\n  border: 0;\n  border-bottom: 1px solid #ddd;\n}\n\n.markdown-body hr:before,\n.markdown-body hr:after {\n  display: table;\n  content: \" \";\n}\n\n.markdown-body hr:after {\n  clear: both;\n}\n\n.markdown-body h1,\n.markdown-body h2,\n.markdown-body h3,\n.markdown-body h4,\n.markdown-body h5,\n.markdown-body h6 {\n  margin-top: 15px;\n  margin-bottom: 15px;\n  line-height: 1.1;\n}\n\n.markdown-body h1 {\n  font-size: 30px;\n}\n\n.markdown-body h2 {\n  font-size: 21px;\n}\n\n.markdown-body h3 {\n  font-size: 16px;\n}\n\n.markdown-body h4 {\n  font-size: 14px;\n}\n\n.markdown-body h5 {\n  font-size: 12px;\n}\n\n.markdown-body h6 {\n  font-size: 11px;\n}\n\n.markdown-body blockquote {\n  margin: 0;\n}\n\n.markdown-body ul,\n.markdown-body ol {\n  padding: 0;\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n.markdown-body ol ol,\n.markdown-body ul ol {\n  list-style-type: lower-roman;\n}\n\n.markdown-body ul ul ol,\n.markdown-body ul ol ol,\n.markdown-body ol ul ol,\n.markdown-body ol ol ol {\n  list-style-type: lower-alpha;\n}\n\n.markdown-body dd {\n  margin-left: 0;\n}\n\n.markdown-body code,\n.markdown-body pre,\n.markdown-body samp {\n  font-family: Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n  font-size: 12px;\n}\n\n.markdown-body pre {\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n.markdown-body kbd {\n  background-color: #e7e7e7;\n  background-image: -moz-linear-gradient(#fefefe, #e7e7e7);\n  background-image: -webkit-linear-gradient(#fefefe, #e7e7e7);\n  background-image: linear-gradient(#fefefe, #e7e7e7);\n  background-repeat: repeat-x;\n  border-radius: 2px;\n  border: 1px solid #cfcfcf;\n  color: #000;\n  padding: 3px 5px;\n  line-height: 10px;\n  font: 11px Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n  display: inline-block;\n}\n\n.markdown-body\u003e*:first-child {\n  margin-top: 0 !important;\n}\n\n.markdown-body\u003e*:last-child {\n  margin-bottom: 0 !important;\n}\n\n.markdown-body .headerlink {\n  font: normal 400 16px fontawesome-mini;\n  vertical-align: middle;\n  margin-left: -16px;\n  float: left;\n  display: inline-block;\n  text-decoration: none;\n  opacity: 0;\n  color: #333;\n}\n\n.markdown-body .headerlink:focus {\n  outline: none;\n}\n\n.markdown-body h1 .headerlink {\n  margin-top: 0.8rem;\n}\n\n.markdown-body h2 .headerlink,\n.markdown-body h3 .headerlink {\n  margin-top: 0.6rem;\n}\n\n.markdown-body h4 .headerlink {\n  margin-top: 0.2rem;\n}\n\n.markdown-body h5 .headerlink,\n.markdown-body h6 .headerlink {\n  margin-top: 0;\n}\n\n.markdown-body .headerlink:hover,\n.markdown-body h1:hover .headerlink,\n.markdown-body h2:hover .headerlink,\n.markdown-body h3:hover .headerlink,\n.markdown-body h4:hover .headerlink,\n.markdown-body h5:hover .headerlink,\n.markdown-body h6:hover .headerlink {\n  opacity: 1;\n  text-decoration: none;\n}\n\n.markdown-body h1 {\n  padding-bottom: 0.3em;\n  font-size: 2.25em;\n  line-height: 1.2;\n  border-bottom: 1px solid #eee;\n}\n\n.markdown-body h2 {\n  padding-bottom: 0.3em;\n  font-size: 1.75em;\n  line-height: 1.225;\n  border-bottom: 1px solid #eee;\n}\n\n.markdown-body h3 {\n  font-size: 1.5em;\n  line-height: 1.43;\n}\n\n.markdown-body h4 {\n  font-size: 1.25em;\n}\n\n.markdown-body h5 {\n  font-size: 1em;\n}\n\n.markdown-body h6 {\n  font-size: 1em;\n  color: #777;\n}\n\n.markdown-body p,\n.markdown-body blockquote,\n.markdown-body ul,\n.markdown-body ol,\n.markdown-body dl,\n.markdown-body table,\n.markdown-body pre,\n.markdown-body .admonition {\n  margin-top: 0;\n  margin-bottom: 16px;\n}\n\n.markdown-body hr {\n  height: 4px;\n  padding: 0;\n  margin: 16px 0;\n  background-color: #e7e7e7;\n  border: 0 none;\n}\n\n.markdown-body ul,\n.markdown-body ol {\n  padding-left: 2em;\n}\n\n.markdown-body ul ul,\n.markdown-body ul ol,\n.markdown-body ol ol,\n.markdown-body ol ul {\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n.markdown-body li\u003ep {\n  margin-top: 16px;\n}\n\n.markdown-body dl {\n  padding: 0;\n}\n\n.markdown-body dl dt {\n  padding: 0;\n  margin-top: 16px;\n  font-size: 1em;\n  font-style: italic;\n  font-weight: bold;\n}\n\n.markdown-body dl dd {\n  padding: 0 16px;\n  margin-bottom: 16px;\n}\n\n.markdown-body blockquote {\n  padding: 0 15px;\n  color: #777;\n  border-left: 4px solid #ddd;\n}\n\n.markdown-body blockquote\u003e:first-child {\n  margin-top: 0;\n}\n\n.markdown-body blockquote\u003e:last-child {\n  margin-bottom: 0;\n}\n\n.markdown-body table {\n  display: block;\n  width: 100%;\n  overflow: auto;\n  word-break: normal;\n  word-break: keep-all;\n}\n\n.markdown-body table th {\n  font-weight: bold;\n}\n\n.markdown-body table th,\n.markdown-body table td {\n  padding: 6px 13px;\n  border: 1px solid #ddd;\n}\n\n.markdown-body table tr {\n  background-color: #fff;\n  border-top: 1px solid #ccc;\n}\n\n.markdown-body table tr:nth-child(2n) {\n  background-color: #f8f8f8;\n}\n\n.markdown-body img {\n  max-width: 100%;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\n.markdown-body code,\n.markdown-body samp {\n  padding: 0;\n  padding-top: 0.2em;\n  padding-bottom: 0.2em;\n  margin: 0;\n  font-size: 85%;\n  border-radius: 3px;\n}\n\n.markdown-body code:not(.highlight):not(.codehilite), .markdown-body samp {\n  background-color: rgba(0,0,0,0.04);\n}\n\n.markdown-body code:before,\n.markdown-body code:after {\n  letter-spacing: -0.2em;\n  content: \"\\00a0\";\n}\n\n.markdown-body pre\u003ecode {\n  padding: 0;\n  margin: 0;\n  font-size: 100%;\n  word-break: normal;\n  white-space: pre;\n  background: transparent;\n  border: 0;\n}\n\n.markdown-body .codehilite,\n.markdown-body .highlight {\n  margin-bottom: 16px;\n}\n\n.markdown-body .codehilite pre,\n.markdown-body .highlight pre,\n.markdown-body pre {\n  padding: 16px;\n  overflow: auto;\n  font-size: 85%;\n  line-height: 1.45;\n}\n\n.markdown-body .codehilite,\n.markdown-body .highlight,\n.markdown-body pre {\n  border-radius: 3px;\n}\n\n.markdown-body :not(.highlight) \u003e pre {\n  background-color: #f7f7f7;\n}\n\n.markdown-body .codehilite pre,\n.markdown-body .highlight pre {\n  margin-bottom: 0;\n  word-break: normal;\n}\n\n.markdown-body pre {\n  word-wrap: normal;\n}\n\n.markdown-body pre code {\n  display: inline;\n  max-width: initial;\n  padding: 0;\n  margin: 0;\n  overflow: initial;\n  line-height: inherit;\n  word-wrap: normal;\n  background-color: transparent;\n  border: 0;\n}\n\n.markdown-body pre code:before,\n.markdown-body pre code:after {\n  content: normal;\n}\n\n/* Admonition */\n.markdown-body .admonition {\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  position: relative;\n  border-radius: 3px;\n  border: 1px solid #e0e0e0;\n  border-left: 6px solid #333;\n  padding: 10px 10px 10px 30px;\n}\n\n.markdown-body .admonition table {\n  color: #333;\n}\n\n.markdown-body .admonition p {\n  padding: 0;\n}\n\n.markdown-body .admonition-title {\n  font-weight: bold;\n  margin: 0;\n}\n\n.markdown-body .admonition\u003e.admonition-title {\n  color: #333;\n}\n\n.markdown-body .attention\u003e.admonition-title {\n  color: #a6d796;\n}\n\n.markdown-body .caution\u003e.admonition-title {\n  color: #d7a796;\n}\n\n.markdown-body .hint\u003e.admonition-title {\n  color: #96c6d7;\n}\n\n.markdown-body .danger\u003e.admonition-title {\n  color: #c25f77;\n}\n\n.markdown-body .question\u003e.admonition-title {\n  color: #96a6d7;\n}\n\n.markdown-body .note\u003e.admonition-title {\n  color: #d7c896;\n}\n\n.markdown-body .admonition:before,\n.markdown-body .attention:before,\n.markdown-body .caution:before,\n.markdown-body .hint:before,\n.markdown-body .danger:before,\n.markdown-body .question:before,\n.markdown-body .note:before {\n  font: normal normal 16px fontawesome-mini;\n  -moz-osx-font-smoothing: grayscale;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  line-height: 1.5;\n  color: #333;\n  position: absolute;\n  left: 0;\n  top: 0;\n  padding-top: 10px;\n  padding-left: 10px;\n}\n\n.markdown-body .admonition:before {\n  content: \"\\f056\\00a0\";\n  color: 333;\n}\n\n.markdown-body .attention:before {\n  content: \"\\f058\\00a0\";\n  color: #a6d796;\n}\n\n.markdown-body .caution:before {\n  content: \"\\f06a\\00a0\";\n  color: #d7a796;\n}\n\n.markdown-body .hint:before {\n  content: \"\\f05a\\00a0\";\n  color: #96c6d7;\n}\n\n.markdown-body .danger:before {\n  content: \"\\f057\\00a0\";\n  color: #c25f77;\n}\n\n.markdown-body .question:before {\n  content: \"\\f059\\00a0\";\n  color: #96a6d7;\n}\n\n.markdown-body .note:before {\n  content: \"\\f040\\00a0\";\n  color: #d7c896;\n}\n\n.markdown-body .admonition::after {\n  content: normal;\n}\n\n.markdown-body .attention {\n  border-left: 6px solid #a6d796;\n}\n\n.markdown-body .caution {\n  border-left: 6px solid #d7a796;\n}\n\n.markdown-body .hint {\n  border-left: 6px solid #96c6d7;\n}\n\n.markdown-body .danger {\n  border-left: 6px solid #c25f77;\n}\n\n.markdown-body .question {\n  border-left: 6px solid #96a6d7;\n}\n\n.markdown-body .note {\n  border-left: 6px solid #d7c896;\n}\n\n.markdown-body .admonition\u003e*:first-child {\n  margin-top: 0 !important;\n}\n\n.markdown-body .admonition\u003e*:last-child {\n  margin-bottom: 0 !important;\n}\n\n/* progress bar*/\n.markdown-body .progress {\n  display: block;\n  width: 300px;\n  margin: 10px 0;\n  height: 24px;\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  border-radius: 3px;\n  background-color: #ededed;\n  position: relative;\n  box-shadow: inset -1px 1px 3px rgba(0, 0, 0, .1);\n}\n\n.markdown-body .progress-label {\n  position: absolute;\n  text-align: center;\n  font-weight: bold;\n  width: 100%; margin: 0;\n  line-height: 24px;\n  color: #333;\n  text-shadow: 1px 1px 0 #fefefe, -1px -1px 0 #fefefe, -1px 1px 0 #fefefe, 1px -1px 0 #fefefe, 0 1px 0 #fefefe, 0 -1px 0 #fefefe, 1px 0 0 #fefefe, -1px 0 0 #fefefe, 1px 1px 2px #000;\n  -webkit-font-smoothing: antialiased !important;\n  white-space: nowrap;\n  overflow: hidden;\n}\n\n.markdown-body .progress-bar {\n  height: 24px;\n  float: left;\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  border-radius: 3px;\n  background-color: #96c6d7;\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), inset 0 -1px 0 rgba(0, 0, 0, .1);\n  background-size: 30px 30px;\n  background-image: -webkit-linear-gradient(\n    135deg, rgba(255, 255, 255, .4) 27%,\n    transparent 27%,\n    transparent 52%, rgba(255, 255, 255, .4) 52%,\n    rgba(255, 255, 255, .4) 77%,\n    transparent 77%, transparent\n  );\n  background-image: -moz-linear-gradient(\n    135deg,\n    rgba(255, 255, 255, .4) 27%, transparent 27%,\n    transparent 52%, rgba(255, 255, 255, .4) 52%,\n    rgba(255, 255, 255, .4) 77%, transparent 77%,\n    transparent\n  );\n  background-image: -ms-linear-gradient(\n    135deg,\n    rgba(255, 255, 255, .4) 27%, transparent 27%,\n    transparent 52%, rgba(255, 255, 255, .4) 52%,\n    rgba(255, 255, 255, .4) 77%, transparent 77%,\n    transparent\n  );\n  background-image: -o-linear-gradient(\n    135deg,\n    rgba(255, 255, 255, .4) 27%, transparent 27%,\n    transparent 52%, rgba(255, 255, 255, .4) 52%,\n    rgba(255, 255, 255, .4) 77%, transparent 77%,\n    transparent\n  );\n  background-image: linear-gradient(\n    135deg,\n    rgba(255, 255, 255, .4) 27%, transparent 27%,\n    transparent 52%, rgba(255, 255, 255, .4) 52%,\n    rgba(255, 255, 255, .4) 77%, transparent 77%,\n    transparent\n  );\n}\n\n.markdown-body .progress-100plus .progress-bar {\n  background-color: #a6d796;\n}\n\n.markdown-body .progress-80plus .progress-bar {\n  background-color: #c6d796;\n}\n\n.markdown-body .progress-60plus .progress-bar {\n  background-color: #d7c896;\n}\n\n.markdown-body .progress-40plus .progress-bar {\n  background-color: #d7a796;\n}\n\n.markdown-body .progress-20plus .progress-bar {\n  background-color: #d796a6;\n}\n\n.markdown-body .progress-0plus .progress-bar {\n  background-color: #c25f77;\n}\n\n.markdown-body .candystripe-animate .progress-bar{\n  -webkit-animation: animate-stripes 3s linear infinite;\n  -moz-animation: animate-stripes 3s linear infinite;\n  animation: animate-stripes 3s linear infinite;\n}\n\n@-webkit-keyframes animate-stripes {\n  0% {\n    background-position: 0 0;\n  }\n\n  100% {\n    background-position: 60px 0;\n  }\n}\n\n@-moz-keyframes animate-stripes {\n  0% {\n    background-position: 0 0;\n  }\n\n  100% {\n    background-position: 60px 0;\n  }\n}\n\n@keyframes animate-stripes {\n  0% {\n    background-position: 0 0;\n  }\n\n  100% {\n    background-position: 60px 0;\n  }\n}\n\n.markdown-body .gloss .progress-bar {\n  box-shadow:\n    inset 0 4px 12px rgba(255, 255, 255, .7),\n    inset 0 -12px 0 rgba(0, 0, 0, .05);\n}\n\n/* MultiMarkdown Critic Blocks */\n.markdown-body .critic_mark {\n  background: #ff0;\n}\n\n.markdown-body .critic_delete {\n  color: #c82829;\n  text-decoration: line-through;\n}\n\n.markdown-body .critic_insert {\n  color: #718c00 ;\n  text-decoration: underline;\n}\n\n.markdown-body .critic_comment {\n  color: #8e908c;\n  font-style: italic;\n}\n\n.markdown-body .headeranchor {\n  font: normal normal 16px fontawesome-mini;\n  line-height: 1;\n  display: inline-block;\n  text-decoration: none;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n\n.headeranchor:before {\n  content: '\\e157';\n}\n\n.markdown-body .task-list-item {\n  list-style-type: none;\n}\n\n.markdown-body .task-list-item+.task-list-item {\n  margin-top: 3px;\n}\n\n.markdown-body .task-list-item input {\n  margin: 0 4px 0.25em -20px;\n  vertical-align: middle;\n}\n\n.markdown-body diagram-div, .markdown-body div.uml-sequence-diagram, .markdown-body, div.uml-flowchart {\n  overflow: auto;\n}\n\n/* Media */\n@media only screen and (min-width: 480px) {\n  .markdown-body {\n    font-size:14px;\n  }\n}\n\n@media only screen and (min-width: 768px) {\n  .markdown-body {\n    font-size:16px;\n  }\n}\n\n@media print {\n  .markdown-body * {\n    background: transparent !important;\n    color: black !important;\n    filter:none !important;\n    -ms-filter: none !important;\n  }\n\n  .markdown-body {\n    font-size:12pt;\n    max-width:100%;\n    outline:none;\n    border: 0;\n  }\n\n  .markdown-body a,\n  .markdown-body a:visited {\n    text-decoration: underline;\n  }\n\n  .markdown-body .headeranchor-link {\n    display: none;\n  }\n\n  .markdown-body a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n\n  .markdown-body abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n\n  .markdown-body .ir a:after,\n  .markdown-body a[href^=\"javascript:\"]:after,\n  .markdown-body a[href^=\"#\"]:after {\n    content: \"\";\n  }\n\n  .markdown-body pre {\n    white-space: pre;\n    white-space: pre-wrap;\n    word-wrap: break-word;\n  }\n\n  .markdown-body pre,\n  .markdown-body blockquote {\n    border: 1px solid #999;\n    padding-right: 1em;\n    page-break-inside: avoid;\n  }\n\n  .markdown-body .progress,\n  .markdown-body .progress-bar {\n    -moz-box-shadow: none;\n    -webkit-box-shadow: none;\n    box-shadow: none;\n  }\n\n  .markdown-body .progress {\n    border: 1px solid #ddd;\n  }\n\n  .markdown-body .progress-bar {\n    height: 22px;\n    border-right: 1px solid #ddd;\n  }\n\n  .markdown-body tr,\n  .markdown-body img {\n    page-break-inside: avoid;\n  }\n\n  .markdown-body img {\n    max-width: 100% !important;\n  }\n\n  .markdown-body p,\n  .markdown-body h2,\n  .markdown-body h3 {\n    orphans: 3;\n    widows: 3;\n  }\n\n  .markdown-body h2,\n  .markdown-body h3 {\n    page-break-after: avoid;\n  }\n}\n\u003c/style\u003e\u003cstyle\u003e/*GitHub*/\n.highlight {background-color:#f7f7f7;color:#333333;}\n.highlight .hll {background-color:#ffffcc;}\n.highlight .c{color:#999988;font-style:italic}\n.highlight .err{color:#a61717;background-color:#e3d2d2}\n.highlight .k{font-weight:bold}\n.highlight .o{font-weight:bold}\n.highlight .cm{color:#999988;font-style:italic}\n.highlight .cp{color:#999999;font-weight:bold}\n.highlight .c1{color:#999988;font-style:italic}\n.highlight .cs{color:#999999;font-weight:bold;font-style:italic}\n.highlight .gd{color:#000000;background-color:#ffdddd}\n.highlight .ge{font-style:italic}\n.highlight .gr{color:#aa0000}\n.highlight .gh{color:#999999}\n.highlight .gi{color:#000000;background-color:#ddffdd}\n.highlight .go{color:#888888}\n.highlight .gp{color:#555555}\n.highlight .gs{font-weight:bold}\n.highlight .gu{color:#800080;font-weight:bold}\n.highlight .gt{color:#aa0000}\n.highlight .kc{font-weight:bold}\n.highlight .kd{font-weight:bold}\n.highlight .kn{font-weight:bold}\n.highlight .kp{font-weight:bold}\n.highlight .kr{font-weight:bold}\n.highlight .kt{color:#445588;font-weight:bold}\n.highlight .m{color:#009999}\n.highlight .s{color:#dd1144}\n.highlight .n{color:#333333}\n.highlight .na{color:teal}\n.highlight .nb{color:#0086b3}\n.highlight .nc{color:#445588;font-weight:bold}\n.highlight .no{color:teal}\n.highlight .ni{color:purple}\n.highlight .ne{color:#990000;font-weight:bold}\n.highlight .nf{color:#990000;font-weight:bold}\n.highlight .nn{color:#555555}\n.highlight .nt{color:navy}\n.highlight .nv{color:teal}\n.highlight .ow{font-weight:bold}\n.highlight .w{color:#bbbbbb}\n.highlight .mf{color:#009999}\n.highlight .mh{color:#009999}\n.highlight .mi{color:#009999}\n.highlight .mo{color:#009999}\n.highlight .sb{color:#dd1144}\n.highlight .sc{color:#dd1144}\n.highlight .sd{color:#dd1144}\n.highlight .s2{color:#dd1144}\n.highlight .se{color:#dd1144}\n.highlight .sh{color:#dd1144}\n.highlight .si{color:#dd1144}\n.highlight .sx{color:#dd1144}\n.highlight .sr{color:#009926}\n.highlight .s1{color:#dd1144}\n.highlight .ss{color:#990073}\n.highlight .bp{color:#999999}\n.highlight .vc{color:teal}\n.highlight .vg{color:teal}\n.highlight .vi{color:teal}\n.highlight .il{color:#009999}\n.highlight .gc{color:#999;background-color:#EAF2F5}\n\u003c/style\u003e\u003ctitle\u003eREADME\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003carticle class=\"markdown-body\"\u003e\u003cdiv align=\"center\"\u003e\n    \u003ca href=\"https://github.com/inphinit/teeny/\"\u003e\n        \u003cimg src=\"./badges/php.png\" width=\"160\" alt=\"Teeny route system for PHP\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/inphinit/teeny.js/\"\u003e\n    \u003cimg src=\"./badges/javascript.png\" width=\"160\" alt=\"Teeny route system for JavaScript (Node.js)\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/inphinit/teeny.go/\"\u003e\n    \u003cimg src=\"./badges/golang.png\" width=\"160\" alt=\"Teeny route system for Golang\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/inphinit/teeny.py/\"\u003e\n    \u003cimg src=\"./badges/python.png\" width=\"160\" alt=\"Teeny route system for Python\"\u003e\n    \u003c/a\u003e\n\u003c/div\u003e\n\n\u003ch1 id=\"teeny-route-system-for-php\"\u003eTeeny route system for PHP\u003ca class=\"headerlink\" href=\"#teeny-route-system-for-php\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003eTeeny is a micro-route system that is really micro, supports \u003cstrong\u003ePHP 5.3\u003c/strong\u003e to \u003cstrong\u003ePHP 8\u003c/strong\u003e, is extremely simple and ready to use.\u003c/p\u003e\n\u003ch2 id=\"install-using-composer\"\u003eInstall using composer\u003ca class=\"headerlink\" href=\"#install-using-composer\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eFor create your project use:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003ecomposer create-project inphinit/teeny \u0026lt;project name\u0026gt;\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eReplace \u003ccode\u003e\u0026lt;project name\u0026gt;\u003c/code\u003e by your project name, for exemple, if want create your project with \u0026ldquo;blog\u0026rdquo; name (folder name), use:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003ecomposer create-project inphinit/teeny blog\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003ch2 id=\"download-without-composer\"\u003eDownload without composer\u003ca class=\"headerlink\" href=\"#download-without-composer\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eIf is not using \u003ccode\u003ecomposer\u003c/code\u003e try direct download from \u003ca href=\"https://github.com/inphinit/teeny/releases\"\u003ehttps://github.com/inphinit/teeny/releases\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"apache-htaccess\"\u003eApache (\u003ccode\u003e.htaccess\u003c/code\u003e)\u003ca class=\"headerlink\" href=\"#apache-htaccess\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThe \u003ccode\u003e.htaccess\u003c/code\u003e will only need some adjustment if you are using it in a subfolder, you will need to change all \u003ccode\u003eErrorDocument\u003c/code\u003e. See more details in \u003ca href=\"https://httpd.apache.org/docs/2.4/custom-error.html\"\u003ehttps://httpd.apache.org/docs/2.4/custom-error.html\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eIf the address is something like \u003ccode\u003ehttps://\u0026lt;domain\u0026gt;/\u003c/code\u003e, then do:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"nb\"\u003eErrorDocument\u003c/span\u003e \u003cspan class=\"m\"\u003e403\u003c/span\u003e \u003cspan class=\"sx\"\u003e/index.php/RESERVED.TEENY-403.html\u003c/span\u003e\n\u003cspan class=\"nb\"\u003eErrorDocument\u003c/span\u003e \u003cspan class=\"m\"\u003e500\u003c/span\u003e \u003cspan class=\"sx\"\u003e/index.php/RESERVED.TEENY-500.html\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eIf the address is something like \u003ccode\u003ehttps://\u0026lt;domain\u0026gt;/foo/\u003c/code\u003e, then do:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"nb\"\u003eErrorDocument\u003c/span\u003e \u003cspan class=\"m\"\u003e403\u003c/span\u003e \u003cspan class=\"sx\"\u003e/foo/index.php/RESERVED.TEENY-403.html\u003c/span\u003e\n\u003cspan class=\"nb\"\u003eErrorDocument\u003c/span\u003e \u003cspan class=\"m\"\u003e500\u003c/span\u003e \u003cspan class=\"sx\"\u003e/foo/index.php/RESERVED.TEENY-500.html\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eIf the address is something like \u003ccode\u003ehttps://\u0026lt;domain\u0026gt;/foo/bar/\u003c/code\u003e, then do:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"nb\"\u003eErrorDocument\u003c/span\u003e \u003cspan class=\"m\"\u003e403\u003c/span\u003e \u003cspan class=\"sx\"\u003e/foo/bar/index.php/RESERVED.TEENY-403.html\u003c/span\u003e\n\u003cspan class=\"nb\"\u003eErrorDocument\u003c/span\u003e \u003cspan class=\"m\"\u003e500\u003c/span\u003e \u003cspan class=\"sx\"\u003e/foo/bar/index.php/RESERVED.TEENY-500.html\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003ch2 id=\"nginx\"\u003eNGINX\u003ca class=\"headerlink\" href=\"#nginx\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eFor NGINX you can use \u003ca href=\"https://nginx.org/en/docs/http/ngx_http_core_module.html#try_files\"\u003e\u003ccode\u003etry_files\u003c/code\u003e\u003c/a\u003e in Nginx. See a example:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003elocation / {\n    root /home/foo/bar/teeny;\n\n    # Redirect page errors to route system\n    error_page 403 /index.php/RESERVED.TEENY-403.html;\n    error_page 500 /index.php/RESERVED.TEENY-500.html;\n\n    try_files /public$uri /index.php?$query_string;\n\n    location = / {\n        try_files $uri /index.php?$query_string;\n    }\n\n    location ~ /\\. {\n        try_files /index.php$uri /index.php?$query_string;\n    }\n\n    location ~ \\.php$ {\n        # Replace by your FPM or FastCGI\n        fastcgi_pass 127.0.0.1:9000;\n\n        fastcgi_index index.php;\n        include fastcgi_params;\n\n        set $teeny_suffix \u0026quot;\u0026quot;;\n\n        if ($uri != \u0026quot;/index.php\u0026quot;) {\n            set $teeny_suffix \u0026quot;/public\u0026quot;;\n        }\n\n        fastcgi_param SCRIPT_FILENAME $realpath_root$teeny_suffix$fastcgi_script_name;\n    }\n}\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eNote:\u003c/strong\u003e For FPM use \u003ccode\u003efastcgi_pass unix:/var/run/php/php\u0026lt;version\u0026gt;-fpm.sock\u003c/code\u003e (replace \u003ccode\u003e\u0026lt;version\u0026gt;\u003c/code\u003e by PHP version in your server)\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"built-in-web-server\"\u003eBuilt-in web server\u003ca class=\"headerlink\" href=\"#built-in-web-server\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eYou can use \u003ca href=\"https://www.php.net/manual/en/features.commandline.webserver.php\"\u003ebuilt-in server\u003c/a\u003e to facilitate the development, Teeny provides the relative static files, which will facilitate the use, example of use (navigate to project folder using \u003ccode\u003ecd\u003c/code\u003e command):\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003ephp -S localhost:8080 -t public index.php\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eYou can edit the \u003ccode\u003eserver.bat\u003c/code\u003e (Windows) or \u003ccode\u003eserver\u003c/code\u003e (Linux or macOS) files to make it easier to start the project with a simple command\u003c/p\u003e\n\u003ch3 id=\"windows-serverbat-file\"\u003eWindows (server.bat file)\u003ca class=\"headerlink\" href=\"#windows-serverbat-file\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eConfigure the \u003ccode\u003eserver.bat\u003c/code\u003e variables according to your environment:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"k\"\u003eset\u003c/span\u003e \u003cspan class=\"nv\"\u003ePHP_BIN\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003eC:\\php\\php.exe\n\u003cspan class=\"k\"\u003eset\u003c/span\u003e \u003cspan class=\"nv\"\u003ePHP_INI\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003eC:\\php\\php.ini\n\n\u003cspan class=\"k\"\u003eset\u003c/span\u003e \u003cspan class=\"nv\"\u003eHOST_ADDR\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003elocalhost\n\u003cspan class=\"k\"\u003eset\u003c/span\u003e \u003cspan class=\"nv\"\u003eHOST_PORT\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"m\"\u003e9000\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eOnce configured, you can navigate to the project folder and run the command that will start built-in server, see an example:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"k\"\u003ecd\u003c/span\u003e c:\\projets\\blog\nserver\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003ch3 id=\"linux-and-macos-server-file\"\u003eLinux and macOS (server file)\u003ca class=\"headerlink\" href=\"#linux-and-macos-server-file\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eConfigure the \u003ccode\u003e./server\u003c/code\u003e variables according to your environment:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"nv\"\u003ePHP_BIN\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e/usr/bin/php\n\u003cspan class=\"nv\"\u003ePHP_INI\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e/etc/php.ini\n\n\u003cspan class=\"nv\"\u003eHOST_ADDR\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003elocalhost\n\u003cspan class=\"nv\"\u003eHOST_PORT\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e9000\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eOnce configured, you can navigate to the project folder and run the command that will start built-in server, see an example:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"nb\"\u003ecd\u003c/span\u003e ~/projets/blog\n./server\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003ch2 id=\"api\"\u003eAPI\u003ca class=\"headerlink\" href=\"#api\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eMethods from \u003ccode\u003eTeeny\u003c/code\u003e class\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eMethod\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eTeeny::path(): string\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eGet current path from URL (ignores subfolders if it is located in a subfolder on your webserver)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eTeeny::path() : string\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eGet current path from application\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eTeeny::status([int $code]): int\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eGet or set HTTP status code\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eTeeny::action($methods, string $path, mixed $callback): void\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eRegister a callback or script for a route\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eTeeny::setPattern(string $pattern, string $regex): void\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eAdd or replace a pattern for custom routes, like \u003ccode\u003e/foo/\u0026lt;variable1:pattern\u0026gt;\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eTeeny::handlerCodes(array $codes, mixed $callback): int\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eHandler HTTP status code\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eTeeny::exec(): bool\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eExecute application\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"add-and-remove-routes\"\u003eAdd and remove routes\u003ca class=\"headerlink\" href=\"#add-and-remove-routes\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eFor create a new route in \u003ccode\u003eindex.php\u003c/code\u003e put like this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"x\"\u003e$app-\u0026gt;action(\u0026#39;GET\u0026#39;, \u0026#39;/myroute\u0026#39;, function () {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    echo \u0026#39;Test!\u0026#39;;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e});\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eYou can use \u003ccode\u003ereturn\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"x\"\u003e$app-\u0026gt;action(\u0026#39;GET\u0026#39;, \u0026#39;/myroute\u0026#39;, function () {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    return \u0026#39;Test!\u0026#39;;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e});\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eFor remove a route use \u003ccode\u003enull\u003c/code\u003e value, like this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"x\"\u003e$app-\u0026gt;action(\u0026#39;GET\u0026#39;, \u0026#39;/myroute\u0026#39;, null);\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003ch2 id=\"route-include-file\"\u003eRoute include file\u003ca class=\"headerlink\" href=\"#route-include-file\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eFor include a file uses like this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"x\"\u003e$app-\u0026gt;action(\u0026#39;GET\u0026#39;, \u0026#39;/myroute\u0026#39;, \u0026#39;foo/bar/test.php\u0026#39;);\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eIf \u003ccode\u003efoo/bar/test.php\u003c/code\u003e not found in project will display the following error:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003eWarning: require(foo/bar/test.php): failed to open stream: No such file or directory in /home/user/blog/vendor/teeny.php on line 156\n\nFatal error: require(): Failed opening required \u0026#39;foo/bar/test.php\u0026#39; (include_path=\u0026#39;.\u0026#39;) /home/user/blog/vendor/teeny.php on line 156\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003ch2 id=\"http-status\"\u003eHTTP status\u003ca class=\"headerlink\" href=\"#http-status\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eFor retrieve HTTP status from SAPI (Apache, Ngnix, IIS) or previously defined in the script itself use like this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"x\"\u003e$var = $app-\u0026gt;status();\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eFor retrieve into a route use like this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"x\"\u003e$app-\u0026gt;action(\u0026#39;GET\u0026#39;, \u0026#39;/myroute\u0026#39;, function () use ($app) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    echo \u0026#39;HTTP status: \u0026#39;, $app-\u0026gt;status();\u003c/span\u003e\n\u003cspan class=\"x\"\u003e});\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eFor set a new HTTP status use like this (eg.: emit 404 Not Found):\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"x\"\u003e$app-\u0026gt;status(404);\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eFor set into route use like this (a example with condition/if):\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"x\"\u003e$app-\u0026gt;action(\u0026#39;GET\u0026#39;, \u0026#39;/report\u0026#39;, function () use ($app) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    $file = \u0026#39;data/foo.csv\u0026#39;;\u003c/span\u003e\n\n\u003cspan class=\"x\"\u003e    if (is_file($file)) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e        header(\u0026#39;Content-Type: text/csv\u0026#39;);\u003c/span\u003e\n\u003cspan class=\"x\"\u003e        readfile($file);\u003c/span\u003e\n\u003cspan class=\"x\"\u003e        /**\u003c/span\u003e\n\u003cspan class=\"x\"\u003e         * Note: this is just an example, about sending a file,\u003c/span\u003e\n\u003cspan class=\"x\"\u003e         * if possible use \u0026quot;X-Sendfile\u0026quot; or equivalent\u003c/span\u003e\n\u003cspan class=\"x\"\u003e         */\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    } else {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e        $app-\u0026gt;status(404);\u003c/span\u003e\n\n\u003cspan class=\"x\"\u003e        echo \u0026#39;Report not found\u0026#39;;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    }\u003c/span\u003e\n\u003cspan class=\"x\"\u003e});\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003ch2 id=\"named-params-in-route\"\u003eNamed params in route\u003ca class=\"headerlink\" href=\"#named-params-in-route\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eYou can use params like this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"x\"\u003e$app-\u0026gt;action(\u0026#39;GET\u0026#39;, \u0026#39;/user/\u0026lt;user\u0026gt;\u0026#39;, function ($params) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    var_dump($params);\u003c/span\u003e\n\u003cspan class=\"x\"\u003e});\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eIf access a URL like this \u003ccode\u003ehttp://mywebsite/user/mary\u003c/code\u003e returns:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"x\"\u003earray(2) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e  [\u0026quot;user\u0026quot;]=\u0026gt;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e  string(3) \u0026quot;mary\u0026quot;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e}\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eAnother example:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"x\"\u003e$app-\u0026gt;action(\u0026#39;GET\u0026#39;, \u0026#39;/article/\u0026lt;name\u0026gt;-\u0026lt;id\u0026gt;\u0026#39;, function ($params) use ($app) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    // Only ID numerics are valids\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    if (ctype_digit($params[\u0026#39;id\u0026#39;])) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e        echo \u0026#39;Article ID: \u0026#39;, $params[\u0026#39;id\u0026#39;], \u0026#39;\u0026lt;br\u0026gt;\u0026#39;;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e        echo \u0026#39;Article name: \u0026#39;, $params[\u0026#39;name\u0026#39;];\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    } else {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e        $app-\u0026gt;status(400);\u003c/span\u003e\n\n\u003cspan class=\"x\"\u003e        echo \u0026#39;Invalid URL\u0026#39;;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    }\u003c/span\u003e\n\u003cspan class=\"x\"\u003e});\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eIf access a URL like this \u003ccode\u003ehttp://mywebsite/article/mary-1000\u003c/code\u003e returns:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003eArticle ID: mary\nArticle name: 1000\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003ch2 id=\"supported-types-for-named-parameters-in-routes\"\u003eSupported types for named parameters in routes\u003ca class=\"headerlink\" href=\"#supported-types-for-named-parameters-in-routes\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eAn example, only numeric id are valids:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"x\"\u003e$app-\u0026gt;action(\u0026#39;GET\u0026#39;, \u0026#39;/article/\u0026lt;name\u0026gt;-\u0026lt;id:num\u0026gt;\u0026#39;, function ($params) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    echo \u0026#39;Article ID: \u0026#39;, $params[\u0026#39;id\u0026#39;], \u0026#39;\u0026lt;br\u0026gt;\u0026#39;;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    echo \u0026#39;Article name: \u0026#39;, $params[\u0026#39;name\u0026#39;];\u003c/span\u003e\n\u003cspan class=\"x\"\u003e});\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eType\u003c/th\u003e\n\u003cth\u003eExample\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ealnum\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e$app-\u0026gt;action('GET', '/baz/\u0026lt;video:alnum\u0026gt;', ...);\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eOnly accepts parameters with alpha-numeric format and \u003ccode\u003e$params\u003c/code\u003e returns \u003ccode\u003earray( video =\u0026gt; ...)\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ealpha\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e$app-\u0026gt;action('GET', '/foo/bar/\u0026lt;name:alpha\u0026gt;', ...);\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eOnly accepts parameters with alpha format and \u003ccode\u003e$params\u003c/code\u003e returns \u003ccode\u003earray( name =\u0026gt; ...)\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003edecimal\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e$app-\u0026gt;action('GET', '/baz/\u0026lt;price:decimal\u0026gt;', ...);\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eOnly accepts parameters with decimal format and \u003ccode\u003e$params\u003c/code\u003e returns \u003ccode\u003earray( price =\u0026gt; ...)\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003enum\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e$app-\u0026gt;action('GET', '/foo/\u0026lt;id:num\u0026gt;', ...);\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eOnly accepts parameters with integer format and \u003ccode\u003e$params\u003c/code\u003e returns \u003ccode\u003earray( id =\u0026gt; ...)\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003enospace\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e$app-\u0026gt;action('GET', '/foo/\u0026lt;nospace:nospace\u0026gt;', ...);\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eAccepts any characters expcet spaces, like white-spaces (\u003ccode\u003e%20\u003c/code\u003e), tabs (\u003ccode\u003e%0A\u003c/code\u003e) and others (see about \u003ccode\u003e\\S\u003c/code\u003e in regex)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003euuid\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e$app-\u0026gt;action('GET', '/bar/\u0026lt;barcode:alnum\u0026gt;', ...);\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eOnly accepts parameters with uuid format and \u003ccode\u003e$params\u003c/code\u003e returns \u003ccode\u003earray( barcode =\u0026gt; ...)\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eversion\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e$app-\u0026gt;action('GET', '/baz/\u0026lt;api:version\u0026gt;', ...);\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eOnly accepts parameters with \u003ca href=\"https://semver.org/spec/v2.0.0.html\"\u003esemversion (v2)\u003c/a\u003e format and \u003ccode\u003e$params\u003c/code\u003e returns \u003ccode\u003earray( api =\u0026gt; ...)\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eFor add new patterns use like this \u003ccode\u003eTeeny::setPattern()\u003c/code\u003e, examples:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"x\"\u003e$app-\u0026gt;setPattern(\u0026#39;example\u0026#39;, \u0026#39;[A-Z]\\d+\u0026#39;);\u003c/span\u003e\n\n\u003cspan class=\"x\"\u003e$app-\u0026gt;action(\u0026#39;GET\u0026#39;, \u0026#39;/custom/\u0026lt;myexample:example\u0026gt;\u0026#39;, function ($params) use ($app) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    echo \u0026#39;\u0026lt;h1\u0026gt;custom pattern\u0026lt;/h1\u0026gt;\u0026#39;;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    echo \u0026#39;\u0026lt;pre\u0026gt;\u0026#39;;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    print_r($params);\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    echo \u0026#39;\u0026lt;/pre\u0026gt;\u0026#39;;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e});\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eAnd for access this route exemple use \u003ccode\u003ehttp://mysite/test/A00001\u003c/code\u003e or \u003ccode\u003ehttp://mysite/test/C02\u003c/code\u003e, start with upper-case letter and after width a integer number\u003c/p\u003e\n\u003ch2 id=\"dealing-with-large-files\"\u003eDealing with large files\u003ca class=\"headerlink\" href=\"#dealing-with-large-files\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eTo work with large files you can choose to use the following server modules:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eModule\u003c/th\u003e\n\u003cth\u003eServer\u003c/th\u003e\n\u003cth\u003eDocumentation\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eX-Sendfile\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eApache\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://tn123.org/mod_xsendfile/\"\u003ehttps://tn123.org/mod_xsendfile/\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eX-Accel-Redirect\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eNGINX\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/\"\u003ehttps://www.nginx.com/resources/wiki/start/topics/examples/x-accel/\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eX-LIGHTTPD-send-file\u003c/code\u003e and \u003ccode\u003eX-Sendfile2\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eLighttpd\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://redmine.lighttpd.net/projects/1/wiki/X-LIGHTTPD-send-file\"\u003ehttps://redmine.lighttpd.net/projects/1/wiki/X-LIGHTTPD-send-file\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eA simple implementation:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan class=\"x\"\u003e$software = $_SERVER[\u0026#39;SERVER_SOFTWARE\u0026#39;];\u003c/span\u003e\n\u003cspan class=\"x\"\u003e$send = null;\u003c/span\u003e\n\n\u003cspan class=\"x\"\u003eif (stripos($software, \u0026#39;apache\u0026#39;) !== false) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    $send = \u0026#39;X-Sendfile\u0026#39;;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e} else if (stripos($software, \u0026#39;nginx\u0026#39;) !== false) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    $send = \u0026#39;X-Accel-Redirect\u0026#39;;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e} else if (stripos($software, \u0026#39;lighttpd\u0026#39;) !== false) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    $send = \u0026#39;X-LIGHTTPD-send-file\u0026#39;;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"x\"\u003e$app-\u0026gt;action(\u0026#39;GET\u0026#39;, \u0026#39;/download\u0026#39;, function () use ($sendHeader) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    $file = \u0026#39;/protected/iso.img\u0026#39;;\u003c/span\u003e\n\n\u003cspan class=\"x\"\u003e    if ($send) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e        header($send . \u0026#39;: \u0026#39; . $file);\u003c/span\u003e\n\u003cspan class=\"x\"\u003e        return;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    }\u003c/span\u003e\n\n\u003cspan class=\"x\"\u003e    if ($handle = fopen($file, \u0026#39;r\u0026#39;)) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e        $app-\u0026gt;status(500);\u003c/span\u003e\n\u003cspan class=\"x\"\u003e        return \u0026#39;Failed to read file\u0026#39;;\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    }\u003c/span\u003e\n\n\u003cspan class=\"x\"\u003e    // fallback (this is just an example)\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    $length = 2097152;\u003c/span\u003e\n\n\u003cspan class=\"x\"\u003e    header(\u0026#39;Content-Disposition: attachment; filename=\u0026quot;iso.img\u0026quot;\u0026#39;);\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    header(\u0026#39;Content-Length: \u0026#39; . filesize($file));\u003c/span\u003e\n\n\u003cspan class=\"x\"\u003e    while (!feof($handle)) {\u003c/span\u003e\n\u003cspan class=\"x\"\u003e        echo fgets($handle, $length);\u003c/span\u003e\n\u003cspan class=\"x\"\u003e        flush();\u003c/span\u003e\n\u003cspan class=\"x\"\u003e    }\u003c/span\u003e\n\n\u003cspan class=\"x\"\u003e    fclose($handle);\u003c/span\u003e\n\u003cspan class=\"x\"\u003e});\u003c/span\u003e\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003ch2 id=\"serving-public-files-and-scripts\"\u003eServing public files (and scripts)\u003ca class=\"headerlink\" href=\"#serving-public-files-and-scripts\" title=\"Permanent link\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eTo serve public files (or scripts) you must add them to the public folder. The prefix \u003ccode\u003e/public/*\u003c/code\u003e will not be displayed in the URL, for example, if there is a file like \u003ccode\u003epublic/foobar.html\u003c/code\u003e, then the user will simply access the address \u003ccode\u003ehttps://\u0026lt;domain\u0026gt;/foobar.html\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eSubfolders will also work, if it has a file like \u003ccode\u003epublic/foo/bar/baz/video.webm\u003c/code\u003e then the user should go to \u003ccode\u003ehttps://\u0026lt;domain\u0026gt;/foo/bar/baz/video.webm\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eYou can add PHP scripts, and they will be executed normally, if you have a script like \u003ccode\u003epublic/sample/helloworld.php\u003c/code\u003e, just access \u003ccode\u003ehttps://\u0026lt;domain\u0026gt;/sample/helloworld.php\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eIf you want to make a blog available, such as Wordpress, you must also place it inside the folder, an example of structure:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e├─── .htaccess\n├─── index.php\n├─── composer.json\n├─── vendor/\n└─── public/\n     ├─── helloword.html\n     └─── blog/\n          ├─── .htaccess\n          ├─── index.php\n          ├─── wp-activate.php\n          ├─── wp-blog-header.php\n          ├─── wp-comments-post.php\n          ├─── wp-config-sample.php\n          ├─── wp-config.php\n          ├─── wp-cron.php\n          ├─── wp-links-opml.php\n          ├─── wp-load.php\n          ├─── wp-login.php\n          ├─── wp-mail.php\n          ├─── wp-settings.php\n          ├─── wp-signup.php\n          ├─── wp-trackback.php\n          ├─── xmlrpc.php\n          ├─── wp-admin/\n          ├─── wp-content/\n          └─── wp-includes/\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp\u003eAnd then just access \u003ccode\u003ehttps://\u0026lt;domain\u0026gt;/blog/\u003c/code\u003e. Other samples:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003ehttps://\u0026lt;domain\u0026gt;/blog/wp-admin/\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ehttps://\u0026lt;domain\u0026gt;/blog/2021/03/24/astronomy-messier-87-black-hole/\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ehttps://\u0026lt;domain\u0026gt;/blog/2023/04/17/researchers-discover-small-galaxy/\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr /\u003e\n\u003cp\u003eIf you need more features you can experience the \u003cstrong\u003eInphinit PHP framework\u003c/strong\u003e: \u003ca href=\"https://inphinit.github.io/\"\u003ehttps://inphinit.github.io/\u003c/a\u003e\u003c/p\u003e\u003c/article\u003e\u003c/body\u003e\u003c/html\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finphinit%2Fteeny","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finphinit%2Fteeny","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finphinit%2Fteeny/lists"}