Yesod (web framework)
Yesod is a free and open-source web framework based on Haskell for productive development of type-safe, REST model based, high performance web applications, developed by Michael Snoyman et al.
Yesod is based on templates, to generate instances for listed entities, and dynamic content process functions, through Template Haskell constructs to host eDSL content templates called QuasiQuotes, where the content is translated into code expressions by metaprogramming instructions.
There are also web-like language snippet templates that admit code expression interpolations, making them fully type-checked at compile-time.
Yesod divides its functionality in separate libraries, so you may choose your functionality library of your choice.
MVC architecture
Controller
Server interface
Yesod uses a Web application interface API, abbreviated WAI, to isolate servlets, aka web apps., from servers, with handlers for the server protocols CGI, FastCGI, SCGI, Warp, Launch,The ''foundation'' type
See ref. Yesod requires a data type that instantiates the controller classes. This is called the foundation type. In the example below, it is named "MyApp".The REST model identifies a web resource with a web path. Here REST resources are given names with an R suffix and are listed in a parseRoutes site map description template. From this list, route names and dispatch handler names are derived.
Yesod makes use of Template Haskell metaprogramming to generate code from templates at compile time, assuring that the names in the templates match and everything typechecks.
By inserting a mkYesod call, this will call Template Haskell primitives to generate the code corresponding to the route type members, and the instances of the dispatch controller classes as to dispatch GET calls to route HomeR to a routine named composing them both as "getHomeR", expecting an existing handler that matches the name.
Hello World
"Hello world" example based on a CGI server interface :import "wai" Network.Wai
import "wai-extra" Network.Wai.Handler.CGI -- interchangeable WAI handler
import "yesod" Yesod
import "yesod-core" Yesod.Handler
import "text" Data.Text
import "shakespeare" Text.Cassius
-- the Foundation type
data MyApp = MyApp
-- sitemap template, listing path, resource name and methods accepted
-- `mkYesod` takes the foundation type name as param. for name composition of dispatch functions
mkYesod "MyApp" → CssUrl url
myStyle paramStyle =
→ colorBlack
_ → Color 0 0 255
-- indentation structured HTML template
myHtml :: → HtmlUrl url
myHtml params =
Hello World! There are
$if null params
Nothing to list
$else
- #: #
getHomeR :: Handler RepHtml
getHomeR = do
req <- getRequest
let params = reqGetParams req
paramStyle <- lookupGetParams "style"
defaultLayout $ do
-- adding widgets to the Widget monad
setTitle "Yesod example"
toWidgetHead $ myStyle paramStyle
toWidgetBody $ myHtml params
-- there are run function variants for different WAI handlers
main = toWaiApp MyApp >>= run- cgi test
export REQUEST_METHOD=GET
export PATH_INFO=/
export QUERY_STRING='p1=abc;p2=def;style=high-contrast'
./wai-cgi-helloResources, routes and REpresentational State Transfer model of access to [web documents">HTTP method handlers
See ref.
Yesod follows the REpresentational State Transfer model of access to [web documents, identifying docs. and directories as resources with a Route constructor, named with an uppercase R suffix.
;The routes table: The parseRoutes template should list the resources specifying route pieces, resource name and dispatch methods to be accepted.
URL segment capture as parameter is possible specifying a '#' prefix for single segment capture or '*' for multisegment capture, followed by the parameter type.
-- given a MyApp foundation type
mkYesod "MyApp"- Applying the previous template generates the following route constructors:
data Route MyApp =
HomeR -- referenced in templates as: @
| BlogR -- in templates: @
| ArticleR ArticleId -- in templates: @
| BranchR Texts -- in templates: @- For every supported HTTP method a handler function must be created to match the dispatch names generated by mkYesod from the parseRoutes template, by prefixing the method name to the resource, as described :
handler''
-- for "/ HomeR" -- no http methods stated ⇒ only one handler with prefix
handlerHomeR :: HasReps t ⇒ Handler t
-- for "/blog BlogR GET POST"
getBlogR :: HasReps t ⇒ Handler t
postBlogR :: HasReps t ⇒ Handler t
-- for "/article/#ArticleId ArticleR GET PUT"
getArticleR :: HasReps t ⇒ ArticleId → Handler t
putArticleR :: HasReps t ⇒ ArticleId → Handler tRequest data, Parameters, Cookies, Languages and other Header info
See ref.Authentication and authorization
See ref. Authentication plugins: OpenId, BrowserId, Email, GoogleEmail, HashDB, RpxNow.Sessions
See ref. Session back-ends: ClientSession, ServerSessionSession messages
A success, failure or indicative message can be stored in the Session and will be shown, if it exists, by the default_layout routine through thedefault_layout.hamlet
template, being cleared on consultation.Subsites
Common URL prefix subsites for workflows, file serving or site partitioning. See ref.
Built-in subsites: Static, AuthForm processing and layout generation
See ref.
The Form type here is an object that is used in the controller to parse and process the form fields user input and produce a pair were the widget holds the layout of the next rendering of the form with error messages and marks. It can also be used to generate a new form with blanks or default values.
The form type takes the shape of a function of an html snippet to be embedded in the view, that will hold security purpose hidden fields.
A form object is generated from an Applicative/Monadic composition of fields for a combined/sequential parsing of field inputs.
There are three types of forms:- Applicative,
- Monadic, both in the Yesod.Form.Functions module,
- Input in the Yesod.Form.Input module.
followed by
, have a fieldParse component and a fieldView one.
- the function runForm runs the field parsers against the form field inputs and generates a pair from the views offering a new form widget with the received form field values as defaults. The function suffix is the http method used in the form submission.
- while generateForm ignores inputs from the client and generates a blank or defaults form widget.
The magic is in the FormResult data type Applicative instance, where collects the error messages for the case ofFormFailure
result values
Monadic forms permit free form layout and better treatment of hiddenField members.
A sample of an Applicative form:
-- a record for our form fields
data Person = Person
-- the Form type has an extra parameter for an html snippet to be embedded, containing a CSRF token hidden field for security
type Form sub master x = Html → MForm sub master
personForm :: MyFoundationType → → Maybe Person → Form sub master Person
personForm master languages mbPersonDefaults = renderTable $
Person <$> areq textField fldSettingsName mbNameDefault
<*> areq customPersonAgeField fldSettingsAge mbAgeDefault
<*> aopt textareaField fldSettingsLikings mbLikingsDefault
where
mbNameDefault = fmap personName mbPersonDefaults
mbAgeDefault = fmap personAge mbPersonDefaults
mbLikingsDefault = fmap personLikings mbPersonDefaults
-- "fieldSettingsLabel" returns an initial fieldSettings record
-- recently the "FieldSettings" record can be defined from a String label since it implements IsString
fldSettingsName =
fldSettingsAge = fieldSettingsLabel MsgAge
fldSettingsLikings =
customPersonAgeField = check validateAge intField
validateAge y
| y < 18 = Left $ renderMessage master languages MsgUnderAge
| otherwise = Right yView
The types shown correspond to an older version, but the philosophy remains.
The Handler monad returns content in one or more of several formats as components of types that implement the HasReps class. Json examples:
The HasReps default implementation of chooseRep chooses the document representation to be returned according to the preferred content-type list of the client accept header.- Widgets are HTML DOM code snippets made by specific commands or from templates of structure / behaviour / style, whose types instantiate the classes ToWidget, ToWidgetHead or ToWidgetBody.
Indentation based templates for tree structured markup
- the hamlet quasiquoter specified in the T.H. Oxford brackets syntax
introduces an indentation based structured html template..
Automatic closing tags are generated only for the tag at line start position.- the whamlet quasiquoter returns a Widget expression..
toWidget
$doctype 5
# - My Site<br> <link rel=stylesheet href=@><br> <body><br> <header><br> ^<br> <section #mySectionId><br> <p><span.titleClass>_</span><br> $if null articles<br> <p :isRed:style="color:red">_<br> $else<br> <ul><br> $forall art <- articles<br> <li>#.- #<br> <footer><br> ^<br></syntaxhighlight><h5>Template interpolation - ''Shakespearean templates''</h5>See ref.<br>These are content view templates that follow a common substitution pattern of code expressions within curly brackets with different character prefix to <a href="/wiki/Refer_to%3C%2Fa%3E_%3Cbr%3E%3B_template_expressions_with_%3Ccode%3E%5E%3C%2Fcode%3E%3A_refers_to_other_templates_of_the_same_type%2C_with_given_parameters_as_%3Ccode%3E%5E%3C%2Fcode%3E%2C%3Cbr%3E%3B_route_expressions_with_%3Ccode%3E%40%3C%2Fcode%3E%3A_safe_urls_as_%3Ccode%3E%40%3C%2Fcode%3E%2C%3Cbr%3E%3B_message_expressions_with_%3Ccode%3E_%3C%2Fcode%3E%3A_%5Bi18n">refer to</a> <br>; template expressions with <code>^</code>: refers to other templates of the same type, with given parameters as <code>^</code>,<br>; route expressions with <code>@</code>: safe urls as <code>@</code>,<br>; message expressions with <code>_</code>: [i18n</a> message rendering as <code>_</code><br>; other Haskell expressions with <code>#</code>: haskell expression rendering as <code>#</code> which type must be convertible<br><ul><li>* in case of <i>hamlet</i> html templates, the expression type must be an instance of Text.Blaze.ToMarkup</li><li>* in case of <a href="/wiki/Css">css</a> templates, the expression type must be an instance of Text.Cassius.ToCss</li><li>* in case of <a href="/wiki/JavaScript">JavaScript</a> templates, the expression type must be an instance of Text.Julius.ToJavascript </li><li>* in case of i18n message definitions with parameter interpolations, the expression type must be an instance of Text.Shakespeare.I18N.ToMessage </li><li>* in case of text/plain templates, the expression type must be an instance of Text.Shakespeare.Text.ToText </li></ul>Using non-English text in expressions requires use of the Unicode-aware type <i>Text</i>, since GHC's <i>show</i> for the type <i>String</i> renders non-ASCII characters as escaped numerical codes.<br>; External file templates:<br><ul><li> at compile time: Template content can be loaded from external files using compile time <i>splice</i> calls as <i>$</i>.</li><li> at run time: There is a <i>reload mode</i> for reparsing external template files at every service call, <a href="/wiki/Except_for">except for</a> HTML <i>hamlet</i> templates: See doc.<h5>Other templates</h5></li></ul>; for JavaScript, <a href="/wiki/CoffeeScript">CoffeeScript</a>, Roy: the <i>julius</i> quasiquoter: introduces a JavaScript template. JavaScript variants CoffeeScript and Roy-language have also specific <i>quasiquoters</i>.<br>;for CSS:<br><ul><li> the <i>cassius</i> quasiquoter: introduces a css template with indentation based structuring.</li><li> the <i>lucius</i> quasiquoter: introduces a css template with standard syntax plus shakespeare-template style substitutions.</li></ul>; <a href="/wiki/TypeScript">TypeScript</a> and <a href="/wiki/React_%28JavaScript_library%29">JSX</a> templates: the <i>tsc</i> and <i>tscJSX</i> quasiquoters. Only on <a href="/wiki/UNIX">UNIX</a> derivatives.<br>; text/plain templates: for <a href="/wiki/E-mail">e-mail</a> or <i>text/plain</i> http <a href="/wiki/Content_type">content type</a>.<br><ol><li>templates: <i>lt</i>: lazy text, <i>st</i>: strict text</li><li>templates for text with a <a href="/wiki/Left_margin">left margin</a> delimiter '|': <i>lbt</i>, <i>sbt</i><h4>Localizable messages</h4></li></ol>See ref.<br>Yesod app messages are localizable. They should be held within the <i>messages</i> folder, in files named based on <a href="/wiki/International_Organization_for_Standardization">ISO</a>, as <i><iso-language>.msg</i><br>Message entries follow the <a href="/wiki/Extended_Backus%E2%80%93Naur_form">EBNF</a> pattern:<br><syntaxhighlight lang="hs"><br>-- EBNF: identifier,, ":", text with interpolations<br>ArticleUnexistent param@Int64 : unexistent article #<br></syntaxhighlight><br><ul><li> message constructors are formed prepending "Msg" to the message label identifier.</li><li> the message datatype is formed appending "Message" to the foundation type name.</li></ul><syntaxhighlight lang="hs"><br>-- <a href="/wiki/In_code">in code</a><br>myMsg :: MyAppMessage -- datatype appending "Message" to the foundation type<br>myMsg = MsgArticleUnexistent myArticleId -- constructor prepending "Msg" to the msg. label<br> <br>-- in widget templates<br> _ <br></syntaxhighlight><br>Actual i18n support is missing from the <i>stack</i> app template. You have to add the <code>mkMessage "MyApp" messagesFolder isoLangDefault</code> to the "Foundation.hs" file to get the messages instantiated.<h4>Navigation <a href="/wiki/Breadcrumb_%28navigation%29">Breadcrumbs</a></h4><ul><li> Navigation Breadcrumbs. You have to provide a YesodBreadcrumbs instance for the site where the generator function <i>breadcrumb</i> should return for each route a title and parent one. Then, the query function <i>breadcrumbs</i> will return the present route title and the ancestors' pairs.<h4>Search engine XML Sitemap</h4></li><li> <a href="/wiki/Search_engines">Search engines</a> <a href="/wiki/Sitemap">XML Sitemaps</a>, where <i>sitemap</i> returns an XML Sitemap as http response, with the routes we want the search engines to crawl, and attributes to instruct the crawler, from a provided list of <i>SitemapUrl</i> records.<h4><a href="/wiki/Web_feed">Web feed</a> views</h4></li><li> Web feed views. You have handlers that return RepRss, RepAtom, or dual RepAtomRss content from a given <i>Feed</i> structure.<h3>Model</h3></li></ul><h4>Using in-memory mutable data (in the foundation datatype)</h4>E.g. a visitor count. See ref.<h4>The Database layer</h4><ul><li> <i>persistent</i> is the name of the database access layer with templates for generating types for entities and keys as well as schema initialization.</li></ul>There is first class support for <a href="/wiki/PostgreSQL">PostgreSQL</a>, <a href="/wiki/SQLite">SQLite</a>, <a href="/wiki/MongoDB">MongoDB</a>, <a href="/wiki/CouchDB">CouchDB</a> and <a href="/wiki/MySQL">MySQL</a>, with experimental support for <a href="/wiki/Redis">Redis</a>.<br>The Database layout is described in a template listing the entities, fields and constraints.<br><ul><li> For every entity listed, an integer key column "id" is generated with autoincrement and primary index attributes, with <a href="/wiki/A_type">a type</a> alias appending Id to the entity name</li><li> For every entity listed, a <a href="/wiki/Record_type">record type</a> named as the entity is generated were record fields names are composed prefixing the entity name to the field name like "personName". An EntityField type "PersonName" is also generated for foreign key referencing from other entities.</li><li> There is an automatic <i>database <a href="/wiki/Schema_migration">schema migration</a></i> mechanism for DB schema updates, which, to succeed, requires, when adding columns to existent tables, to specify 'Default-column-value constraints<i> with </i>sql level notation<i>.</li><li> "At most one" cardinality has a special mechanism around the type Checkmark.</li><li> Weak entities have no special support for cascade delete </i>triggers<i>, but there are functions to </i>deleteCascade<i> manually in the Database.Persist.Class module.</li></ul>; automatic table creation, schema update and table migration: Modifications of the entities template produces an schema update with automatic table creation, and migration for the DBMS's that support "ALTER TABLE" <a href="/wiki/SQL">SQL</a> commands in a </i>migrateAll<i> procedure, generated from the template content. See "Migrations" in ref. to look for migration aware <a href="/wiki/Database_management_system">DBMS</a>.<br><syntaxhighlight lang="hs"><br>share <a href="/wiki/Persist"><br>User -- table name and entity record type<br> -- implicit autoincrement column "id" as primary key, typed UserId<br> ident Text -- refers to db. table column "ident"; <br> -- generates a record field prefixing the table name as "userIdent"<br> password Text Maybe -- Maybe indicates Nullable field<br> UniqueUser ident -- unique constraint with space sep. field sequence<br>Email -- table name and entity record type<br> -- implicit autoincrement column "id" as primary key, typed EmailId<br> email Text<br> user UserId -- foreign key by specifying other tables EntityField types<br> verkey Text Maybe<br> newlyAddedColumn Text "default='sometext'::character varying" -- sql level Default constraint<br> UniqueEmail email -- unique constraint<br></syntaxhighlight><br><ul><li> Esqueleto: is a haskell combinators layer to generate correct relational queries to </i>persistent<i>.</li></ul>Example for </i>persistent rawSQL<i> and </i>Esqueleto'' queries.<h3>E-mail</h3>The following packages are part of the <i>yesod-platform</i>:<br><ul><li> email-validate: Validating an email address.</li><li> mime-mail: Compose and send <a href="/wiki/MIME%3C%2Fa%3E_email_messages.%3Ch3%3EFacebook%3C%2Fh3%3E%3C%2Fli%3E%3Cli%3E_Useful_glue_functions_between_the_fb_library_and_Yesod.%3Ch2%3EDevelopment_cycle%3C%2Fh2%3E%3C%2Fli%3E%3C%2Ful%3ENew_Yesod_apps_are_generated_from_the_HaskellStack_tool_templates%2C_replacing_previous_command_%26quot%3Byesod_init%26quot%3B%3Cbr%3E%3Ci%3EStack%3C%2Fi%3E_based_app._template_names_are_prefixed_by_yesod_as_%26quot%3Byesod-%26quot%3B%3Cbr%3E%3Cul%3E%3Cli%3ESince_HaskellStack_uses_the_%3Ci%3Estackage%3C%2Fi%3E_repo_%5Bby_default">MIME</a> email messages.<h3>Facebook</h3></li><li> Useful glue functions between the fb library and Yesod.<h2>Development cycle</h2></li></ul>New Yesod apps are generated from the HaskellStack tool templates, replacing previous command "yesod init"<br><i>Stack</i> based app. template names are prefixed by yesod as "yesod-"<br><ul><li>Since HaskellStack uses the <i>stackage</i> repo [by default</a>, extra packages from the <i>hackage</i> repo should be referred in the "stack.yaml" <i>extra-deps</i> section.</li><li>You may customize packages to a local subfolder. They must be referred in the "stack.yaml" <i>packages</i> section.<h3>The "Yesod helper" tool</h3></li><li> The <i>yesod</i> helper tool </li><li>* <code>yesod devel</code> run from the project site, recompiles and restarts the project at every file tree modification.</li><li>* <code>yesod add-handler</code> adds a new handler and module to the project, adding an <i>import</i> clause for the handler in the "Application" module.<h3>Deploying with Keter: A <a href="/wiki/Web_app">web app</a> server monitor and reverse <a href="/wiki/Proxy_server">proxy server</a></h3></li></ul>See refs.<br>Keter is a process <a href="/wiki/As_a_service">as a service</a> that handles deployment and restart of Yesod web app servers, and, per <i>web app</i>, database creation for PostgreSQL.<br>The console command <code>yesod keter</code> packs the web app. as a keter bundle for uploading to a keter folder named "incoming".<br>Keter monitors the "incoming" folder and unpacks the app. to a temporary one, then assigns the web app a port to listen to, and starts it.<br>Initially it worked with <a href="/wiki/Nginx">Nginx</a> as <a href="/wiki/Reverse_proxy">reverse proxy</a>, adding <a href="/wiki/Virtual_hosting">virtual server</a> entries to its configuration and making Nginx reload it, but now Keter itself provides its own <i>reverse proxy</i> functionality, removing Nginx dependency and acting as the main web server.<br>Old documentation.<h2>Integration with <a href="/wiki/%5BJavaScript">[JavaScript</a>] generated from <a href="/wiki/Functional_languages">functional languages</a></h2>See ref.<h3>Blog tutorials</h3><ul><li> , </li><li> </li><li> <h3>Comparisons</h3></li><li> </li><li> </li><li> <h3>Other languages</h3></li><li> Univ. of <a href="/wiki/Cadiz">Cadiz</a><h3>At <a href="/wiki/GNU%2FLinux_distributions">GNU/Linux distributions</a></h3></li><li> </li><li> </li></ul><br> </section> <aside> <h2><span>Popular articles</span></h2><ul class="poplist"><li><a href="/wiki/Javier_Milei">Javier Milei</a> - Argentine libertarian economist, author, radio conductor and public speaker sympathetic to the Austrian School of economic thought. He became widely known for his regular ...</li><li><a href="/wiki/Jimmy_Carter">Jimmy Carter</a> - American politician, philanthropist, and former farmer who served as the 39th president of the United States from 1977 to 1981. A member of the Democratic Party, he previ...</li><li><a href="/wiki/UEFA_Euro_2024">UEFA Euro 2024</a> - The 2024 UEFA European Football Championship , commonly referred to as UEFA Euro 2024 or simply Euro 2024 , will be the 17th edition of the UEFA European Championship, the quadrennial internationa...</li><li><a href="/wiki/Argentina">Argentina</a> - country located mostly in the southern half of South America. Sharing the bulk of the Southern Cone with Chile to the west, the country is also b...</li><li><a href="/wiki/Sam_Altman">Sam Altman</a> - American entrepreneur, investor, programmer, and blogger. He is the former president of Y Combinator and now the CEO of OpenAI. Early life and education. ...</li><li><a href="/wiki/Rosalynn_Carter">Rosalynn Carter</a> - American who served as First Lady of the United States from 1977 to 1981 as the wife of President Jimmy Carter. For decades, she has been a leading advocate for numerou...</li><li><a href="/wiki/Next_Argentine_presidential_election">Next Argentine presidential election</a> - Next Argentine presidential election - presidential election in Argentina....</li></ul><h2><span>Popular movies</span></h2><ul class="poplist"><li><a href="/wiki/The_Hunger_Games_(film)">The Hunger Games (film)</a> - 2012 American dystopian action thriller science fiction-adventure film directed by Gary Ross and based on Suzanne Collins’s 2008 novel of the same name. It is the first insta...</li><li><a href="/wiki/untitled_Captain_Marvel_sequel">untitled Captain Marvel sequel</a> - part of Marvel Cinematic Universe....</li><li><a href="/wiki/Killers_of_the_Flower_Moon_(film_project)">Killers of the Flower Moon (film project)</a> - Killers of the Flower Moon - film project in United States of America. It was presented as drama, detective fiction, thriller. The film project starred Leonardo Dicaprio, Robert De Niro. Director of...</li><li><a href="/wiki/Five_Nights_at_Freddy's_(film)">Five Nights at Freddy's (film)</a> - Five Nights at Freddy's - film published in 2017 in United States of America. Scenarist of the film - Scott Cawthon....</li><h2><span>Popular video games</span></h2><ul class="poplist"><li><a href="/wiki/Minecraft">Minecraft</a> - sandbox video game developed by Mojang Studios. Created by Markus "Notch" Persson in the Java programming language and released as a public alpha for personal computers in 2...</li><li><a href="/wiki/Grand_Theft_Auto_V">Grand Theft Auto V</a> - 2013 action-adventure game developed by Rockstar North and published by Rockstar Games. It is the first main entry in the Grand Theft Auto series since 2008's Grand Theft ...</li><li><a href="/wiki/Roblox">Roblox</a> - online game platform and game creation system that allows users to program games and play games created by other users. Founded by David Baszucki and Erik Cassel in 2004 and released in...</li><li><a href="/wiki/Baldur's_Gate_III">Baldur's Gate III</a> - upcoming role-playing video game developed and published by Larian Studios for Microsoft Windows and the Stadia streaming service. It is the third main game in the Baldur's ...</li><li><a href="/wiki/Alan_Wake">Alan Wake</a> - action-adventure video game developed by Remedy Entertainment and published by Microsoft Studios, released for the Xbox 360 and Microsoft Windows. The story follows best-selling thri...</li><li><a href="/wiki/Fortnite">Fortnite</a> - online video game developed by Epic Games and released in 2017. It is available in three distinct game mode versions that otherwise share the same general gameplay and game engine: ...</li><li><a href="/wiki/Super_Mario_RPG">Super Mario RPG</a> - is a role-playing video game developed by Square and published by Nintendo for the Super Nintendo Entertainment System in 1996. It was directed by Yoshihiko Maekawa and Chihiro Fujioka and produced by...</li></ul><h2><span>Popular books</span></h2><ul class="poplist"><li><a href="/wiki/Book_of_Revelation">Book of Revelation</a> - The Book of Revelation is the final book of the New Testament, and consequently is also the final book of the Christian Bible. Its title is derived from the first word of the Koine Greek text: apok...</li><li><a href="/wiki/Book_of_Genesis">Book of Genesis</a> - account of the creation of the world, the early history of humanity, Israel's ancestors and the origins...</li><li><a href="/wiki/Gospel_of_Matthew">Gospel of Matthew</a> - The Gospel According to Matthew is the first book of the New Testament and one of the three synoptic gospels. It tells how Israel's Messiah, rejected and executed in Israel, pronounces judgement on ...</li><li><a href="/wiki/Michelin_Guide">Michelin Guide</a> - Michelin Guides are a series of guide books published by the French tyre company Michelin for more than a century. The term normally refers to the annually published Michelin Red Guide , the oldest...</li><li><a href="/wiki/Psalms">Psalms</a> - The Book of Psalms , commonly referred to simply as Psalms , the Psalter or "the Psalms", is the first book of the Ketuvim , the third section of the Hebrew Bible, and thus a book of th...</li><li><a href="/wiki/Ecclesiastes">Ecclesiastes</a> - Ecclesiastes is one of 24 books of the Tanakh , where it is classified as one of the Ketuvim . Originally written c. 450–200 BCE, it is also among the canonical Wisdom literature of the Old Tes...</li><li><a href="/wiki/The_48_Laws_of_Power">The 48 Laws of Power</a> - non-fiction book by American author Robert Greene. The book...</li></ul><h2><span>Popular television series</span></h2><ul class="poplist"><li><a href="/wiki/The_Crown_(TV_series)">The Crown (TV series)</a> - historical drama web television series about the reign of Queen Elizabeth II, created and principally written by Peter Morgan, and produced by Left Bank Pictures and Sony Pictures Tel...</li><li><a href="/wiki/Friends">Friends</a> - American sitcom television series, created by David Crane and Marta Kauffman, which aired on NBC from September 22, 1994, to May 6, 2004, lasting ten seasons. With an ensemble cast sta...</li><li><a href="/wiki/Young_Sheldon">Young Sheldon</a> - spin-off prequel to The Big Bang Theory and begins with the character Sheldon...</li><li><a href="/wiki/Modern_Family">Modern Family</a> - American television mockumentary family sitcom created by Christopher Lloyd and Steven Levitan for the American Broadcasting Company. It ran for eleven seasons, from September 23...</li><li><a href="/wiki/Loki_(TV_series)">Loki (TV series)</a> - upcoming American web television miniseries created for Disney+ by Michael Waldron, based on the Marvel Comics character of the same name. It is set in the Marvel Cinematic Universe, shar...</li><li><a href="/wiki/Game_of_Thrones">Game of Thrones</a> - American fantasy drama television series created by David Benioff and D. B. Weiss for HBO. It...</li><li><a href="/wiki/Shameless_(American_TV_series)">Shameless (American TV series)</a> - American comedy-drama television series developed by John Wells which debuted on Showtime on January 9, 2011. It...</li></ul> </aside> </div> <footer class="wrapper clearfix"> <a href="https://owiki.org">OWIKI.org</a>. Text is available under the Creative Commons Attribution-ShareAlike License. </footer> <script src="/js//jquery-1.9.0.min.js"></script> <script src="/js/main.js"></script> </body> </html>
$forall param <- params