Last active
August 29, 2015 14:13
-
-
Save creichert/09d45804db657181005f to your computer and use it in GitHub Desktop.
WebSockets Help
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/yesod-websockets/Game-Example/Fm.hs b/yesod-websockets/Game-Example/Fm.hs | |
| index cf31bef..a799eca 100755 | |
| --- a/yesod-websockets/Game-Example/Fm.hs | |
| +++ b/yesod-websockets/Game-Example/Fm.hs | |
| @@ -1,21 +1,27 @@ | |
| {-# LANGUAGE OverloadedStrings #-} | |
| module Fm where | |
| -import Data.List | |
| -import Text.Julius | |
| -import Data.Text hiding (map, concat, null) | |
| -import Prelude | |
| -import System.Random | |
| -import System.IO.Unsafe -- Only for values going directly into HTML website forms. | |
| + | |
| +import Data.List | |
| +import Data.Text hiding (concat, map, null) | |
| +import Prelude | |
| +import System.IO.Unsafe | |
| +import System.Random | |
| +import Text.Julius | |
| + | |
| toDouble :: Int -> Double | |
| toDouble x = read (show x) :: Double | |
| -{----------------------------------------------------------------------------------- | |
| +{------------------------------------------------------------------------------- | |
| + | |
| POTENTIALLY DANGEROUS CODE | |
| -Values produced by these functions are intended only for use in browser code, such as Javascript and HTML5, | |
| -and never where it is important to maintain referential transparency, such as Haskell. -} | |
| +Values produced by these functions are intended only for use in | |
| +browser code, such as Javascript and HTML5, and never where it is | |
| +important to maintain referential transparency, such as Haskell. | |
| + | |
| +-} | |
| rN x = unsafePerformIO (getStdRandom (System.Random.randomR (1,x)) :: IO Int) | |
| rN' x = unsafePerformIO (getStdRandom (System.Random.randomR (1,x)) :: IO Int) | |
| @@ -24,10 +30,14 @@ start a b c d = [rN a, rN' b, rN c, rN d, 42] | |
| roll a b c d = map toDouble $ start a b c d | |
| -{- Placing values generated by these functions in HTML forms is more predictable, and therefore | |
| -less fraught with danger, than accepting values placed in forms provided by in-house corporate | |
| -software and, more commonly, by web pages available to the public over the Internet. | |
| -----------------------------------------------------------------------------------------------} | |
| +{- | |
| + | |
| +Placing values generated by these functions in HTML forms is more | |
| +predictable, and therefore less fraught with danger, than accepting | |
| +values placed in forms provided by in-house corporate software and, | |
| +more commonly, by web pages available to the public over the Internet. | |
| + | |
| +-------------------------------------------------------------------------------} | |
| computation a b c | b == "+" = (+) a c | |
| | b == "-" = (-) a c | |
| @@ -63,21 +73,24 @@ scoreDiv :: (Eq a, Fractional a) => a -> a -> a | |
| scoreDiv az bz | bz == 0 = 99999 | |
| | otherwise = (/) az bz | |
| -calc :: Double -> Double -> Double -> Double -> [(String, String, String, String, String)] | |
| +calc :: Double -> Double -> Double -> Double | |
| + -> [(String, String, String, String, String)] | |
| calc a b c d = [(f a', g op1, f b', g op2, f c') | | |
| [a',b',c',d'] <- nub(permutations [a,b,c,d]), | |
| op1 <- [cat, (+), (-), (*), scoreDiv], | |
| op2 <- [cat, (+), (-), (*), scoreDiv], | |
| op2 (op1 a' b') c' == 20] | |
| -calc2 :: Double -> Double -> Double -> Double -> [(String, String, String, String, String)] | |
| +calc2 :: Double -> Double -> Double -> Double | |
| + -> [(String, String, String, String, String)] | |
| calc2 a b c d = [(f a', g op1, f b', g op2, f c') | | |
| [a',b',c',d'] <- nub(permutations [a,b,c,d]), | |
| op1 <- [cat, (+), (-), (*), scoreDiv], | |
| op2 <- [cat, (+), (-), (*), scoreDiv], | |
| op2 a' (op1 b' c') == 20] | |
| -calc3 :: Double -> Double -> Double -> Double -> [(String, String, String, String, String, String, String)] | |
| +calc3 :: Double -> Double -> Double -> Double | |
| + -> [(String, String, String, String, String, String, String)] | |
| calc3 a b c d = [(f a', g op1, f b', g op3, f c', g op2, f d') | | |
| [a',b',c',d'] <- nub(permutations [a,b,c,d]), | |
| op1 <- [cat, (+), (-), (*), scoreDiv], | |
| @@ -85,7 +98,8 @@ calc3 a b c d = [(f a', g op1, f b', g op3, f c', g op2, f d') | | |
| op3 <- [cat, (+), (-), (*), scoreDiv], | |
| op3 (op1 a' b') (op2 c' d') == 20] | |
| -calc4 :: Double -> Double -> Double -> Double -> [(String, String, String, String, String, String, String)] | |
| +calc4 :: Double -> Double -> Double -> Double | |
| + -> [(String, String, String, String, String, String, String)] | |
| calc4 a b c d = [(f a', g op1, f b', g op3, f c', g op2, f d') | | |
| [a',b',c',d'] <- nub(permutations [a,b,c,d]), | |
| op1 <- [cat, (+), (-), (*), scoreDiv], | |
| @@ -115,7 +129,9 @@ calc7 a b c d = [(f a', g op1, f b', g op3, f c', g op2, f d') | | |
| op3 d' (op2 c' (op1 a' b')) == 20] | |
| h :: (String, String, String, String, String) -> String | |
| -h (a',b',c',d',e') = "(" ++ a' ++ b' ++ c' ++ ")" ++ d' ++ e' ++ " = 20<br> " | |
| +h (a',b',c',d',e') = concat [ "(", a', b', c', ")" | |
| + , d', e', " = 20<br> " | |
| + ] | |
| h2 :: (String, String, String, String, String) -> String | |
| h2 (a',b',c',d',e') = a' ++ d' ++ "(" ++ c' ++ b' ++ e'++ ") = 20<br> " | |
| @@ -141,47 +157,62 @@ h7 (a',b',c',d',e',f',g') = g' ++ d' ++ "(" ++ e' ++ f' ++ | |
| -- | otherwise = "" | |
| ca [] = ["Empty"] | |
| -ca [a, b, c, d, e] = map h (calc a b c d) ++ map h2 (calc2 a b c d) ++ map h3 (calc3 a b c d) ++ map h4 (calc4 a b c d) ++ | |
| - map h5 (calc5 a b c d) ++ map h6 (calc6 a b c d) ++ map h7 (calc7 a b c d) | |
| +ca [a, b, c, d, e] = concat [ map h (calc a b c d) | |
| + , map h2 (calc2 a b c d) | |
| + , map h3 (calc3 a b c d) | |
| + , map h4 (calc4 a b c d) | |
| + , map h5 (calc5 a b c d) | |
| + , map h6 (calc6 a b c d) | |
| + , map h7 (calc7 a b c d) | |
| + ] | |
| ca _ = ["What?"] | |
| cars [a,b,c,d,e] = concat $ ca [a,b,c,d,e] | |
| -truck x = do | |
| +truck x = do | |
| let y = map round x | |
| let z = show (y !! 0) ++ " " ++ show (y !! 1) ++ " " ++ show (y !! 2) ++ " " ++ show (y !! 3) ++ "<br><br>" | |
| - let a = (z ++ cars x ++ "<br>") :: String | |
| - return a :: IO String | |
| + let a = (z ++ cars x ++ "<br>") :: String | |
| + return a :: IO String | |
| main = truck $ roll 6 6 12 20 | |
| {- | |
| - "Using the first number left of the result obtained from the second and third numbers." ++ | |
| + "Using the first number left of the result obtained from the | |
| + second and third numbers." ++ | |
| + | |
| map h2 (calc2 a b c d) ++ | |
| pim (calc2 a b c d) ++ | |
| - "Using the first two numbers and then the remaining two numbers, then using those results."++ | |
| + "Using the first two numbers and then the remaining two numbers, | |
| + then using those results."++ | |
| + | |
| map h3 (calc3 a b c d) ++ | |
| pim (calc3 a b c d) ++ | |
| - "Using the result from the first two numbers left of the third, then that result left of fourth number." ++ | |
| + "Using the result from the first two numbers left of the third, | |
| + then that result left of fourth number." ++ | |
| + | |
| map h4 (calc4 a b c d) ++ | |
| pim (calc4 a b c d) ++ | |
| - "Using the third number left of the result obtained from the first two, then that result left of the fourth number." ++ | |
| + "Using the third number left of the result obtained from the first | |
| + two, then that result left of the fourth number." ++ | |
| + | |
| map h5 (calc5 a b c d) ++ | |
| pim (calc5 a b c d) ++ | |
| - "Using the fourth number to the left of the result from using the first two numbers' result left of the third." ++ | |
| + "Using the fourth number to the left of the result from using the | |
| + first two numbers' result left of the third." ++ | |
| + | |
| map h6 (calc6 a b c d) ++ | |
| pim (calc6 a b c d) ++ | |
| - "Using the fourth number to the left of the result from using the third number left of the result from the first two." ++ | |
| - map h7 (calc7 a b c d) ++ | |
| - pim (calc7 a b c d) | |
| --} | |
| - | |
| - | |
| + "Using the fourth number to the left of the result from using the | |
| + third number left of the result from the first two." ++ | |
| + map h7 (calc7 a b c d) ++ | |
| + pim (calc7 a b c d) | |
| +-} | |
| diff --git a/yesod-websockets/Game-Example/Fm.html b/yesod-websockets/Game-Example/Fm.html | |
| deleted file mode 100644 | |
| index 26f5efa..0000000 | |
| --- a/yesod-websockets/Game-Example/Fm.html | |
| +++ /dev/null | |
| @@ -1,1180 +0,0 @@ | |
| -<!DOCTYPE html><html><head><meta charset="utf-8"><style>body { | |
| - width: 45em; | |
| - border: 1px solid #ddd; | |
| - outline: 1300px solid #fff; | |
| - margin: 16px auto; | |
| -} | |
| - | |
| -body .markdown-body | |
| -{ | |
| - padding: 30px; | |
| -} | |
| - | |
| -@font-face { | |
| - font-family: fontawesome-mini; | |
| - src: url(data:font/woff;charset=utf-8;base64,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) format('woff'); | |
| -} | |
| - | |
| -@font-face { | |
| - font-family: octicons-anchor; | |
| - src: url(data:font/woff;charset=utf-8;base64,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) format('woff'); | |
| -} | |
| - | |
| -.markdown-body { | |
| - font-family: sans-serif; | |
| - -ms-text-size-adjust: 100%; | |
| - -webkit-text-size-adjust: 100%; | |
| - color: #333333; | |
| - overflow: hidden; | |
| - font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; | |
| - font-size: 16px; | |
| - line-height: 1.6; | |
| - word-wrap: break-word; | |
| -} | |
| - | |
| -.markdown-body a { | |
| - background: transparent; | |
| -} | |
| - | |
| -.markdown-body a:active, | |
| -.markdown-body a:hover { | |
| - outline: 0; | |
| -} | |
| - | |
| -.markdown-body b, | |
| -.markdown-body strong { | |
| - font-weight: bold; | |
| -} | |
| - | |
| -.markdown-body mark { | |
| - background: #ff0; | |
| - color: #000; | |
| - font-style: italic; | |
| - font-weight: bold; | |
| -} | |
| - | |
| -.markdown-body sub, | |
| -.markdown-body sup { | |
| - font-size: 75%; | |
| - line-height: 0; | |
| - position: relative; | |
| - vertical-align: baseline; | |
| -} | |
| -.markdown-body sup { | |
| - top: -0.5em; | |
| -} | |
| -.markdown-body sub { | |
| - bottom: -0.25em; | |
| -} | |
| - | |
| -.markdown-body h1 { | |
| - font-size: 2em; | |
| - margin: 0.67em 0; | |
| -} | |
| - | |
| -.markdown-body img { | |
| - border: 0; | |
| -} | |
| - | |
| -.markdown-body hr { | |
| - -moz-box-sizing: content-box; | |
| - box-sizing: content-box; | |
| - height: 0; | |
| -} | |
| - | |
| -.markdown-body pre { | |
| - overflow: auto; | |
| -} | |
| - | |
| -.markdown-body code, | |
| -.markdown-body kbd, | |
| -.markdown-body pre, | |
| -.markdown-body samp { | |
| - font-family: monospace, monospace; | |
| - font-size: 1em; | |
| -} | |
| - | |
| -.markdown-body input { | |
| - color: inherit; | |
| - font: inherit; | |
| - margin: 0; | |
| -} | |
| - | |
| -.markdown-body html input[disabled] { | |
| - cursor: default; | |
| -} | |
| - | |
| -.markdown-body input { | |
| - line-height: normal; | |
| -} | |
| - | |
| -.markdown-body input[type="checkbox"] { | |
| - box-sizing: border-box; | |
| - padding: 0; | |
| -} | |
| - | |
| -.markdown-body table { | |
| - border-collapse: collapse; | |
| - border-spacing: 0; | |
| -} | |
| - | |
| -.markdown-body td, | |
| -.markdown-body th { | |
| - padding: 0; | |
| -} | |
| - | |
| -.markdown-body .codehilitetable { | |
| - border: 0; | |
| - border-spacing: 0; | |
| -} | |
| - | |
| -.markdown-body .codehilitetable tr { | |
| - border: 0; | |
| -} | |
| - | |
| -.markdown-body .codehilitetable pre, | |
| -.markdown-body .codehilitetable div.codehilite { | |
| - margin: 0; | |
| -} | |
| - | |
| -.markdown-body .linenos, | |
| -.markdown-body .code, | |
| -.markdown-body .codehilitetable td { | |
| - border: 0; | |
| - padding: 0; | |
| -} | |
| - | |
| -.markdown-body td:not(.linenos) .linenodiv { | |
| - padding: 0 !important; | |
| -} | |
| - | |
| -.markdown-body .code { | |
| - width: 100%; | |
| -} | |
| - | |
| -.markdown-body .linenos div pre, | |
| -.markdown-body .linenodiv pre, | |
| -.markdown-body .linenodiv { | |
| - border: 0; | |
| - -webkit-border-radius: 0; | |
| - -moz-border-radius: 0; | |
| - border-radius: 0; | |
| - -webkit-border-top-left-radius: 3px; | |
| - -webkit-border-bottom-left-radius: 3px; | |
| - -moz-border-radius-topleft: 3px; | |
| - -moz-border-radius-bottomleft: 3px; | |
| - border-top-left-radius: 3px; | |
| - border-bottom-left-radius: 3px; | |
| -} | |
| - | |
| -.markdown-body .code div pre, | |
| -.markdown-body .code div { | |
| - border: 0; | |
| - -webkit-border-radius: 0; | |
| - -moz-border-radius: 0; | |
| - border-radius: 0; | |
| - -webkit-border-top-right-radius: 3px; | |
| - -webkit-border-bottom-right-radius: 3px; | |
| - -moz-border-radius-topright: 3px; | |
| - -moz-border-radius-bottomright: 3px; | |
| - border-top-right-radius: 3px; | |
| - border-bottom-right-radius: 3px; | |
| -} | |
| - | |
| -.markdown-body * { | |
| - -moz-box-sizing: border-box; | |
| - box-sizing: border-box; | |
| -} | |
| - | |
| -.markdown-body input { | |
| - font: 13px Helvetica, arial, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol"; | |
| - line-height: 1.4; | |
| -} | |
| - | |
| -.markdown-body a { | |
| - color: #4183c4; | |
| - text-decoration: none; | |
| -} | |
| - | |
| -.markdown-body a:hover, | |
| -.markdown-body a:focus, | |
| -.markdown-body a:active { | |
| - text-decoration: underline; | |
| -} | |
| - | |
| -.markdown-body hr { | |
| - height: 0; | |
| - margin: 15px 0; | |
| - overflow: hidden; | |
| - background: transparent; | |
| - border: 0; | |
| - border-bottom: 1px solid #ddd; | |
| -} | |
| - | |
| -.markdown-body hr:before, | |
| -.markdown-body hr:after { | |
| - display: table; | |
| - content: " "; | |
| -} | |
| - | |
| -.markdown-body hr:after { | |
| - clear: both; | |
| -} | |
| - | |
| -.markdown-body h1, | |
| -.markdown-body h2, | |
| -.markdown-body h3, | |
| -.markdown-body h4, | |
| -.markdown-body h5, | |
| -.markdown-body h6 { | |
| - margin-top: 15px; | |
| - margin-bottom: 15px; | |
| - line-height: 1.1; | |
| -} | |
| - | |
| -.markdown-body h1 { | |
| - font-size: 30px; | |
| -} | |
| - | |
| -.markdown-body h2 { | |
| - font-size: 21px; | |
| -} | |
| - | |
| -.markdown-body h3 { | |
| - font-size: 16px; | |
| -} | |
| - | |
| -.markdown-body h4 { | |
| - font-size: 14px; | |
| -} | |
| - | |
| -.markdown-body h5 { | |
| - font-size: 12px; | |
| -} | |
| - | |
| -.markdown-body h6 { | |
| - font-size: 11px; | |
| -} | |
| - | |
| -.markdown-body blockquote { | |
| - margin: 0; | |
| -} | |
| - | |
| -.markdown-body ul, | |
| -.markdown-body ol { | |
| - padding: 0; | |
| - margin-top: 0; | |
| - margin-bottom: 0; | |
| -} | |
| - | |
| -.markdown-body ol ol, | |
| -.markdown-body ul ol { | |
| - list-style-type: lower-roman; | |
| -} | |
| - | |
| -.markdown-body ul ul ol, | |
| -.markdown-body ul ol ol, | |
| -.markdown-body ol ul ol, | |
| -.markdown-body ol ol ol { | |
| - list-style-type: lower-alpha; | |
| -} | |
| - | |
| -.markdown-body dd { | |
| - margin-left: 0; | |
| -} | |
| - | |
| -.markdown-body code, | |
| -.markdown-body pre, | |
| -.markdown-body samp { | |
| - font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; | |
| - font-size: 12px; | |
| -} | |
| - | |
| -.markdown-body pre { | |
| - margin-top: 0; | |
| - margin-bottom: 0; | |
| -} | |
| - | |
| -.markdown-body kbd { | |
| - background-color: #e7e7e7; | |
| - background-image: -moz-linear-gradient(#fefefe, #e7e7e7); | |
| - background-image: -webkit-linear-gradient(#fefefe, #e7e7e7); | |
| - background-image: linear-gradient(#fefefe, #e7e7e7); | |
| - background-repeat: repeat-x; | |
| - border-radius: 2px; | |
| - border: 1px solid #cfcfcf; | |
| - color: #000; | |
| - padding: 3px 5px; | |
| - line-height: 10px; | |
| - font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace; | |
| - display: inline-block; | |
| -} | |
| - | |
| -.markdown-body>*:first-child { | |
| - margin-top: 0 !important; | |
| -} | |
| - | |
| -.markdown-body>*:last-child { | |
| - margin-bottom: 0 !important; | |
| -} | |
| - | |
| -.markdown-body .headeranchor-link { | |
| - position: absolute; | |
| - top: 0; | |
| - bottom: 0; | |
| - left: 0; | |
| - display: block; | |
| - padding-right: 6px; | |
| - padding-left: 30px; | |
| - margin-left: -30px; | |
| -} | |
| - | |
| -.markdown-body .headeranchor-link:focus { | |
| - outline: none; | |
| -} | |
| - | |
| -.markdown-body h1, | |
| -.markdown-body h2, | |
| -.markdown-body h3, | |
| -.markdown-body h4, | |
| -.markdown-body h5, | |
| -.markdown-body h6 { | |
| - position: relative; | |
| - margin-top: 1em; | |
| - margin-bottom: 16px; | |
| - font-weight: bold; | |
| - line-height: 1.4; | |
| -} | |
| - | |
| -.markdown-body h1 .headeranchor, | |
| -.markdown-body h2 .headeranchor, | |
| -.markdown-body h3 .headeranchor, | |
| -.markdown-body h4 .headeranchor, | |
| -.markdown-body h5 .headeranchor, | |
| -.markdown-body h6 .headeranchor { | |
| - display: none; | |
| - color: #000; | |
| - vertical-align: middle; | |
| -} | |
| - | |
| -.markdown-body h1:hover .headeranchor-link, | |
| -.markdown-body h2:hover .headeranchor-link, | |
| -.markdown-body h3:hover .headeranchor-link, | |
| -.markdown-body h4:hover .headeranchor-link, | |
| -.markdown-body h5:hover .headeranchor-link, | |
| -.markdown-body h6:hover .headeranchor-link { | |
| - height: 1em; | |
| - padding-left: 8px; | |
| - margin-left: -30px; | |
| - line-height: 1; | |
| - text-decoration: none; | |
| -} | |
| - | |
| -.markdown-body h1:hover .headeranchor-link .headeranchor, | |
| -.markdown-body h2:hover .headeranchor-link .headeranchor, | |
| -.markdown-body h3:hover .headeranchor-link .headeranchor, | |
| -.markdown-body h4:hover .headeranchor-link .headeranchor, | |
| -.markdown-body h5:hover .headeranchor-link .headeranchor, | |
| -.markdown-body h6:hover .headeranchor-link .headeranchor { | |
| - display: inline-block; | |
| -} | |
| - | |
| -.markdown-body h1 { | |
| - padding-bottom: 0.3em; | |
| - font-size: 2.25em; | |
| - line-height: 1.2; | |
| - border-bottom: 1px solid #eee; | |
| -} | |
| - | |
| -.markdown-body h2 { | |
| - padding-bottom: 0.3em; | |
| - font-size: 1.75em; | |
| - line-height: 1.225; | |
| - border-bottom: 1px solid #eee; | |
| -} | |
| - | |
| -.markdown-body h3 { | |
| - font-size: 1.5em; | |
| - line-height: 1.43; | |
| -} | |
| - | |
| -.markdown-body h4 { | |
| - font-size: 1.25em; | |
| -} | |
| - | |
| -.markdown-body h5 { | |
| - font-size: 1em; | |
| -} | |
| - | |
| -.markdown-body h6 { | |
| - font-size: 1em; | |
| - color: #777; | |
| -} | |
| - | |
| -.markdown-body p, | |
| -.markdown-body blockquote, | |
| -.markdown-body ul, | |
| -.markdown-body ol, | |
| -.markdown-body dl, | |
| -.markdown-body table, | |
| -.markdown-body pre, | |
| -.markdown-body .admonition { | |
| - margin-top: 0; | |
| - margin-bottom: 16px; | |
| -} | |
| - | |
| -.markdown-body hr { | |
| - height: 4px; | |
| - padding: 0; | |
| - margin: 16px 0; | |
| - background-color: #e7e7e7; | |
| - border: 0 none; | |
| -} | |
| - | |
| -.markdown-body ul, | |
| -.markdown-body ol { | |
| - padding-left: 2em; | |
| -} | |
| - | |
| -.markdown-body ul ul, | |
| -.markdown-body ul ol, | |
| -.markdown-body ol ol, | |
| -.markdown-body ol ul { | |
| - margin-top: 0; | |
| - margin-bottom: 0; | |
| -} | |
| - | |
| -.markdown-body li>p { | |
| - margin-top: 16px; | |
| -} | |
| - | |
| -.markdown-body dl { | |
| - padding: 0; | |
| -} | |
| - | |
| -.markdown-body dl dt { | |
| - padding: 0; | |
| - margin-top: 16px; | |
| - font-size: 1em; | |
| - font-style: italic; | |
| - font-weight: bold; | |
| -} | |
| - | |
| -.markdown-body dl dd { | |
| - padding: 0 16px; | |
| - margin-bottom: 16px; | |
| -} | |
| - | |
| -.markdown-body blockquote { | |
| - padding: 0 15px; | |
| - color: #777; | |
| - border-left: 4px solid #ddd; | |
| -} | |
| - | |
| -.markdown-body blockquote>:first-child { | |
| - margin-top: 0; | |
| -} | |
| - | |
| -.markdown-body blockquote>:last-child { | |
| - margin-bottom: 0; | |
| -} | |
| - | |
| -.markdown-body table { | |
| - display: block; | |
| - width: 100%; | |
| - overflow: auto; | |
| - word-break: normal; | |
| - word-break: keep-all; | |
| -} | |
| - | |
| -.markdown-body table th { | |
| - font-weight: bold; | |
| -} | |
| - | |
| -.markdown-body table th, | |
| -.markdown-body table td { | |
| - padding: 6px 13px; | |
| - border: 1px solid #ddd; | |
| -} | |
| - | |
| -.markdown-body table tr { | |
| - background-color: #fff; | |
| - border-top: 1px solid #ccc; | |
| -} | |
| - | |
| -.markdown-body table tr:nth-child(2n) { | |
| - background-color: #f8f8f8; | |
| -} | |
| - | |
| -.markdown-body img { | |
| - max-width: 100%; | |
| - -moz-box-sizing: border-box; | |
| - box-sizing: border-box; | |
| -} | |
| - | |
| -.markdown-body code, | |
| -.markdown-body samp { | |
| - padding: 0; | |
| - padding-top: 0.2em; | |
| - padding-bottom: 0.2em; | |
| - margin: 0; | |
| - font-size: 85%; | |
| - background-color: rgba(0,0,0,0.04); | |
| - border-radius: 3px; | |
| -} | |
| - | |
| -.markdown-body code:before, | |
| -.markdown-body code:after { | |
| - letter-spacing: -0.2em; | |
| - content: "\00a0"; | |
| -} | |
| - | |
| -.markdown-body pre>code { | |
| - padding: 0; | |
| - margin: 0; | |
| - font-size: 100%; | |
| - word-break: normal; | |
| - white-space: pre; | |
| - background: transparent; | |
| - border: 0; | |
| -} | |
| - | |
| -.markdown-body .codehilite { | |
| - margin-bottom: 16px; | |
| -} | |
| - | |
| -.markdown-body .codehilite pre, | |
| -.markdown-body pre { | |
| - padding: 16px; | |
| - overflow: auto; | |
| - font-size: 85%; | |
| - line-height: 1.45; | |
| - background-color: #f7f7f7; | |
| - border-radius: 3px; | |
| -} | |
| - | |
| -.markdown-body .codehilite pre { | |
| - margin-bottom: 0; | |
| - word-break: normal; | |
| -} | |
| - | |
| -.markdown-body pre { | |
| - word-wrap: normal; | |
| -} | |
| - | |
| -.markdown-body pre code { | |
| - display: inline; | |
| - max-width: initial; | |
| - padding: 0; | |
| - margin: 0; | |
| - overflow: initial; | |
| - line-height: inherit; | |
| - word-wrap: normal; | |
| - background-color: transparent; | |
| - border: 0; | |
| -} | |
| - | |
| -.markdown-body pre code:before, | |
| -.markdown-body pre code:after { | |
| - content: normal; | |
| -} | |
| - | |
| -/* Admonition */ | |
| -.markdown-body .admonition { | |
| - -webkit-border-radius: 3px; | |
| - -moz-border-radius: 3px; | |
| - position: relative; | |
| - border-radius: 3px; | |
| - border: 1px solid #e0e0e0; | |
| - border-left: 6px solid #333; | |
| - padding: 10px 10px 10px 30px; | |
| -} | |
| - | |
| -.markdown-body .admonition table { | |
| - color: #333; | |
| -} | |
| - | |
| -.markdown-body .admonition p { | |
| - padding: 0; | |
| -} | |
| - | |
| -.markdown-body .admonition-title { | |
| - font-weight: bold; | |
| - margin: 0; | |
| -} | |
| - | |
| -.markdown-body .admonition>.admonition-title { | |
| - color: #333; | |
| -} | |
| - | |
| -.markdown-body .attention>.admonition-title { | |
| - color: #a6d796; | |
| -} | |
| - | |
| -.markdown-body .caution>.admonition-title { | |
| - color: #d7a796; | |
| -} | |
| - | |
| -.markdown-body .hint>.admonition-title { | |
| - color: #96c6d7; | |
| -} | |
| - | |
| -.markdown-body .danger>.admonition-title { | |
| - color: #c25f77; | |
| -} | |
| - | |
| -.markdown-body .question>.admonition-title { | |
| - color: #96a6d7; | |
| -} | |
| - | |
| -.markdown-body .note>.admonition-title { | |
| - color: #d7c896; | |
| -} | |
| - | |
| -.markdown-body .admonition:before, | |
| -.markdown-body .attention:before, | |
| -.markdown-body .caution:before, | |
| -.markdown-body .hint:before, | |
| -.markdown-body .danger:before, | |
| -.markdown-body .question:before, | |
| -.markdown-body .note:before { | |
| - font: normal normal 16px fontawesome-mini; | |
| - -moz-osx-font-smoothing: grayscale; | |
| - -webkit-user-select: none; | |
| - -moz-user-select: none; | |
| - -ms-user-select: none; | |
| - user-select: none; | |
| - line-height: 1.5; | |
| - color: #333; | |
| - position: absolute; | |
| - left: 0; | |
| - top: 0; | |
| - padding-top: 10px; | |
| - padding-left: 10px; | |
| -} | |
| - | |
| -.markdown-body .admonition:before { | |
| - content: "\f056\00a0"; | |
| - color: 333; | |
| -} | |
| - | |
| -.markdown-body .attention:before { | |
| - content: "\f058\00a0"; | |
| - color: #a6d796; | |
| -} | |
| - | |
| -.markdown-body .caution:before { | |
| - content: "\f06a\00a0"; | |
| - color: #d7a796; | |
| -} | |
| - | |
| -.markdown-body .hint:before { | |
| - content: "\f05a\00a0"; | |
| - color: #96c6d7; | |
| -} | |
| - | |
| -.markdown-body .danger:before { | |
| - content: "\f057\00a0"; | |
| - color: #c25f77; | |
| -} | |
| - | |
| -.markdown-body .question:before { | |
| - content: "\f059\00a0"; | |
| - color: #96a6d7; | |
| -} | |
| - | |
| -.markdown-body .note:before { | |
| - content: "\f040\00a0"; | |
| - color: #d7c896; | |
| -} | |
| - | |
| -.markdown-body .admonition::after { | |
| - content: normal; | |
| -} | |
| - | |
| -.markdown-body .attention { | |
| - border-left: 6px solid #a6d796; | |
| -} | |
| - | |
| -.markdown-body .caution { | |
| - border-left: 6px solid #d7a796; | |
| -} | |
| - | |
| -.markdown-body .hint { | |
| - border-left: 6px solid #96c6d7; | |
| -} | |
| - | |
| -.markdown-body .danger { | |
| - border-left: 6px solid #c25f77; | |
| -} | |
| - | |
| -.markdown-body .question { | |
| - border-left: 6px solid #96a6d7; | |
| -} | |
| - | |
| -.markdown-body .note { | |
| - border-left: 6px solid #d7c896; | |
| -} | |
| - | |
| -.markdown-body .admonition>*:first-child { | |
| - margin-top: 0 !important; | |
| -} | |
| - | |
| -.markdown-body .admonition>*:last-child { | |
| - margin-bottom: 0 !important; | |
| -} | |
| - | |
| -/* progress bar*/ | |
| -.markdown-body .progress { | |
| - display: block; | |
| - width: 300px; | |
| - margin: 10px 0; | |
| - height: 24px; | |
| - -webkit-border-radius: 3px; | |
| - -moz-border-radius: 3px; | |
| - border-radius: 3px; | |
| - background-color: #ededed; | |
| - position: relative; | |
| - box-shadow: inset -1px 1px 3px rgba(0, 0, 0, .1); | |
| -} | |
| - | |
| -.markdown-body .progress-label { | |
| - position: absolute; | |
| - text-align: center; | |
| - font-weight: bold; | |
| - width: 100%; margin: 0; | |
| - line-height: 24px; | |
| - color: #333; | |
| - 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; | |
| - -webkit-font-smoothing: antialiased !important; | |
| - white-space: nowrap; | |
| - overflow: hidden; | |
| -} | |
| - | |
| -.markdown-body .progress-bar { | |
| - height: 24px; | |
| - float: left; | |
| - -webkit-border-radius: 3px; | |
| - -moz-border-radius: 3px; | |
| - border-radius: 3px; | |
| - background-color: #96c6d7; | |
| - box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), inset 0 -1px 0 rgba(0, 0, 0, .1); | |
| - background-size: 30px 30px; | |
| - background-image: -webkit-linear-gradient( | |
| - 135deg, rgba(255, 255, 255, .4) 27%, | |
| - transparent 27%, | |
| - transparent 52%, rgba(255, 255, 255, .4) 52%, | |
| - rgba(255, 255, 255, .4) 77%, | |
| - transparent 77%, transparent | |
| - ); | |
| - background-image: -moz-linear-gradient( | |
| - 135deg, | |
| - rgba(255, 255, 255, .4) 27%, transparent 27%, | |
| - transparent 52%, rgba(255, 255, 255, .4) 52%, | |
| - rgba(255, 255, 255, .4) 77%, transparent 77%, | |
| - transparent | |
| - ); | |
| - background-image: -ms-linear-gradient( | |
| - 135deg, | |
| - rgba(255, 255, 255, .4) 27%, transparent 27%, | |
| - transparent 52%, rgba(255, 255, 255, .4) 52%, | |
| - rgba(255, 255, 255, .4) 77%, transparent 77%, | |
| - transparent | |
| - ); | |
| - background-image: -o-linear-gradient( | |
| - 135deg, | |
| - rgba(255, 255, 255, .4) 27%, transparent 27%, | |
| - transparent 52%, rgba(255, 255, 255, .4) 52%, | |
| - rgba(255, 255, 255, .4) 77%, transparent 77%, | |
| - transparent | |
| - ); | |
| - background-image: linear-gradient( | |
| - 135deg, | |
| - rgba(255, 255, 255, .4) 27%, transparent 27%, | |
| - transparent 52%, rgba(255, 255, 255, .4) 52%, | |
| - rgba(255, 255, 255, .4) 77%, transparent 77%, | |
| - transparent | |
| - ); | |
| -} | |
| - | |
| -.markdown-body .progress-100plus .progress-bar { | |
| - background-color: #a6d796; | |
| -} | |
| - | |
| -.markdown-body .progress-80plus .progress-bar { | |
| - background-color: #c6d796; | |
| -} | |
| - | |
| -.markdown-body .progress-60plus .progress-bar { | |
| - background-color: #d7c896; | |
| -} | |
| - | |
| -.markdown-body .progress-40plus .progress-bar { | |
| - background-color: #d7a796; | |
| -} | |
| - | |
| -.markdown-body .progress-20plus .progress-bar { | |
| - background-color: #d796a6; | |
| -} | |
| - | |
| -.markdown-body .progress-0plus .progress-bar { | |
| - background-color: #c25f77; | |
| -} | |
| - | |
| -.markdown-body .candystripe-animate .progress-bar{ | |
| - -webkit-animation: animate-stripes 3s linear infinite; | |
| - -moz-animation: animate-stripes 3s linear infinite; | |
| - animation: animate-stripes 3s linear infinite; | |
| -} | |
| - | |
| -@-webkit-keyframes animate-stripes { | |
| - 0% { | |
| - background-position: 0 0; | |
| - } | |
| - | |
| - 100% { | |
| - background-position: 60px 0; | |
| - } | |
| -} | |
| - | |
| -@-moz-keyframes animate-stripes { | |
| - 0% { | |
| - background-position: 0 0; | |
| - } | |
| - | |
| - 100% { | |
| - background-position: 60px 0; | |
| - } | |
| -} | |
| - | |
| -@keyframes animate-stripes { | |
| - 0% { | |
| - background-position: 0 0; | |
| - } | |
| - | |
| - 100% { | |
| - background-position: 60px 0; | |
| - } | |
| -} | |
| - | |
| -.markdown-body .gloss .progress-bar { | |
| - box-shadow: | |
| - inset 0 4px 12px rgba(255, 255, 255, .7), | |
| - inset 0 -12px 0 rgba(0, 0, 0, .05); | |
| -} | |
| - | |
| -/* Multimarkdown Critic Blocks */ | |
| -.markdown-body .critic_mark { | |
| - background: #ff0; | |
| -} | |
| - | |
| -.markdown-body .critic_delete { | |
| - color: #c82829; | |
| - text-decoration: line-through; | |
| -} | |
| - | |
| -.markdown-body .critic_insert { | |
| - color: #718c00 ; | |
| - text-decoration: underline; | |
| -} | |
| - | |
| -.markdown-body .critic_comment { | |
| - color: #8e908c; | |
| - font-style: italic; | |
| -} | |
| - | |
| -.markdown-body .headeranchor { | |
| - font: normal normal 16px octicons-anchor; | |
| - line-height: 1; | |
| - display: inline-block; | |
| - text-decoration: none; | |
| - -webkit-font-smoothing: antialiased; | |
| - -moz-osx-font-smoothing: grayscale; | |
| - -webkit-user-select: none; | |
| - -moz-user-select: none; | |
| - -ms-user-select: none; | |
| - user-select: none; | |
| -} | |
| - | |
| -.headeranchor:before { | |
| - content: '\f05c'; | |
| -} | |
| - | |
| -.markdown-body .task-list-item { | |
| - list-style-type: none; | |
| -} | |
| - | |
| -.markdown-body .task-list-item+.task-list-item { | |
| - margin-top: 3px; | |
| -} | |
| - | |
| -.markdown-body .task-list-item input { | |
| - margin: 0 4px 0.25em -20px; | |
| - vertical-align: middle; | |
| -} | |
| - | |
| -/* Media */ | |
| -@media only screen and (min-width: 480px) { | |
| - .markdown-body { | |
| - font-size:14px; | |
| - } | |
| -} | |
| - | |
| -@media only screen and (min-width: 768px) { | |
| - .markdown-body { | |
| - font-size:16px; | |
| - } | |
| -} | |
| - | |
| -@media print { | |
| - .markdown-body * { | |
| - background: transparent !important; | |
| - color: black !important; | |
| - filter:none !important; | |
| - -ms-filter: none !important; | |
| - } | |
| - | |
| - .markdown-body { | |
| - font-size:12pt; | |
| - max-width:100%; | |
| - outline:none; | |
| - border: 0; | |
| - } | |
| - | |
| - .markdown-body a, | |
| - .markdown-body a:visited { | |
| - text-decoration: underline; | |
| - } | |
| - | |
| - .markdown-body .headeranchor-link { | |
| - display: none; | |
| - } | |
| - | |
| - .markdown-body a[href]:after { | |
| - content: " (" attr(href) ")"; | |
| - } | |
| - | |
| - .markdown-body abbr[title]:after { | |
| - content: " (" attr(title) ")"; | |
| - } | |
| - | |
| - .markdown-body .ir a:after, | |
| - .markdown-body a[href^="javascript:"]:after, | |
| - .markdown-body a[href^="#"]:after { | |
| - content: ""; | |
| - } | |
| - | |
| - .markdown-body pre { | |
| - white-space: pre; | |
| - white-space: pre-wrap; | |
| - word-wrap: break-word; | |
| - } | |
| - | |
| - .markdown-body pre, | |
| - .markdown-body blockquote { | |
| - border: 1px solid #999; | |
| - padding-right: 1em; | |
| - page-break-inside: avoid; | |
| - } | |
| - | |
| - .markdown-body .progress, | |
| - .markdown-body .progress-bar { | |
| - -moz-box-shadow: none; | |
| - -webkit-box-shadow: none; | |
| - box-shadow: none; | |
| - } | |
| - | |
| - .markdown-body .progress { | |
| - border: 1px solid #ddd; | |
| - } | |
| - | |
| - .markdown-body .progress-bar { | |
| - height: 22px; | |
| - border-right: 1px solid #ddd; | |
| - } | |
| - | |
| - .markdown-body tr, | |
| - .markdown-body img { | |
| - page-break-inside: avoid; | |
| - } | |
| - | |
| - .markdown-body img { | |
| - max-width: 100% !important; | |
| - } | |
| - | |
| - .markdown-body p, | |
| - .markdown-body h2, | |
| - .markdown-body h3 { | |
| - orphans: 3; | |
| - widows: 3; | |
| - } | |
| - | |
| - .markdown-body h2, | |
| - .markdown-body h3 { | |
| - page-break-after: avoid; | |
| - } | |
| -} | |
| -</style><title>Fm</title></head><body><article class="markdown-body"><p>{-# LANGUAGE OverloadedStrings #-}<br /> | |
| -module Fm where</p> | |
| -<p>import Data.List<br /> | |
| -import Text.Julius<br /> | |
| -import Data.Text hiding (map, concat, null)<br /> | |
| -import Prelude<br /> | |
| -import System.Random<br /> | |
| -import System.IO.Unsafe – Only for values going directly into HTML website forms.</p> | |
| -<p>toDouble :: Int -> Double<br /> | |
| -toDouble x = read (show x) :: Double</p> | |
| -<p>{-----------------------------------------------------------------------------------<br /> | |
| -POTENTIALLY DANGEROUS CODE</p> | |
| -<p>Values produced by these functions are intended only for use in browser code, such as Javascript and HTML5, <br /> | |
| -and never where it is important to maintain referential transparency, such as Haskell. -}</p> | |
| -<p>rN x = unsafePerformIO (getStdRandom (System.Random.randomR (1,x)) :: IO Int)<br /> | |
| -rN’ x = unsafePerformIO (getStdRandom (System.Random.randomR (1,x)) :: IO Int)</p> | |
| -<p>start a b c d = [rN a, rN’ b, rN c, rN d, 42]</p> | |
| -<p>roll a b c d = map toDouble $ start a b c d</p> | |
| -<p>{- Placing values generated by these functions in HTML forms is more predictable, and therefore <br /> | |
| -less fraught with danger, than accepting values placed in forms provided by in-house corporate <br /> | |
| -software and, more commonly, by web pages available to the public over the Internet.<br /> | |
| -----------------------------------------------------------------------------------------------}</p> | |
| -<table> | |
| -<thead> | |
| -<tr> | |
| -<th>computation a b c</th> | |
| -<th>b == “+” = (+) a c</th> | |
| -</tr> | |
| -</thead> | |
| -<tbody> | |
| -<tr> | |
| -<td></td> | |
| -<td>b == “<em>” = (</em>) a c</td> | |
| -</tr> | |
| -<tr> | |
| -<td></td> | |
| -<td>b == “/” = scoreDiv a c</td> | |
| -</tr> | |
| -<tr> | |
| -<td></td> | |
| -<td>b == “Concatenate” = cat a c</td> | |
| -</tr> | |
| -</tbody> | |
| -</table> | |
| -<p>fRound :: Double -> Int<br /> | |
| -fRound = round</p> | |
| -<p>notWhole :: Double -> Bool<br /> | |
| -notWhole x = fromIntegral (round x) /= x</p> | |
| -<p>cat :: Double -> Double -> Double<br /> | |
| -cat l m | m < 0 = 3.1<br /> | |
| - | l == 0 = 3.1<br /> | |
| - | notWhole l = 3.1<br /> | |
| - | notWhole m = 3.1<br /> | |
| - | otherwise = read (show (round l) ++ show (round m) :: Double)</p> | |
| -<p>g :: (Double -> Double -> Double) -> String<br /> | |
| -g x | x 3 2 == 5 = ” + “<br /> | |
| - | x 3 2 == 1 = ” - “<br /> | |
| - | x 3 2 == 6 = ” * “<br /> | |
| - | x 18 3 == 6 = ” / “<br /> | |
| - | x 5 5 == 55 = ” concatenated left of “<br /> | |
| - | otherwise = ” cow “</p> | |
| -<p>f :: Double -> String<br /> | |
| -f x = show (round x)</p> | |
| -<p>scoreDiv :: (Eq a, Fractional a) => a -> a -> a<br /> | |
| -scoreDiv az bz | bz == 0 = 99999<br /> | |
| - | otherwise = (/) az bz</p> | |
| -<p>calc :: Double -> Double -> Double -> Double -> [(String, String, String, String, String)]<br /> | |
| -calc a b c d = [(f a’, g op1, f b’, g op2, f c’) |<br /> | |
| - [a’,b’,c’,d’] <- nub(permutations [a,b,c,d]),<br /> | |
| - op1 <- [cat, (+), (-), (<em>), scoreDiv],<br /> | |
| - op2 <- [cat, (+), (-), (</em>), scoreDiv],<br /> | |
| - op2 (op1 a’ b’) c’ == 20]</p> | |
| -<p>calc2 :: Double -> Double -> Double -> Double -> [(String, String, String, String, String)]<br /> | |
| -calc2 a b c d = [(f a’, g op1, f b’, g op2, f c’) |<br /> | |
| - [a’,b’,c’,d’] <- nub(permutations [a,b,c,d]),<br /> | |
| - op1 <- [cat, (+), (-), (<em>), scoreDiv],<br /> | |
| - op2 <- [cat, (+), (-), (</em>), scoreDiv],<br /> | |
| - op2 a’ (op1 b’ c’) == 20]</p> | |
| -<p>calc3 :: Double -> Double -> Double -> Double -> [(String, String, String, String, String, String, String)]<br /> | |
| -calc3 a b c d = [(f a’, g op1, f b’, g op3, f c’, g op2, f d’) |<br /> | |
| - [a’,b’,c’,d’] <- nub(permutations [a,b,c,d]),<br /> | |
| - op1 <- [cat, (+), (-), (<em>), scoreDiv],<br /> | |
| - op2 <- [cat, (+), (-), (</em>), scoreDiv],<br /> | |
| - op3 <- [cat, (+), (-), (*), scoreDiv],<br /> | |
| - op3 (op1 a’ b’) (op2 c’ d’) == 20]</p> | |
| -<p>calc4 :: Double -> Double -> Double -> Double -> [(String, String, String, String, String, String, String)]<br /> | |
| -calc4 a b c d = [(f a’, g op1, f b’, g op3, f c’, g op2, f d’) |<br /> | |
| - [a’,b’,c’,d’] <- nub(permutations [a,b,c,d]),<br /> | |
| - op1 <- [cat, (+), (-), (<em>), scoreDiv],<br /> | |
| - op2 <- [cat, (+), (-), (</em>), scoreDiv],<br /> | |
| - op3 <- [cat, (+), (-), (*), scoreDiv],<br /> | |
| - op3 (op2 (op1 a’ b’) c’) d’ == 20]</p> | |
| -<p>calc5 a b c d = [(f a’, g op1, f b’, g op3, f c’, g op2, f d’) |<br /> | |
| - [a’,b’,c’,d’] <- nub(permutations [a,b,c,d]),<br /> | |
| - op1 <- [cat, (+), (-), (<em>), scoreDiv],<br /> | |
| - op2 <- [cat, (+), (-), (</em>), scoreDiv],<br /> | |
| - op3 <- [cat, (+), (-), (*), scoreDiv],<br /> | |
| - op3 (op2 c’ (op1 a’ b’)) d’ == 20]</p> | |
| -<p>calc6 a b c d = [(f a’, g op1, f b’, g op3, f c’, g op2, f d’) |<br /> | |
| - [a’,b’,c’,d’] <- nub(permutations [a,b,c,d]),<br /> | |
| - op1 <- [cat, (+), (-), (<em>), scoreDiv],<br /> | |
| - op2 <- [cat, (+), (-), (</em>), scoreDiv],<br /> | |
| - op3 <- [cat, (+), (-), (*), scoreDiv],<br /> | |
| - op3 d’ (op2 (op1 a’ b’) c’) == 20]</p> | |
| -<p>calc7 a b c d = [(f a’, g op1, f b’, g op3, f c’, g op2, f d’) |<br /> | |
| - [a’,b’,c’,d’] <- nub(permutations [a,b,c,d]),<br /> | |
| - op1 <- [cat, (+), (-), (<em>), scoreDiv],<br /> | |
| - op2 <- [cat, (+), (-), (</em>), scoreDiv],<br /> | |
| - op3 <- [cat, (+), (-), (*), scoreDiv],<br /> | |
| - op3 d’ (op2 c’ (op1 a’ b’)) == 20]</p> | |
| -<p>h :: (String, String, String, String, String) -> String<br /> | |
| -h (a’,b’,c’,d’,e’) = “(” ++ a’ ++ b’ ++ c’ ++ “)” ++ d’ ++ e’ ++ ” = 20<br> “</p> | |
| -<p>h2 :: (String, String, String, String, String) -> String<br /> | |
| -h2 (a’,b’,c’,d’,e’) = a’ ++ d’ ++ “(” ++ c’ ++ b’ ++ e’++ “) = 20<br> “</p> | |
| -<p>h3 :: (String, String, String, String, String, String, String) -> String<br /> | |
| -h3 (a’,b’,c’,d’,e’,f’,g’) = “(” ++ a’ ++ b’ ++ c’ ++ “)” ++ d’ ++ “(” ++ e’ ++ f’ ++<br /> | |
| - g’ ++ “) = 20<br> “</p> | |
| -<p>h4 :: (String, String, String, String, String, String, String) -> String<br /> | |
| -h4 (a’,b’,c’,d’,e’,f’,g’) = “((” ++ a’ ++ b’ ++ c’ ++ “)” ++<br /> | |
| - f’ ++ e’ ++ “)” ++ d’ ++ g’ ++ “) = 20<br> “</p> | |
| -<p>h5 (a’,b’,c’,d’,e’,f’,g’) = “(” ++ e’ ++ f’ ++ “(” ++ a’ ++<br /> | |
| - b’ ++ c’ ++ “))” ++ d’ ++ g’ ++ “) = 20<br> “</p> | |
| -<p>h6 (a’,b’,c’,d’,e’,f’,g’) = g’ ++ d’ ++ “((” ++ a’ ++ b’ ++<br /> | |
| - c’ ++ “)” ++ f’ ++ e’ ++ “) = 20<br> “</p> | |
| -<p>h7 (a’,b’,c’,d’,e’,f’,g’) = g’ ++ d’ ++ “(” ++ e’ ++ f’ ++<br /> | |
| - “(” ++ a’ ++ b’ ++ c’ ++ “)) = 20<br> “</p> | |
| -<p>– pim x | null x = ” – There are no solutions in this category”<br /> | |
| -– | otherwise = “”</p> | |
| -<p>ca [] = [“Empty”]<br /> | |
| -ca [a, b, c, d, e] = map h (calc a b c d) ++ map h2 (calc2 a b c d) ++ map h3 (calc3 a b c d) ++ map h4 (calc4 a b c d) ++<br /> | |
| - map h5 (calc5 a b c d) ++ map h6 (calc6 a b c d) ++ map h7 (calc7 a b c d)<br /> | |
| -ca _ = [“What?”]</p> | |
| -<p>cars [a,b,c,d,e] = concat $ ca [a,b,c,d,e]</p> | |
| -<p>truck x = do <br /> | |
| - let y = map round x<br /> | |
| - let z = show (y !! 0) ++ ” ” ++ show (y !! 1) ++ ” ” ++ show (y !! 2) ++ ” ” ++ show (y !! 3) ++ “<br><br>“<br /> | |
| - let a = (z ++ cars x ++ “<br>“) :: String <br /> | |
| - return a :: IO String </p> | |
| -<p>main = truck $ roll 6 6 12 20</p> | |
| -<p>{-</p> | |
| -<pre><code>“Using the first number left of the result obtained from the second and third numbers.” ++ | |
| -map h2 (calc2 a b c d) ++ | |
| -pim (calc2 a b c d) ++ | |
| - | |
| -“Using the first two numbers and then the remaining two numbers, then using those results.”++ | |
| -map h3 (calc3 a b c d) ++ | |
| -pim (calc3 a b c d) ++ | |
| - | |
| -“Using the result from the first two numbers left of the third, then that result left of fourth number.” ++ | |
| -map h4 (calc4 a b c d) ++ | |
| -pim (calc4 a b c d) ++ | |
| - | |
| -“Using the third number left of the result obtained from the first two, then that result left of the fourth number.” ++ | |
| -map h5 (calc5 a b c d) ++ | |
| -pim (calc5 a b c d) ++ | |
| - | |
| -“Using the fourth number to the left of the result from using the first two numbers’ result left of the third.” ++ | |
| -map h6 (calc6 a b c d) ++ | |
| -pim (calc6 a b c d) ++ | |
| - | |
| -“Using the fourth number to the left of the result from using the third number left of the result from the first two.” ++ | |
| -map h7 (calc7 a b c d) ++ | |
| -pim (calc7 a b c d)</code></pre> | |
| -<p>-}</p></article></body></html> | |
| \ No newline at end of file | |
| diff --git a/yesod-websockets/Game-Example/Websockets_for_Browser_Control.html b/yesod-websockets/Game-Example/Websockets_for_Browser_Control.html | |
| deleted file mode 100644 | |
| index a87b7e1..0000000 | |
| --- a/yesod-websockets/Game-Example/Websockets_for_Browser_Control.html | |
| +++ /dev/null | |
| @@ -1,1270 +0,0 @@ | |
| -<!DOCTYPE html><html><head><meta charset="utf-8"><style>body { | |
| - width: 45em; | |
| - border: 1px solid #ddd; | |
| - outline: 1300px solid #fff; | |
| - margin: 16px auto; | |
| -} | |
| - | |
| -body .markdown-body | |
| -{ | |
| - padding: 30px; | |
| -} | |
| - | |
| -@font-face { | |
| - font-family: fontawesome-mini; | |
| - src: url(data:font/woff;charset=utf-8;base64,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) format('woff'); | |
| -} | |
| - | |
| -@font-face { | |
| - font-family: octicons-anchor; | |
| - src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAYcAA0AAAAACjQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABMAAAABwAAAAca8vGTk9TLzIAAAFMAAAARAAAAFZG1VHVY21hcAAAAZAAAAA+AAABQgAP9AdjdnQgAAAB0AAAAAQAAAAEACICiGdhc3AAAAHUAAAACAAAAAj//wADZ2x5ZgAAAdwAAADRAAABEKyikaNoZWFkAAACsAAAAC0AAAA2AtXoA2hoZWEAAALgAAAAHAAAACQHngNFaG10eAAAAvwAAAAQAAAAEAwAACJsb2NhAAADDAAAAAoAAAAKALIAVG1heHAAAAMYAAAAHwAAACABEAB2bmFtZQAAAzgAAALBAAAFu3I9x/Nwb3N0AAAF/AAAAB0AAAAvaoFvbwAAAAEAAAAAzBdyYwAAAADP2IQvAAAAAM/bz7t4nGNgZGFgnMDAysDB1Ml0hoGBoR9CM75mMGLkYGBgYmBlZsAKAtJcUxgcPsR8iGF2+O/AEMPsznAYKMwIkgMA5REMOXicY2BgYGaAYBkGRgYQsAHyGMF8FgYFIM0ChED+h5j//yEk/3KoSgZGNgYYk4GRCUgwMaACRoZhDwCs7QgGAAAAIgKIAAAAAf//AAJ4nHWMMQrCQBBF/0zWrCCIKUQsTDCL2EXMohYGSSmorScInsRGL2DOYJe0Ntp7BK+gJ1BxF1stZvjz/v8DRghQzEc4kIgKwiAppcA9LtzKLSkdNhKFY3HF4lK69ExKslx7Xa+vPRVS43G98vG1DnkDMIBUgFN0MDXflU8tbaZOUkXUH0+U27RoRpOIyCKjbMCVejwypzJJG4jIwb43rfl6wbwanocrJm9XFYfskuVC5K/TPyczNU7b84CXcbxks1Un6H6tLH9vf2LRnn8Ax7A5WQAAAHicY2BkYGAA4teL1+yI57f5ysDNwgAC529f0kOmWRiYVgEpDgYmEA8AUzEKsQAAAHicY2BkYGB2+O/AEMPCAAJAkpEBFbAAADgKAe0EAAAiAAAAAAQAAAAEAAAAAAAAKgAqACoAiAAAeJxjYGRgYGBhsGFgYgABEMkFhAwM/xn0QAIAD6YBhwB4nI1Ty07cMBS9QwKlQapQW3VXySvEqDCZGbGaHULiIQ1FKgjWMxknMfLEke2A+IJu+wntrt/QbVf9gG75jK577Lg8K1qQPCfnnnt8fX1NRC/pmjrk/zprC+8D7tBy9DHgBXoWfQ44Av8t4Bj4Z8CLtBL9CniJluPXASf0Lm4CXqFX8Q84dOLnMB17N4c7tBo1AS/Qi+hTwBH4rwHHwN8DXqQ30XXAS7QaLwSc0Gn8NuAVWou/gFmnjLrEaEh9GmDdDGgL3B4JsrRPDU2hTOiMSuJUIdKQQayiAth69r6akSSFqIJuA19TrzCIaY8sIoxyrNIrL//pw7A2iMygkX5vDj+G+kuoLdX4GlGK/8Lnlz6/h9MpmoO9rafrz7ILXEHHaAx95s9lsI7AHNMBWEZHULnfAXwG9/ZqdzLI08iuwRloXE8kfhXYAvE23+23DU3t626rbs8/8adv+9DWknsHp3E17oCf+Z48rvEQNZ78paYM38qfk3v/u3l3u3GXN2Dmvmvpf1Srwk3pB/VSsp512bA/GG5i2WJ7wu430yQ5K3nFGiOqgtmSB5pJVSizwaacmUZzZhXLlZTq8qGGFY2YcSkqbth6aW1tRmlaCFs2016m5qn36SbJrqosG4uMV4aP2PHBmB3tjtmgN2izkGQyLWprekbIntJFing32a5rKWCN/SdSoga45EJykyQ7asZvHQ8PTm6cslIpwyeyjbVltNikc2HTR7YKh9LBl9DADC0U/jLcBZDKrMhUBfQBvXRzLtFtjU9eNHKin0x5InTqb8lNpfKv1s1xHzTXRqgKzek/mb7nB8RZTCDhGEX3kK/8Q75AmUM/eLkfA+0Hi908Kx4eNsMgudg5GLdRD7a84npi+YxNr5i5KIbW5izXas7cHXIMAau1OueZhfj+cOcP3P8MNIWLyYOBuxL6DRylJ4cAAAB4nGNgYoAALjDJyIAOWMCiTIxMLDmZedkABtIBygAAAA==) format('woff'); | |
| -} | |
| - | |
| -.markdown-body { | |
| - font-family: sans-serif; | |
| - -ms-text-size-adjust: 100%; | |
| - -webkit-text-size-adjust: 100%; | |
| - color: #333333; | |
| - overflow: hidden; | |
| - font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; | |
| - font-size: 16px; | |
| - line-height: 1.6; | |
| - word-wrap: break-word; | |
| -} | |
| - | |
| -.markdown-body a { | |
| - background: transparent; | |
| -} | |
| - | |
| -.markdown-body a:active, | |
| -.markdown-body a:hover { | |
| - outline: 0; | |
| -} | |
| - | |
| -.markdown-body b, | |
| -.markdown-body strong { | |
| - font-weight: bold; | |
| -} | |
| - | |
| -.markdown-body mark { | |
| - background: #ff0; | |
| - color: #000; | |
| - font-style: italic; | |
| - font-weight: bold; | |
| -} | |
| - | |
| -.markdown-body sub, | |
| -.markdown-body sup { | |
| - font-size: 75%; | |
| - line-height: 0; | |
| - position: relative; | |
| - vertical-align: baseline; | |
| -} | |
| -.markdown-body sup { | |
| - top: -0.5em; | |
| -} | |
| -.markdown-body sub { | |
| - bottom: -0.25em; | |
| -} | |
| - | |
| -.markdown-body h1 { | |
| - font-size: 2em; | |
| - margin: 0.67em 0; | |
| -} | |
| - | |
| -.markdown-body img { | |
| - border: 0; | |
| -} | |
| - | |
| -.markdown-body hr { | |
| - -moz-box-sizing: content-box; | |
| - box-sizing: content-box; | |
| - height: 0; | |
| -} | |
| - | |
| -.markdown-body pre { | |
| - overflow: auto; | |
| -} | |
| - | |
| -.markdown-body code, | |
| -.markdown-body kbd, | |
| -.markdown-body pre, | |
| -.markdown-body samp { | |
| - font-family: monospace, monospace; | |
| - font-size: 1em; | |
| -} | |
| - | |
| -.markdown-body input { | |
| - color: inherit; | |
| - font: inherit; | |
| - margin: 0; | |
| -} | |
| - | |
| -.markdown-body html input[disabled] { | |
| - cursor: default; | |
| -} | |
| - | |
| -.markdown-body input { | |
| - line-height: normal; | |
| -} | |
| - | |
| -.markdown-body input[type="checkbox"] { | |
| - box-sizing: border-box; | |
| - padding: 0; | |
| -} | |
| - | |
| -.markdown-body table { | |
| - border-collapse: collapse; | |
| - border-spacing: 0; | |
| -} | |
| - | |
| -.markdown-body td, | |
| -.markdown-body th { | |
| - padding: 0; | |
| -} | |
| - | |
| -.markdown-body .codehilitetable { | |
| - border: 0; | |
| - border-spacing: 0; | |
| -} | |
| - | |
| -.markdown-body .codehilitetable tr { | |
| - border: 0; | |
| -} | |
| - | |
| -.markdown-body .codehilitetable pre, | |
| -.markdown-body .codehilitetable div.codehilite { | |
| - margin: 0; | |
| -} | |
| - | |
| -.markdown-body .linenos, | |
| -.markdown-body .code, | |
| -.markdown-body .codehilitetable td { | |
| - border: 0; | |
| - padding: 0; | |
| -} | |
| - | |
| -.markdown-body td:not(.linenos) .linenodiv { | |
| - padding: 0 !important; | |
| -} | |
| - | |
| -.markdown-body .code { | |
| - width: 100%; | |
| -} | |
| - | |
| -.markdown-body .linenos div pre, | |
| -.markdown-body .linenodiv pre, | |
| -.markdown-body .linenodiv { | |
| - border: 0; | |
| - -webkit-border-radius: 0; | |
| - -moz-border-radius: 0; | |
| - border-radius: 0; | |
| - -webkit-border-top-left-radius: 3px; | |
| - -webkit-border-bottom-left-radius: 3px; | |
| - -moz-border-radius-topleft: 3px; | |
| - -moz-border-radius-bottomleft: 3px; | |
| - border-top-left-radius: 3px; | |
| - border-bottom-left-radius: 3px; | |
| -} | |
| - | |
| -.markdown-body .code div pre, | |
| -.markdown-body .code div { | |
| - border: 0; | |
| - -webkit-border-radius: 0; | |
| - -moz-border-radius: 0; | |
| - border-radius: 0; | |
| - -webkit-border-top-right-radius: 3px; | |
| - -webkit-border-bottom-right-radius: 3px; | |
| - -moz-border-radius-topright: 3px; | |
| - -moz-border-radius-bottomright: 3px; | |
| - border-top-right-radius: 3px; | |
| - border-bottom-right-radius: 3px; | |
| -} | |
| - | |
| -.markdown-body * { | |
| - -moz-box-sizing: border-box; | |
| - box-sizing: border-box; | |
| -} | |
| - | |
| -.markdown-body input { | |
| - font: 13px Helvetica, arial, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol"; | |
| - line-height: 1.4; | |
| -} | |
| - | |
| -.markdown-body a { | |
| - color: #4183c4; | |
| - text-decoration: none; | |
| -} | |
| - | |
| -.markdown-body a:hover, | |
| -.markdown-body a:focus, | |
| -.markdown-body a:active { | |
| - text-decoration: underline; | |
| -} | |
| - | |
| -.markdown-body hr { | |
| - height: 0; | |
| - margin: 15px 0; | |
| - overflow: hidden; | |
| - background: transparent; | |
| - border: 0; | |
| - border-bottom: 1px solid #ddd; | |
| -} | |
| - | |
| -.markdown-body hr:before, | |
| -.markdown-body hr:after { | |
| - display: table; | |
| - content: " "; | |
| -} | |
| - | |
| -.markdown-body hr:after { | |
| - clear: both; | |
| -} | |
| - | |
| -.markdown-body h1, | |
| -.markdown-body h2, | |
| -.markdown-body h3, | |
| -.markdown-body h4, | |
| -.markdown-body h5, | |
| -.markdown-body h6 { | |
| - margin-top: 15px; | |
| - margin-bottom: 15px; | |
| - line-height: 1.1; | |
| -} | |
| - | |
| -.markdown-body h1 { | |
| - font-size: 30px; | |
| -} | |
| - | |
| -.markdown-body h2 { | |
| - font-size: 21px; | |
| -} | |
| - | |
| -.markdown-body h3 { | |
| - font-size: 16px; | |
| -} | |
| - | |
| -.markdown-body h4 { | |
| - font-size: 14px; | |
| -} | |
| - | |
| -.markdown-body h5 { | |
| - font-size: 12px; | |
| -} | |
| - | |
| -.markdown-body h6 { | |
| - font-size: 11px; | |
| -} | |
| - | |
| -.markdown-body blockquote { | |
| - margin: 0; | |
| -} | |
| - | |
| -.markdown-body ul, | |
| -.markdown-body ol { | |
| - padding: 0; | |
| - margin-top: 0; | |
| - margin-bottom: 0; | |
| -} | |
| - | |
| -.markdown-body ol ol, | |
| -.markdown-body ul ol { | |
| - list-style-type: lower-roman; | |
| -} | |
| - | |
| -.markdown-body ul ul ol, | |
| -.markdown-body ul ol ol, | |
| -.markdown-body ol ul ol, | |
| -.markdown-body ol ol ol { | |
| - list-style-type: lower-alpha; | |
| -} | |
| - | |
| -.markdown-body dd { | |
| - margin-left: 0; | |
| -} | |
| - | |
| -.markdown-body code, | |
| -.markdown-body pre, | |
| -.markdown-body samp { | |
| - font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; | |
| - font-size: 12px; | |
| -} | |
| - | |
| -.markdown-body pre { | |
| - margin-top: 0; | |
| - margin-bottom: 0; | |
| -} | |
| - | |
| -.markdown-body kbd { | |
| - background-color: #e7e7e7; | |
| - background-image: -moz-linear-gradient(#fefefe, #e7e7e7); | |
| - background-image: -webkit-linear-gradient(#fefefe, #e7e7e7); | |
| - background-image: linear-gradient(#fefefe, #e7e7e7); | |
| - background-repeat: repeat-x; | |
| - border-radius: 2px; | |
| - border: 1px solid #cfcfcf; | |
| - color: #000; | |
| - padding: 3px 5px; | |
| - line-height: 10px; | |
| - font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace; | |
| - display: inline-block; | |
| -} | |
| - | |
| -.markdown-body>*:first-child { | |
| - margin-top: 0 !important; | |
| -} | |
| - | |
| -.markdown-body>*:last-child { | |
| - margin-bottom: 0 !important; | |
| -} | |
| - | |
| -.markdown-body .headeranchor-link { | |
| - position: absolute; | |
| - top: 0; | |
| - bottom: 0; | |
| - left: 0; | |
| - display: block; | |
| - padding-right: 6px; | |
| - padding-left: 30px; | |
| - margin-left: -30px; | |
| -} | |
| - | |
| -.markdown-body .headeranchor-link:focus { | |
| - outline: none; | |
| -} | |
| - | |
| -.markdown-body h1, | |
| -.markdown-body h2, | |
| -.markdown-body h3, | |
| -.markdown-body h4, | |
| -.markdown-body h5, | |
| -.markdown-body h6 { | |
| - position: relative; | |
| - margin-top: 1em; | |
| - margin-bottom: 16px; | |
| - font-weight: bold; | |
| - line-height: 1.4; | |
| -} | |
| - | |
| -.markdown-body h1 .headeranchor, | |
| -.markdown-body h2 .headeranchor, | |
| -.markdown-body h3 .headeranchor, | |
| -.markdown-body h4 .headeranchor, | |
| -.markdown-body h5 .headeranchor, | |
| -.markdown-body h6 .headeranchor { | |
| - display: none; | |
| - color: #000; | |
| - vertical-align: middle; | |
| -} | |
| - | |
| -.markdown-body h1:hover .headeranchor-link, | |
| -.markdown-body h2:hover .headeranchor-link, | |
| -.markdown-body h3:hover .headeranchor-link, | |
| -.markdown-body h4:hover .headeranchor-link, | |
| -.markdown-body h5:hover .headeranchor-link, | |
| -.markdown-body h6:hover .headeranchor-link { | |
| - height: 1em; | |
| - padding-left: 8px; | |
| - margin-left: -30px; | |
| - line-height: 1; | |
| - text-decoration: none; | |
| -} | |
| - | |
| -.markdown-body h1:hover .headeranchor-link .headeranchor, | |
| -.markdown-body h2:hover .headeranchor-link .headeranchor, | |
| -.markdown-body h3:hover .headeranchor-link .headeranchor, | |
| -.markdown-body h4:hover .headeranchor-link .headeranchor, | |
| -.markdown-body h5:hover .headeranchor-link .headeranchor, | |
| -.markdown-body h6:hover .headeranchor-link .headeranchor { | |
| - display: inline-block; | |
| -} | |
| - | |
| -.markdown-body h1 { | |
| - padding-bottom: 0.3em; | |
| - font-size: 2.25em; | |
| - line-height: 1.2; | |
| - border-bottom: 1px solid #eee; | |
| -} | |
| - | |
| -.markdown-body h2 { | |
| - padding-bottom: 0.3em; | |
| - font-size: 1.75em; | |
| - line-height: 1.225; | |
| - border-bottom: 1px solid #eee; | |
| -} | |
| - | |
| -.markdown-body h3 { | |
| - font-size: 1.5em; | |
| - line-height: 1.43; | |
| -} | |
| - | |
| -.markdown-body h4 { | |
| - font-size: 1.25em; | |
| -} | |
| - | |
| -.markdown-body h5 { | |
| - font-size: 1em; | |
| -} | |
| - | |
| -.markdown-body h6 { | |
| - font-size: 1em; | |
| - color: #777; | |
| -} | |
| - | |
| -.markdown-body p, | |
| -.markdown-body blockquote, | |
| -.markdown-body ul, | |
| -.markdown-body ol, | |
| -.markdown-body dl, | |
| -.markdown-body table, | |
| -.markdown-body pre, | |
| -.markdown-body .admonition { | |
| - margin-top: 0; | |
| - margin-bottom: 16px; | |
| -} | |
| - | |
| -.markdown-body hr { | |
| - height: 4px; | |
| - padding: 0; | |
| - margin: 16px 0; | |
| - background-color: #e7e7e7; | |
| - border: 0 none; | |
| -} | |
| - | |
| -.markdown-body ul, | |
| -.markdown-body ol { | |
| - padding-left: 2em; | |
| -} | |
| - | |
| -.markdown-body ul ul, | |
| -.markdown-body ul ol, | |
| -.markdown-body ol ol, | |
| -.markdown-body ol ul { | |
| - margin-top: 0; | |
| - margin-bottom: 0; | |
| -} | |
| - | |
| -.markdown-body li>p { | |
| - margin-top: 16px; | |
| -} | |
| - | |
| -.markdown-body dl { | |
| - padding: 0; | |
| -} | |
| - | |
| -.markdown-body dl dt { | |
| - padding: 0; | |
| - margin-top: 16px; | |
| - font-size: 1em; | |
| - font-style: italic; | |
| - font-weight: bold; | |
| -} | |
| - | |
| -.markdown-body dl dd { | |
| - padding: 0 16px; | |
| - margin-bottom: 16px; | |
| -} | |
| - | |
| -.markdown-body blockquote { | |
| - padding: 0 15px; | |
| - color: #777; | |
| - border-left: 4px solid #ddd; | |
| -} | |
| - | |
| -.markdown-body blockquote>:first-child { | |
| - margin-top: 0; | |
| -} | |
| - | |
| -.markdown-body blockquote>:last-child { | |
| - margin-bottom: 0; | |
| -} | |
| - | |
| -.markdown-body table { | |
| - display: block; | |
| - width: 100%; | |
| - overflow: auto; | |
| - word-break: normal; | |
| - word-break: keep-all; | |
| -} | |
| - | |
| -.markdown-body table th { | |
| - font-weight: bold; | |
| -} | |
| - | |
| -.markdown-body table th, | |
| -.markdown-body table td { | |
| - padding: 6px 13px; | |
| - border: 1px solid #ddd; | |
| -} | |
| - | |
| -.markdown-body table tr { | |
| - background-color: #fff; | |
| - border-top: 1px solid #ccc; | |
| -} | |
| - | |
| -.markdown-body table tr:nth-child(2n) { | |
| - background-color: #f8f8f8; | |
| -} | |
| - | |
| -.markdown-body img { | |
| - max-width: 100%; | |
| - -moz-box-sizing: border-box; | |
| - box-sizing: border-box; | |
| -} | |
| - | |
| -.markdown-body code, | |
| -.markdown-body samp { | |
| - padding: 0; | |
| - padding-top: 0.2em; | |
| - padding-bottom: 0.2em; | |
| - margin: 0; | |
| - font-size: 85%; | |
| - background-color: rgba(0,0,0,0.04); | |
| - border-radius: 3px; | |
| -} | |
| - | |
| -.markdown-body code:before, | |
| -.markdown-body code:after { | |
| - letter-spacing: -0.2em; | |
| - content: "\00a0"; | |
| -} | |
| - | |
| -.markdown-body pre>code { | |
| - padding: 0; | |
| - margin: 0; | |
| - font-size: 100%; | |
| - word-break: normal; | |
| - white-space: pre; | |
| - background: transparent; | |
| - border: 0; | |
| -} | |
| - | |
| -.markdown-body .codehilite { | |
| - margin-bottom: 16px; | |
| -} | |
| - | |
| -.markdown-body .codehilite pre, | |
| -.markdown-body pre { | |
| - padding: 16px; | |
| - overflow: auto; | |
| - font-size: 85%; | |
| - line-height: 1.45; | |
| - background-color: #f7f7f7; | |
| - border-radius: 3px; | |
| -} | |
| - | |
| -.markdown-body .codehilite pre { | |
| - margin-bottom: 0; | |
| - word-break: normal; | |
| -} | |
| - | |
| -.markdown-body pre { | |
| - word-wrap: normal; | |
| -} | |
| - | |
| -.markdown-body pre code { | |
| - display: inline; | |
| - max-width: initial; | |
| - padding: 0; | |
| - margin: 0; | |
| - overflow: initial; | |
| - line-height: inherit; | |
| - word-wrap: normal; | |
| - background-color: transparent; | |
| - border: 0; | |
| -} | |
| - | |
| -.markdown-body pre code:before, | |
| -.markdown-body pre code:after { | |
| - content: normal; | |
| -} | |
| - | |
| -/* Admonition */ | |
| -.markdown-body .admonition { | |
| - -webkit-border-radius: 3px; | |
| - -moz-border-radius: 3px; | |
| - position: relative; | |
| - border-radius: 3px; | |
| - border: 1px solid #e0e0e0; | |
| - border-left: 6px solid #333; | |
| - padding: 10px 10px 10px 30px; | |
| -} | |
| - | |
| -.markdown-body .admonition table { | |
| - color: #333; | |
| -} | |
| - | |
| -.markdown-body .admonition p { | |
| - padding: 0; | |
| -} | |
| - | |
| -.markdown-body .admonition-title { | |
| - font-weight: bold; | |
| - margin: 0; | |
| -} | |
| - | |
| -.markdown-body .admonition>.admonition-title { | |
| - color: #333; | |
| -} | |
| - | |
| -.markdown-body .attention>.admonition-title { | |
| - color: #a6d796; | |
| -} | |
| - | |
| -.markdown-body .caution>.admonition-title { | |
| - color: #d7a796; | |
| -} | |
| - | |
| -.markdown-body .hint>.admonition-title { | |
| - color: #96c6d7; | |
| -} | |
| - | |
| -.markdown-body .danger>.admonition-title { | |
| - color: #c25f77; | |
| -} | |
| - | |
| -.markdown-body .question>.admonition-title { | |
| - color: #96a6d7; | |
| -} | |
| - | |
| -.markdown-body .note>.admonition-title { | |
| - color: #d7c896; | |
| -} | |
| - | |
| -.markdown-body .admonition:before, | |
| -.markdown-body .attention:before, | |
| -.markdown-body .caution:before, | |
| -.markdown-body .hint:before, | |
| -.markdown-body .danger:before, | |
| -.markdown-body .question:before, | |
| -.markdown-body .note:before { | |
| - font: normal normal 16px fontawesome-mini; | |
| - -moz-osx-font-smoothing: grayscale; | |
| - -webkit-user-select: none; | |
| - -moz-user-select: none; | |
| - -ms-user-select: none; | |
| - user-select: none; | |
| - line-height: 1.5; | |
| - color: #333; | |
| - position: absolute; | |
| - left: 0; | |
| - top: 0; | |
| - padding-top: 10px; | |
| - padding-left: 10px; | |
| -} | |
| - | |
| -.markdown-body .admonition:before { | |
| - content: "\f056\00a0"; | |
| - color: 333; | |
| -} | |
| - | |
| -.markdown-body .attention:before { | |
| - content: "\f058\00a0"; | |
| - color: #a6d796; | |
| -} | |
| - | |
| -.markdown-body .caution:before { | |
| - content: "\f06a\00a0"; | |
| - color: #d7a796; | |
| -} | |
| - | |
| -.markdown-body .hint:before { | |
| - content: "\f05a\00a0"; | |
| - color: #96c6d7; | |
| -} | |
| - | |
| -.markdown-body .danger:before { | |
| - content: "\f057\00a0"; | |
| - color: #c25f77; | |
| -} | |
| - | |
| -.markdown-body .question:before { | |
| - content: "\f059\00a0"; | |
| - color: #96a6d7; | |
| -} | |
| - | |
| -.markdown-body .note:before { | |
| - content: "\f040\00a0"; | |
| - color: #d7c896; | |
| -} | |
| - | |
| -.markdown-body .admonition::after { | |
| - content: normal; | |
| -} | |
| - | |
| -.markdown-body .attention { | |
| - border-left: 6px solid #a6d796; | |
| -} | |
| - | |
| -.markdown-body .caution { | |
| - border-left: 6px solid #d7a796; | |
| -} | |
| - | |
| -.markdown-body .hint { | |
| - border-left: 6px solid #96c6d7; | |
| -} | |
| - | |
| -.markdown-body .danger { | |
| - border-left: 6px solid #c25f77; | |
| -} | |
| - | |
| -.markdown-body .question { | |
| - border-left: 6px solid #96a6d7; | |
| -} | |
| - | |
| -.markdown-body .note { | |
| - border-left: 6px solid #d7c896; | |
| -} | |
| - | |
| -.markdown-body .admonition>*:first-child { | |
| - margin-top: 0 !important; | |
| -} | |
| - | |
| -.markdown-body .admonition>*:last-child { | |
| - margin-bottom: 0 !important; | |
| -} | |
| - | |
| -/* progress bar*/ | |
| -.markdown-body .progress { | |
| - display: block; | |
| - width: 300px; | |
| - margin: 10px 0; | |
| - height: 24px; | |
| - -webkit-border-radius: 3px; | |
| - -moz-border-radius: 3px; | |
| - border-radius: 3px; | |
| - background-color: #ededed; | |
| - position: relative; | |
| - box-shadow: inset -1px 1px 3px rgba(0, 0, 0, .1); | |
| -} | |
| - | |
| -.markdown-body .progress-label { | |
| - position: absolute; | |
| - text-align: center; | |
| - font-weight: bold; | |
| - width: 100%; margin: 0; | |
| - line-height: 24px; | |
| - color: #333; | |
| - 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; | |
| - -webkit-font-smoothing: antialiased !important; | |
| - white-space: nowrap; | |
| - overflow: hidden; | |
| -} | |
| - | |
| -.markdown-body .progress-bar { | |
| - height: 24px; | |
| - float: left; | |
| - -webkit-border-radius: 3px; | |
| - -moz-border-radius: 3px; | |
| - border-radius: 3px; | |
| - background-color: #96c6d7; | |
| - box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), inset 0 -1px 0 rgba(0, 0, 0, .1); | |
| - background-size: 30px 30px; | |
| - background-image: -webkit-linear-gradient( | |
| - 135deg, rgba(255, 255, 255, .4) 27%, | |
| - transparent 27%, | |
| - transparent 52%, rgba(255, 255, 255, .4) 52%, | |
| - rgba(255, 255, 255, .4) 77%, | |
| - transparent 77%, transparent | |
| - ); | |
| - background-image: -moz-linear-gradient( | |
| - 135deg, | |
| - rgba(255, 255, 255, .4) 27%, transparent 27%, | |
| - transparent 52%, rgba(255, 255, 255, .4) 52%, | |
| - rgba(255, 255, 255, .4) 77%, transparent 77%, | |
| - transparent | |
| - ); | |
| - background-image: -ms-linear-gradient( | |
| - 135deg, | |
| - rgba(255, 255, 255, .4) 27%, transparent 27%, | |
| - transparent 52%, rgba(255, 255, 255, .4) 52%, | |
| - rgba(255, 255, 255, .4) 77%, transparent 77%, | |
| - transparent | |
| - ); | |
| - background-image: -o-linear-gradient( | |
| - 135deg, | |
| - rgba(255, 255, 255, .4) 27%, transparent 27%, | |
| - transparent 52%, rgba(255, 255, 255, .4) 52%, | |
| - rgba(255, 255, 255, .4) 77%, transparent 77%, | |
| - transparent | |
| - ); | |
| - background-image: linear-gradient( | |
| - 135deg, | |
| - rgba(255, 255, 255, .4) 27%, transparent 27%, | |
| - transparent 52%, rgba(255, 255, 255, .4) 52%, | |
| - rgba(255, 255, 255, .4) 77%, transparent 77%, | |
| - transparent | |
| - ); | |
| -} | |
| - | |
| -.markdown-body .progress-100plus .progress-bar { | |
| - background-color: #a6d796; | |
| -} | |
| - | |
| -.markdown-body .progress-80plus .progress-bar { | |
| - background-color: #c6d796; | |
| -} | |
| - | |
| -.markdown-body .progress-60plus .progress-bar { | |
| - background-color: #d7c896; | |
| -} | |
| - | |
| -.markdown-body .progress-40plus .progress-bar { | |
| - background-color: #d7a796; | |
| -} | |
| - | |
| -.markdown-body .progress-20plus .progress-bar { | |
| - background-color: #d796a6; | |
| -} | |
| - | |
| -.markdown-body .progress-0plus .progress-bar { | |
| - background-color: #c25f77; | |
| -} | |
| - | |
| -.markdown-body .candystripe-animate .progress-bar{ | |
| - -webkit-animation: animate-stripes 3s linear infinite; | |
| - -moz-animation: animate-stripes 3s linear infinite; | |
| - animation: animate-stripes 3s linear infinite; | |
| -} | |
| - | |
| -@-webkit-keyframes animate-stripes { | |
| - 0% { | |
| - background-position: 0 0; | |
| - } | |
| - | |
| - 100% { | |
| - background-position: 60px 0; | |
| - } | |
| -} | |
| - | |
| -@-moz-keyframes animate-stripes { | |
| - 0% { | |
| - background-position: 0 0; | |
| - } | |
| - | |
| - 100% { | |
| - background-position: 60px 0; | |
| - } | |
| -} | |
| - | |
| -@keyframes animate-stripes { | |
| - 0% { | |
| - background-position: 0 0; | |
| - } | |
| - | |
| - 100% { | |
| - background-position: 60px 0; | |
| - } | |
| -} | |
| - | |
| -.markdown-body .gloss .progress-bar { | |
| - box-shadow: | |
| - inset 0 4px 12px rgba(255, 255, 255, .7), | |
| - inset 0 -12px 0 rgba(0, 0, 0, .05); | |
| -} | |
| - | |
| -/* Multimarkdown Critic Blocks */ | |
| -.markdown-body .critic_mark { | |
| - background: #ff0; | |
| -} | |
| - | |
| -.markdown-body .critic_delete { | |
| - color: #c82829; | |
| - text-decoration: line-through; | |
| -} | |
| - | |
| -.markdown-body .critic_insert { | |
| - color: #718c00 ; | |
| - text-decoration: underline; | |
| -} | |
| - | |
| -.markdown-body .critic_comment { | |
| - color: #8e908c; | |
| - font-style: italic; | |
| -} | |
| - | |
| -.markdown-body .headeranchor { | |
| - font: normal normal 16px octicons-anchor; | |
| - line-height: 1; | |
| - display: inline-block; | |
| - text-decoration: none; | |
| - -webkit-font-smoothing: antialiased; | |
| - -moz-osx-font-smoothing: grayscale; | |
| - -webkit-user-select: none; | |
| - -moz-user-select: none; | |
| - -ms-user-select: none; | |
| - user-select: none; | |
| -} | |
| - | |
| -.headeranchor:before { | |
| - content: '\f05c'; | |
| -} | |
| - | |
| -.markdown-body .task-list-item { | |
| - list-style-type: none; | |
| -} | |
| - | |
| -.markdown-body .task-list-item+.task-list-item { | |
| - margin-top: 3px; | |
| -} | |
| - | |
| -.markdown-body .task-list-item input { | |
| - margin: 0 4px 0.25em -20px; | |
| - vertical-align: middle; | |
| -} | |
| - | |
| -/* Media */ | |
| -@media only screen and (min-width: 480px) { | |
| - .markdown-body { | |
| - font-size:14px; | |
| - } | |
| -} | |
| - | |
| -@media only screen and (min-width: 768px) { | |
| - .markdown-body { | |
| - font-size:16px; | |
| - } | |
| -} | |
| - | |
| -@media print { | |
| - .markdown-body * { | |
| - background: transparent !important; | |
| - color: black !important; | |
| - filter:none !important; | |
| - -ms-filter: none !important; | |
| - } | |
| - | |
| - .markdown-body { | |
| - font-size:12pt; | |
| - max-width:100%; | |
| - outline:none; | |
| - border: 0; | |
| - } | |
| - | |
| - .markdown-body a, | |
| - .markdown-body a:visited { | |
| - text-decoration: underline; | |
| - } | |
| - | |
| - .markdown-body .headeranchor-link { | |
| - display: none; | |
| - } | |
| - | |
| - .markdown-body a[href]:after { | |
| - content: " (" attr(href) ")"; | |
| - } | |
| - | |
| - .markdown-body abbr[title]:after { | |
| - content: " (" attr(title) ")"; | |
| - } | |
| - | |
| - .markdown-body .ir a:after, | |
| - .markdown-body a[href^="javascript:"]:after, | |
| - .markdown-body a[href^="#"]:after { | |
| - content: ""; | |
| - } | |
| - | |
| - .markdown-body pre { | |
| - white-space: pre; | |
| - white-space: pre-wrap; | |
| - word-wrap: break-word; | |
| - } | |
| - | |
| - .markdown-body pre, | |
| - .markdown-body blockquote { | |
| - border: 1px solid #999; | |
| - padding-right: 1em; | |
| - page-break-inside: avoid; | |
| - } | |
| - | |
| - .markdown-body .progress, | |
| - .markdown-body .progress-bar { | |
| - -moz-box-shadow: none; | |
| - -webkit-box-shadow: none; | |
| - box-shadow: none; | |
| - } | |
| - | |
| - .markdown-body .progress { | |
| - border: 1px solid #ddd; | |
| - } | |
| - | |
| - .markdown-body .progress-bar { | |
| - height: 22px; | |
| - border-right: 1px solid #ddd; | |
| - } | |
| - | |
| - .markdown-body tr, | |
| - .markdown-body img { | |
| - page-break-inside: avoid; | |
| - } | |
| - | |
| - .markdown-body img { | |
| - max-width: 100% !important; | |
| - } | |
| - | |
| - .markdown-body p, | |
| - .markdown-body h2, | |
| - .markdown-body h3 { | |
| - orphans: 3; | |
| - widows: 3; | |
| - } | |
| - | |
| - .markdown-body h2, | |
| - .markdown-body h3 { | |
| - page-break-after: avoid; | |
| - } | |
| -} | |
| -</style><title>Websockets_for_Browser_Control</title></head><body><article class="markdown-body"><h2 id="browser-control-with-websockets"><a name="user-content-browser-control-with-websockets" href="#browser-control-with-websockets" class="headeranchor-link" aria-hidden="true"><span class="headeranchor"></span></a>BROWSER CONTROL WITH WEBSOCKETS</h2> | |
| -<p><strong>INTRODUCTION</strong></p> | |
| -<p>The Haskell version of the game of <em>Score</em> was developed by modifying the chat.hs file at <a href="http://github.com/yesodweb/websockets">http://github.com/yesodweb/websockets</a>. The chat login remains the same, but the chat window is replaced by the real time, multi-player game of score. Websockets are used to provide players with a scoreboard that keeps track of participants and their current scores with:</p> | |
| -<ul> | |
| -<li>no backend database or flatfile</li> | |
| -<li>no persistent entities or transactions</li> | |
| -<li>no cookies</li> | |
| -</ul> | |
| -<p>The online browsers add and deduct game points, maintain the list of current players, and keep track of scores by manipulating the values of javascript variables. The Yesod/Warp server does not get involved. It generates random numbers simulating rolls of four dice: two six-sided dice, one twelve-sided die, and one twenty-sided die. Other than that, the server acts mainly as a conduit for messages from individual players to the online group.</p> | |
| -<p>The game of <em>Score</em> shows how coders familiar with Javascript but new to Haskell can get fairly complex Haskell web applications up and running using the coding techniques with which they are familiar. It might also remind seasoned Haskell programmers that websockets can sometimes be very useful in creating fast, efficient web applications that delegate much or most of the work to the browsers.</p> | |
| -<p><strong>THE ELEGANCE OF JAVASCRIPT</strong></p> | |
| -<p>Here’s how the game works: When a player clicks “ROLL”, the server sends a fresh set of four random numbers to all participants. If a player sees a way to make the number 20 by means of two or three operations involving any combination of addition, subtraction, multiplication, division, or concatenation, the player can click the button labeled “SCORE” to start a 30-second countdown and try to win a point. Clicking “SCORE” sends a message to the server which is passed on to all browsers setting T = 30. That’s all it takes to start the clocks running. Just set the global variable T to anything above 0 and a countdown back to 0 begins. A “setInterval” function cycles once per second, testing the value of T. If T is greater than 0, it sets<br /> | |
| -<pre><code class="javascript"> T = T - 1 | |
| -</code></pre><br /> | |
| -and prints the value in the browser. The visible countdown function is not involved in keeping score; that is done by other countdown routings activated by clicking “SCORE” or “IMPOSSIBLE”.</p> | |
| -<p>Clicking “IMPOSSIBLE” sends a message to all participants (routed through the server) setting T = 60. After 60 seconds, the player who clicked “IMPOSSIBLE” gets one point; but if during the 60-second countdown another player clicks “SCORE”, a message is routed to all players setting T = 30. If the player who clicked “SCORE” makes the number 20 before T = 0, that player gains one point and the player who clicked impossible loses one point.</p> | |
| -<p>As soon as a player scores, or when a player fails to obtain the number 20 after 30 seconds or three computations, the player’s score is increased or decreased and a message goes out to all browsers announcing the outcome and setting T = 0 so another round can begin.</p> | |
| -<p>In other words, a player who clicks “SCORE” loses a point if 30 seconds elapse or if three computations fail to produce 20, and gains a point if 20 is computed within the time limit. A player who clicks “IMPOSSIBLE” gains a point unless another player clickes “SCORE” and computes the number 20 within 30 seconds. Individual scores are maintained in each player’s browser in the variable “score”; but almost immediately, all of the scoreboards on all participating browsers see the update. Thanks to Javascript’s mutable variables, updates are accomplished simply and elegantly as follows:</p> | |
| -<p>Every three seconds, each player sends his or her name and score to the server which immediately broadcases the information to all participating browsers. The name and score are placed in a javascript object in the following format:</p> | |
| -<p><pre><code class="javascript">{"player" : {"player",score}} | |
| -</code></pre><br /> | |
| -Each browser has an object called “game”. When a player/score object arrives, say<br /> | |
| -<pre><code class="javascript">{"Fred" : {"player":"Fred, "score":42}} | |
| -</code></pre><br /> | |
| -the code<br /> | |
| -<pre><code class="javascript">game["Fred"] = {"Fred" : {"player":"Fred, "score":42}} | |
| -</code></pre><br /> | |
| -is executed. As with “T”, the mutable global variable “game” provides an efficient way to maintain identical, updated scoreboards on all browsers. Javascript objects cannot have duplicate keys, so it doesn’t matter if Fred was already in game, perhaps with a different score. The new Fred object bumps the older one out of the way and the next scoreboard update shows the result.</p> | |
| -<p><strong>Browser disconnects</strong></p> | |
| -<p>Disconnects are noted without parsing Internet protocol packets or interacting with session cookies. There are no session cookies, and the server does not participate in maintaining up-to-date scoreboards. The browsers take care of this with the following code:<br /> | |
| -<pre><code class="javascript"> setInterval (function () { | |
| - game = {}; | |
| - }, 10000); | |
| -</code></pre><br /> | |
| -Every 10 seconds, on each browser, all players are deleted from game. The game object is soon replenished with the names and scores of all participants because each broser refreshes game every 3 seconds using the code<br /> | |
| -<pre><code class="javascript"> setInterval (function () { | |
| - conn.send("COWS," + player + "," + score); | |
| - }, 3000); | |
| -</code></pre><br /> | |
| -When browsers receive messages beginning with “COWS”, they react as follows:<br /> | |
| -<pre><code class="javascript"> if (data.substring(0,4) == "COWS") { | |
| - var x = data; | |
| - var l = x.split(","); // creates an array | |
| - var pl = l[1]; | |
| - var sc = l[2]; | |
| - game[pl] = {"player" : pl, "score" : sc}; | |
| - players[pl] = pl | |
| - } | |
| -</code></pre><br /> | |
| -Notice that the object “players” gets only the player’s name, but not the score. The “players” object is used to screen attempts to log in with names that are already taken. The first four lines inside the if clause split the incoming string into a three-member list and attach the player and the score to the object “game”. Mutable global variable allow much to be accomplished with few lines of code. The server could participate in time keeping and scoreboard updating but MVars, the state monad, stm, or some such way of avoiding side effects seems like a lot of work compared with the simple elegance of using the mutable global variables “T” and “game”. For production code, names such as “SCH_T” and “SCH_game” might be used to avoid inadvertant clashes with someone else’s code using the global variables “T” and “game”. the prefix “SCH” could be used to create a namespace for code written by Schalk.</p> | |
| -<p>The code for the game of <strong>Score</strong> is pretty straghtforward. One part that might need an explanation is the code involving a click of the “IMPOSSIBLE” button. When that happens, clickers send their names to all the other browsers (through the server) as follows:<br /> | |
| -<pre><code class="javascript"> $("#IMPOSSIBLE").click( function () { | |
| - score = score - 1; | |
| - T3 = 61; | |
| - localCalc2(); | |
| - conn.send("SIXTY" + player); | |
| - }); | |
| -</code></pre></p> | |
| -<p>One point is immediately deducted from the clicker’s score, but two points will be added if the timer reaches T3 = 0, or if someone clicks “SCORE” and either can’t show a solution within 30 seconds or performs 3 computations which don’t result in the number 20. T3 is set for only the clicker’s browser. The local function localCalc2 is calledas follows:<br /> | |
| -<pre><code class="javascript"> var localCalc2 = function() { | |
| - setTimeout (function () { | |
| - T3 = T3 - 1; | |
| - if (T3 > 0) { | |
| - localCalc2(); | |
| - } | |
| - if (T3 == 0) { | |
| - score += 2; | |
| - return; | |
| - } | |
| - else return; // not necessary | |
| - }, 1000) | |
| - } | |
| -</code></pre><br /> | |
| -Clicking “IMPOSSIBLE” caused the string (“SIXTY” + player) to be sent to the server and broadcast to all participants. Each browser intercepts the string as follows:<br /> | |
| -<pre><code class="javascript"> if (data.substring(0,5) == "SIXTY") { | |
| - T = 61; | |
| - var name = data.substring(5); | |
| - $("#SCORE3").show(); | |
| - $("#roll").hide(); | |
| - $("#submitB").hide(); | |
| - $("#SCORE1").hide(); | |
| - $("#IMPOSSIBLE").hide(); | |
| - $("#output2").show(); | |
| - $("#output2").html("The deduction from " + name + "'s score might be temporary.") | |
| - impossiblePlayer = e.data.substring(5); | |
| - $("#output4").html("impossiblePlayer is " + impossiblePlayer); | |
| - } | |
| -</code></pre><br /> | |
| -T = 61 sets the countdown in all of the browsers. The rest of the code is just display housekeeping. Clicking “SCORE” will reset the countdown to 30 with the simple instruction<br /> | |
| -<pre><code class="javascript"> T = 31 | |
| -</code></pre><br /> | |
| -The reason the countdown timer can be set and re-set by changing the value of T is this perpetually (up to the timeout limit) cycling code:</p> | |
| -<p><pre><code class="javascript"> SCH_t = 3600 | |
| - setInterval (function () { | |
| - SCH_t = SCH_t - 1; | |
| - var timer = function () { | |
| - if (T < 1) { | |
| - return; | |
| - } else { | |
| - T = T - 1; | |
| - $("#output").html(T); | |
| - } | |
| - } | |
| - timer(); | |
| - }, 1000); | |
| -</code></pre><br /> | |
| -Once every second, setInterval checks to see if T is greater than 0. If it is, it deminishes T by 1 and displays its value in the browser. This is only for display. Scorekeeping depends on T2, T3, and T4, which are not shown in the browsers.</p> | |
| -<p>If someone clicks “SCORE” during the 60 countdown, T3 = (-1) is set, stopping the local, invisible <em>Impossible</em> countdown and starting localCalc3 as follows:<br /> | |
| -<pre><code class="javascript"> $("#SCORE3").click( function () { | |
| - $("#submitA").show(); | |
| - conn.send("THIRTY2"); | |
| - T4 = 31; | |
| - localCalc3(); | |
| - }); | |
| -</code></pre><br /> | |
| -Hhere is localCalc3:<br /> | |
| -<pre><code class="javascript"> var localCalc3 = function() { | |
| - setTimeout (function () { | |
| - T4 = T4 - 1; | |
| - if (T4 > 0) { | |
| - localCalc3(); | |
| - } | |
| - else if (T4 == 0) { | |
| - score -= 1; | |
| - return; | |
| - } | |
| - else { | |
| - return; | |
| - } | |
| - }, 1000) | |
| - } | |
| -</code></pre><br /> | |
| -The clicker will lose a point if the countdown is not interrupted by computing the number 20. Here is how the interruption occurs:<br /> | |
| -<pre><code class="javascript"> var firstCalc = function (a,b,c) { | |
| - var res; | |
| - switch (b) { | |
| - case 0: res = a + c; | |
| - break; | |
| - case 1: res = a - c; | |
| - break; | |
| - case 2: res = a * c; | |
| - break; | |
| - case 3: res = a / c; | |
| - break; | |
| - case 4: res = a+""+c | |
| - } | |
| - return res; | |
| - }; | |
| - | |
| - var calculate = function (a,b,c) { | |
| - var res; | |
| - switch (b) { | |
| - case 0: res = a + c; | |
| - break; | |
| - case 1: res = a - c; | |
| - break; | |
| - case 2: res = a * c; | |
| - break; | |
| - case 3: res = a / c; | |
| - break; | |
| - case 4: res = a+""+c | |
| - } | |
| - if (res == 20) { | |
| - score += 1; | |
| - conn.send("WINNER" + player) | |
| - } | |
| - return res; | |
| - }; | |
| -</code></pre><br /> | |
| -Players don’t get credit for computing 20 in the first round, so firstCalc does not affect the score. But calculate has the block:<br /> | |
| -<pre><code class="javascript"> if (res == 20) { | |
| - score += 1; | |
| - conn.send("WINNER" + player) | |
| - } | |
| -</code></pre><br /> | |
| -The player’s score is increased if the computation result is 20, in which case the string (“WINNER” + player) goes to the server and is broadcast. Browsers intercept the message with:<br /> | |
| -<pre><code class="javascript"> if (data.substring(0,6) == "WINNER") { | |
| - T = 0; | |
| - T2 = (-1) | |
| - T4 = (-1) | |
| - var win = data.substring(6); | |
| - $("#roll").show(); | |
| - $("#submitA").hide(); | |
| - $("#out4").hide(); | |
| - $("#out5").hide(); | |
| - $("#out6").hide(); | |
| - winner(win); | |
| - } | |
| -</code></pre><br /> | |
| -T = 0 resets the display clocks. Any invisible timers which are running get deactivated, the ROLL button is displayed, some display housekeeping is performed, and winner(win) is called. Here is the function “winner”.<br /> | |
| -<pre><code class="javascript"> var winner = function (x) { | |
| - $("#output").html(""); | |
| - $("#output2").html("<h2>One point for " + x + "</h2>"); | |
| - } if (data.substring(0,6) == "WINNER") { | |
| - T = (-1); | |
| - T2 = (-1); | |
| - T3 = (-1); | |
| - T4 = (-1); | |
| - var win = data.substring(6); | |
| - $("#roll").show(); | |
| - $("#submitA").hide(); | |
| - $("#submitB").hide(); | |
| - $("#submitC").hide(); | |
| - $("#submitD").hide(); | |
| - $("#SCORE3").hide(); | |
| - winner(win); | |
| - } | |
| -</code></pre><br /> | |
| -It just announces the result, displays the “ROLL” button, and hides some useless buttons which might otherwise be displayed, and calls the function “winner”. Here is the function “winner”.<br /> | |
| -<pre><code class="javascript"> var winner = function (x) { | |
| - $("#output").html("<h2>One point for " + x + "</h2>"); | |
| - $("#output2").html(""); | |
| - } | |
| -</code></pre><br /> | |
| -It just announces the result and erases whatever useless information remains in the div with id = “output2”.</p> | |
| -<p>Clicking “IMPOSSIBLE” caused<br /> | |
| -<pre><code class="javascript"> conn.send("SIXTY" + player); | |
| -</code></pre><br /> | |
| -to be executed, causing the server to broadcast the string “SIXTY” + player. Each browser uses the string as follows:<br /> | |
| -<pre><code class="javascript"> if (data.substring(0,5) == "SIXTY") { | |
| - T = 61; | |
| - impossiblePlayer = data.substring(5); | |
| - $("#output2").html("The deduction from " + player + "'s score might be temporary."); | |
| - $("#submitB").hide(); | |
| - $("#output2").show(); | |
| - $("#SCORE3").show(); | |
| - $("#SCORE1").hide(); | |
| - $("#output2").html(""); | |
| -</code></pre><br /> | |
| -The mutable global variable “impossiblePlayer” is set to the name of the player who clicked “IMPOSSIBLE”. If someone clickes “SCORE”, impossiblePlayer is used in the following code:<br /> | |
| -<pre><code class="javascript"> if (data.substring(0,6) == "LOSER2") { | |
| - T = -1; | |
| - T4 = -1; | |
| - var lose = e.data.substring(6); | |
| - if (player == impossiblePlayer) { | |
| - score += 2; | |
| - } | |
| - $("#output2").html(""); | |
| - $("#roll").show(); | |
| - $("#submitA").hide(); | |
| - $("#submitB").hide(); | |
| - $("#submitC").hide(); | |
| - $("#submitD").hide(); | |
| - $("#SCORE3").hide(); | |
| - loser2(lose); | |
| - } | |
| -</code></pre><br /> | |
| -This shows some of the things that happen if someone clicks “SCORE” after someone else clicked “IMPOSSIBLE”. The player who clicked “IMPOSSIBLE” gets two points, more than compensating for the initial one point deduction. The function “loser2” is called, causing a message to be displayed as follows:<br /> | |
| -<pre><code class="javascript"> var loser2 = function (x) { | |
| - $("#output").html(""); | |
| - $("#output3").html("<h2>Deduct one point from " + x + "<br>One point for " + impossiblePlayer + "</h2>"); | |
| - } | |
| -</code></pre><br /> | |
| -The variable “impossiblePlayer” that was set in each browser when someone clicked “IMPOSSIBLE” is used to announce the outcome of the completed round.</p></article></body></html> | |
| \ No newline at end of file | |
| diff --git a/yesod-websockets/Game-Example/Websockets_for_Browser_Control.md b/yesod-websockets/Game-Example/Websockets_for_Browser_Control.md | |
| index 5654d9c..86fc432 100644 | |
| --- a/yesod-websockets/Game-Example/Websockets_for_Browser_Control.md | |
| +++ b/yesod-websockets/Game-Example/Websockets_for_Browser_Control.md | |
| @@ -3,56 +3,125 @@ | |
| **INTRODUCTION** | |
| -The Haskell version of the game of *Score* was developed by modifying the chat.hs file at <http://github.com/yesodweb/websockets>. The chat login remains the same, but the chat window is replaced by the real time, multi-player game of score. Websockets are used to provide players with a scoreboard that keeps track of participants and their current scores with: | |
| +The Haskell version of the game of *Score* was developed by modifying | |
| +the chat.hs file at <http://github.com/yesodweb/websockets>. The chat | |
| +login remains the same, but the chat window is replaced by the real | |
| +time, multi-player game of score. Websockets are used to provide | |
| +players with a scoreboard that keeps track of participants and their | |
| +current scores with: | |
| - no backend database or flatfile | |
| - no persistent entities or transactions | |
| - no cookies | |
| -The online browsers add and deduct game points, maintain the list of current players, and keep track of scores by manipulating the values of javascript variables. The Yesod/Warp server does not get involved. It generates random numbers simulating rolls of four dice: two six-sided dice, one twelve-sided die, and one twenty-sided die. Other than that, the server acts mainly as a conduit for messages from individual players to the online group. | |
| +The online browsers add and deduct game points, maintain the list of | |
| +current players, and keep track of scores by manipulating the values | |
| +of javascript variables. The Yesod/Warp server does not get | |
| +involved. It generates random numbers simulating rolls of four dice: | |
| +two six-sided dice, one twelve-sided die, and one twenty-sided | |
| +die. Other than that, the server acts mainly as a conduit for messages | |
| +from individual players to the online group. | |
| -The game of *Score* shows how coders familiar with Javascript but new to Haskell can get fairly complex Haskell web applications up and running using the coding techniques with which they are familiar. It might also remind seasoned Haskell programmers that websockets can sometimes be very useful in creating fast, efficient web applications that delegate much or most of the work to the browsers. | |
| +The game of *Score* shows how coders familiar with Javascript but new | |
| +to Haskell can get fairly complex Haskell web applications up and | |
| +running using the coding techniques with which they are familiar. It | |
| +might also remind seasoned Haskell programmers that websockets can | |
| +sometimes be very useful in creating fast, efficient web applications | |
| +that delegate much or most of the work to the browsers. | |
| **THE ELEGANCE OF JAVASCRIPT** | |
| -Here's how the game works: When a player clicks "ROLL", the server sends a fresh set of four random numbers to all participants. If a player sees a way to make the number 20 by means of two or three operations involving any combination of addition, subtraction, multiplication, division, or concatenation, the player can click the button labeled "SCORE" to start a 30-second countdown and try to win a point. Clicking "SCORE" sends a message to the server which is passed on to all browsers setting T = 30. That's all it takes to start the clocks running. Just set the global variable T to anything above 0 and a countdown back to 0 begins. A "setInterval" function cycles once per second, testing the value of T. If T is greater than 0, it sets | |
| -```javascript | |
| +Here's how the game works: When a player clicks "ROLL", the server | |
| +sends a fresh set of four random numbers to all participants. If a | |
| +player sees a way to make the number 20 by means of two or three | |
| +operations involving any combination of addition, subtraction, | |
| +multiplication, division, or concatenation, the player can click the | |
| +button labeled "SCORE" to start a 30-second countdown and try to win a | |
| +point. Clicking "SCORE" sends a message to the server which is passed | |
| +on to all browsers setting T = 30. That's all it takes to start the | |
| +clocks running. Just set the global variable T to anything above 0 and | |
| +a countdown back to 0 begins. A "setInterval" function cycles once per | |
| +second, testing the value of T. If T is greater than 0, it sets | |
| + | |
| +``` javascript | |
| T = T - 1 | |
| ``` | |
| -and prints the value in the browser. The visible countdown function is not involved in keeping score; that is done by other countdown routings activated by clicking "SCORE" or "IMPOSSIBLE". | |
| -Clicking "IMPOSSIBLE" sends a message to all participants (routed through the server) setting T = 60. After 60 seconds, the player who clicked "IMPOSSIBLE" gets one point; but if during the 60-second countdown another player clicks "SCORE", a message is routed to all players setting T = 30. If the player who clicked "SCORE" makes the number 20 before T = 0, that player gains one point and the player who clicked impossible loses one point. | |
| +and prints the value in the browser. The visible countdown function is | |
| +not involved in keeping score; that is done by other countdown | |
| +routings activated by clicking "SCORE" or "IMPOSSIBLE". | |
| + | |
| +Clicking "IMPOSSIBLE" sends a message to all participants (routed | |
| +through the server) setting T = 60. After 60 seconds, the player who | |
| +clicked "IMPOSSIBLE" gets one point; but if during the 60-second | |
| +countdown another player clicks "SCORE", a message is routed to all | |
| +players setting T = 30. If the player who clicked "SCORE" makes the | |
| +number 20 before T = 0, that player gains one point and the player who | |
| +clicked impossible loses one point. | |
| -As soon as a player scores, or when a player fails to obtain the number 20 after 30 seconds or three computations, the player's score is increased or decreased and a message goes out to all browsers announcing the outcome and setting T = 0 so another round can begin. | |
| +As soon as a player scores, or when a player fails to obtain the | |
| +number 20 after 30 seconds or three computations, the player's score | |
| +is increased or decreased and a message goes out to all browsers | |
| +announcing the outcome and setting T = 0 so another round can begin. | |
| -In other words, a player who clicks "SCORE" loses a point if 30 seconds elapse or if three computations fail to produce 20, and gains a point if 20 is computed within the time limit. A player who clicks "IMPOSSIBLE" gains a point unless another player clickes "SCORE" and computes the number 20 within 30 seconds. Individual scores are maintained in each player's browser in the variable "score"; but almost immediately, all of the scoreboards on all participating browsers see the update. Thanks to Javascript's mutable variables, updates are accomplished simply and elegantly as follows: | |
| +In other words, a player who clicks "SCORE" loses a point if 30 | |
| +seconds elapse or if three computations fail to produce 20, and gains | |
| +a point if 20 is computed within the time limit. A player who clicks | |
| +"IMPOSSIBLE" gains a point unless another player clickes "SCORE" and | |
| +computes the number 20 within 30 seconds. Individual scores are | |
| +maintained in each player's browser in the variable "score"; but | |
| +almost immediately, all of the scoreboards on all participating | |
| +browsers see the update. Thanks to Javascript's mutable variables, | |
| +updates are accomplished simply and elegantly as follows: | |
| -Every three seconds, each player sends his or her name and score to the server which immediately broadcases the information to all participating browsers. The name and score are placed in a javascript object in the following format: | |
| +Every three seconds, each player sends his or her name and score to | |
| +the server which immediately broadcases the information to all | |
| +participating browsers. The name and score are placed in a javascript | |
| +object in the following format: | |
| ``` javascript | |
| {"player" : {"player",score}} | |
| ``` | |
| + | |
| Each browser has an object called "game". When a player/score object arrives, say | |
| -```javascript | |
| + | |
| +```javascript | |
| {"Fred" : {"player":"Fred, "score":42}} | |
| ``` | |
| + | |
| the code | |
| + | |
| ```javascript | |
| game["Fred"] = {"Fred" : {"player":"Fred, "score":42}} | |
| ``` | |
| -is executed. As with "T", the mutable global variable "game" provides an efficient way to maintain identical, updated scoreboards on all browsers. Javascript objects cannot have duplicate keys, so it doesn't matter if Fred was already in game, perhaps with a different score. The new Fred object bumps the older one out of the way and the next scoreboard update shows the result. | |
| + | |
| +is executed. As with "T", the mutable global variable "game" provides | |
| +an efficient way to maintain identical, updated scoreboards on all | |
| +browsers. Javascript objects cannot have duplicate keys, so it doesn't | |
| +matter if Fred was already in game, perhaps with a different | |
| +score. The new Fred object bumps the older one out of the way and the | |
| +next scoreboard update shows the result. | |
| **Browser disconnects** | |
| -Disconnects are noted without parsing Internet protocol packets or interacting with session cookies. There are no session cookies, and the server does not participate in maintaining up-to-date scoreboards. The browsers take care of this with the following code: | |
| +Disconnects are noted without parsing Internet protocol packets or | |
| +interacting with session cookies. There are no session cookies, and | |
| +the server does not participate in maintaining up-to-date | |
| +scoreboards. The browsers take care of this with the following code: | |
| + | |
| ```javascript | |
| setInterval (function () { | |
| game = {}; | |
| }, 10000); | |
| ``` | |
| -Every 10 seconds, on each browser, all players are deleted from game. The game object is soon replenished with the names and scores of all participants because each broser refreshes game every 3 seconds using the code | |
| + | |
| +Every 10 seconds, on each browser, all players are deleted from | |
| +game. The game object is soon replenished with the names and scores of | |
| +all participants because each broser refreshes game every 3 seconds | |
| +using the code | |
| + | |
| ```javascript | |
| setInterval (function () { | |
| conn.send("COWS," + player + "," + score); | |
| @@ -68,10 +137,29 @@ When browsers receive messages beginning with "COWS", they react as follows: | |
| game[pl] = {"player" : pl, "score" : sc}; | |
| players[pl] = pl | |
| } | |
| + | |
| ``` | |
| -Notice that the object "players" gets only the player's name, but not the score. The "players" object is used to screen attempts to log in with names that are already taken. The first four lines inside the if clause split the incoming string into a three-member list and attach the player and the score to the object "game". Mutable global variable allow much to be accomplished with few lines of code. The server could participate in time keeping and scoreboard updating but MVars, the state monad, stm, or some such way of avoiding side effects seems like a lot of work compared with the simple elegance of using the mutable global variables "T" and "game". For production code, names such as "SCH_T" and "SCH_game" might be used to avoid inadvertant clashes with someone else's code using the global variables "T" and "game". the prefix "SCH" could be used to create a namespace for code written by Schalk. | |
| -The code for the game of **Score** is pretty straghtforward. One part that might need an explanation is the code involving a click of the "IMPOSSIBLE" button. When that happens, clickers send their names to all the other browsers (through the server) as follows: | |
| +Notice that the object "players" gets only the player's name, but not | |
| +the score. The "players" object is used to screen attempts to log in | |
| +with names that are already taken. The first four lines inside the if | |
| +clause split the incoming string into a three-member list and attach | |
| +the player and the score to the object "game". Mutable global variable | |
| +allow much to be accomplished with few lines of code. The server could | |
| +participate in time keeping and scoreboard updating but MVars, the | |
| +state monad, stm, or some such way of avoiding side effects seems like | |
| +a lot of work compared with the simple elegance of using the mutable | |
| +global variables "T" and "game". For production code, names such as | |
| +"SCH_T" and "SCH_game" might be used to avoid inadvertant clashes with | |
| +someone else's code using the global variables "T" and "game". the | |
| +prefix "SCH" could be used to create a namespace for code written by | |
| +Schalk. | |
| + | |
| +The code for the game of **Score** is pretty straghtforward. One part | |
| +that might need an explanation is the code involving a click of the | |
| +"IMPOSSIBLE" button. When that happens, clickers send their names to | |
| +all the other browsers (through the server) as follows: | |
| + | |
| ```javascript | |
| $("#IMPOSSIBLE").click( function () { | |
| score = score - 1; | |
| @@ -81,7 +169,14 @@ The code for the game of **Score** is pretty straghtforward. One part that might | |
| }); | |
| ``` | |
| -One point is immediately deducted from the clicker's score, but two points will be added if the timer reaches T3 = 0, or if someone clicks "SCORE" and either can't show a solution within 30 seconds or performs 3 computations which don't result in the number 20. T3 is set for only the clicker's browser. The local function localCalc2 is calledas follows: | |
| + | |
| +One point is immediately deducted from the clicker's score, but two | |
| +points will be added if the timer reaches T3 = 0, or if someone clicks | |
| +"SCORE" and either can't show a solution within 30 seconds or performs | |
| +3 computations which don't result in the number 20. T3 is set for only | |
| +the clicker's browser. The local function localCalc2 is calledas | |
| +follows: | |
| + | |
| ```javascript | |
| var localCalc2 = function() { | |
| setTimeout (function () { | |
| @@ -97,7 +192,11 @@ One point is immediately deducted from the clicker's score, but two points will | |
| }, 1000) | |
| } | |
| ``` | |
| -Clicking "IMPOSSIBLE" caused the string ("SIXTY" + player) to be sent to the server and broadcast to all participants. Each browser intercepts the string as follows: | |
| + | |
| +Clicking "IMPOSSIBLE" caused the string ("SIXTY" + player) to be sent | |
| +to the server and broadcast to all participants. Each browser | |
| +intercepts the string as follows: | |
| + | |
| ```javascript | |
| if (data.substring(0,5) == "SIXTY") { | |
| T = 61; | |
| @@ -107,17 +206,24 @@ Clicking "IMPOSSIBLE" caused the string ("SIXTY" + player) to be sent to the ser | |
| $("#submitB").hide(); | |
| $("#SCORE1").hide(); | |
| $("#IMPOSSIBLE").hide(); | |
| - $("#output2").show(); | |
| + $("#output2").show(); | |
| $("#output2").html("The deduction from " + name + "'s score might be temporary.") | |
| - impossiblePlayer = e.data.substring(5); | |
| - $("#output4").html("impossiblePlayer is " + impossiblePlayer); | |
| + impossiblePlayer = e.data.substring(5); | |
| + $("#output4").html("impossiblePlayer is " + impossiblePlayer); | |
| } | |
| ``` | |
| -T = 61 sets the countdown in all of the browsers. The rest of the code is just display housekeeping. Clicking "SCORE" will reset the countdown to 30 with the simple instruction | |
| + | |
| +T = 61 sets the countdown in all of the browsers. The rest of the code | |
| +is just display housekeeping. Clicking "SCORE" will reset the | |
| +countdown to 30 with the simple instruction | |
| + | |
| ```javascript | |
| T = 31 | |
| ``` | |
| -The reason the countdown timer can be set and re-set by changing the value of T is this perpetually (up to the timeout limit) cycling code: | |
| + | |
| +The reason the countdown timer can be set and re-set by changing the | |
| +value of T is this perpetually (up to the timeout limit) cycling code: | |
| + | |
| ```javascript | |
| SCH_t = 3600 | |
| @@ -134,9 +240,17 @@ The reason the countdown timer can be set and re-set by changing the value of T | |
| timer(); | |
| }, 1000); | |
| ``` | |
| -Once every second, setInterval checks to see if T is greater than 0. If it is, it deminishes T by 1 and displays its value in the browser. This is only for display. Scorekeeping depends on T2, T3, and T4, which are not shown in the browsers. | |
| -If someone clicks "SCORE" during the 60 countdown, T3 = (-1) is set, stopping the local, invisible *Impossible* countdown and starting localCalc3 as follows: | |
| +Once every second, setInterval checks to see if T is greater | |
| +than 0. If it is, it deminishes T by 1 and displays its value in the | |
| +browser. This is only for display. Scorekeeping depends on T2, T3, and | |
| +T4, which are not shown in the browsers. | |
| + | |
| + | |
| +If someone clicks "SCORE" during the 60 countdown, T3 = (-1) is set, | |
| +stopping the local, invisible *Impossible* countdown and starting | |
| +localCalc3 as follows: | |
| + | |
| ```javascript | |
| $("#SCORE3").click( function () { | |
| $("#submitA").show(); | |
| @@ -145,7 +259,9 @@ If someone clicks "SCORE" during the 60 countdown, T3 = (-1) is set, stopping th | |
| localCalc3(); | |
| }); | |
| ``` | |
| -Hhere is localCalc3: | |
| + | |
| +Here is localCalc3: | |
| + | |
| ```javascript | |
| var localCalc3 = function() { | |
| setTimeout (function () { | |
| @@ -156,14 +272,17 @@ Hhere is localCalc3: | |
| else if (T4 == 0) { | |
| score -= 1; | |
| return; | |
| - } | |
| + } | |
| else { | |
| return; | |
| } | |
| }, 1000) | |
| } | |
| ``` | |
| -The clicker will lose a point if the countdown is not interrupted by computing the number 20. Here is how the interruption occurs: | |
| + | |
| +The clicker will lose a point if the countdown is not interrupted by | |
| +computing the number 20. Here is how the interruption occurs: | |
| + | |
| ```javascript | |
| var firstCalc = function (a,b,c) { | |
| var res; | |
| @@ -201,14 +320,21 @@ The clicker will lose a point if the countdown is not interrupted by computing t | |
| return res; | |
| }; | |
| ``` | |
| -Players don't get credit for computing 20 in the first round, so firstCalc does not affect the score. But calculate has the block: | |
| + | |
| +Players don't get credit for computing 20 in the first round, so | |
| +firstCalc does not affect the score. But calculate has the block: | |
| + | |
| ```javascript | |
| if (res == 20) { | |
| score += 1; | |
| conn.send("WINNER" + player) | |
| } | |
| ``` | |
| -The player's score is increased if the computation result is 20, in which case the string ("WINNER" + player) goes to the server and is broadcast. Browsers intercept the message with: | |
| + | |
| +The player's score is increased if the computation result is 20, in | |
| +which case the string ("WINNER" + player) goes to the server and is | |
| +broadcast. Browsers intercept the message with: | |
| + | |
| ```javascript | |
| if (data.substring(0,6) == "WINNER") { | |
| T = 0; | |
| @@ -223,7 +349,12 @@ The player's score is increased if the computation result is 20, in which case t | |
| winner(win); | |
| } | |
| ``` | |
| -T = 0 resets the display clocks. Any invisible timers which are running get deactivated, the ROLL button is displayed, some display housekeeping is performed, and winner(win) is called. Here is the function "winner". | |
| + | |
| +T = 0 resets the display clocks. Any invisible timers which are | |
| +running get deactivated, the ROLL button is displayed, some display | |
| +housekeeping is performed, and winner(win) is called. Here is the | |
| +function "winner". | |
| + | |
| ```javascript | |
| var winner = function (x) { | |
| $("#output").html(""); | |
| @@ -240,23 +371,33 @@ T = 0 resets the display clocks. Any invisible timers which are running get deac | |
| $("#submitC").hide(); | |
| $("#submitD").hide(); | |
| $("#SCORE3").hide(); | |
| - winner(win); | |
| - } | |
| + winner(win); | |
| + } | |
| ``` | |
| -It just announces the result, displays the "ROLL" button, and hides some useless buttons which might otherwise be displayed, and calls the function "winner". Here is the function "winner". | |
| + | |
| +It just announces the result, displays the "ROLL" button, and hides | |
| +some useless buttons which might otherwise be displayed, and calls the | |
| +function "winner". Here is the function "winner". | |
| + | |
| ```javascript | |
| var winner = function (x) { | |
| $("#output").html("<h2>One point for " + x + "</h2>"); | |
| $("#output2").html(""); | |
| } | |
| ``` | |
| -It just announces the result and erases whatever useless information remains in the div with id = "output2". | |
| + | |
| +It just announces the result and erases whatever useless information | |
| +remains in the div with id = "output2". | |
| Clicking "IMPOSSIBLE" caused | |
| + | |
| ```javascript | |
| conn.send("SIXTY" + player); | |
| ``` | |
| -to be executed, causing the server to broadcast the string "SIXTY" + player. Each browser uses the string as follows: | |
| + | |
| +to be executed, causing the server to broadcast the string "SIXTY" + | |
| +player. Each browser uses the string as follows: | |
| + | |
| ```javascript | |
| if (data.substring(0,5) == "SIXTY") { | |
| T = 61; | |
| @@ -268,9 +409,13 @@ to be executed, causing the server to broadcast the string "SIXTY" + player. Eac | |
| $("#SCORE1").hide(); | |
| $("#output2").html(""); | |
| ``` | |
| -The mutable global variable "impossiblePlayer" is set to the name of the player who clicked "IMPOSSIBLE". If someone clickes "SCORE", impossiblePlayer is used in the following code: | |
| + | |
| +The mutable global variable "impossiblePlayer" is set to the name of | |
| +the player who clicked "IMPOSSIBLE". If someone clickes "SCORE", | |
| +impossiblePlayer is used in the following code: | |
| + | |
| ```javascript | |
| - if (data.substring(0,6) == "LOSER2") { | |
| + if (data.substring(0,6) == "LOSER2") { | |
| T = -1; | |
| T4 = -1; | |
| var lose = e.data.substring(6); | |
| @@ -287,19 +432,20 @@ The mutable global variable "impossiblePlayer" is set to the name of the player | |
| loser2(lose); | |
| } | |
| ``` | |
| -This shows some of the things that happen if someone clicks "SCORE" after someone else clicked "IMPOSSIBLE". The player who clicked "IMPOSSIBLE" gets two points, more than compensating for the initial one point deduction. The function "loser2" is called, causing a message to be displayed as follows: | |
| + | |
| +This shows some of the things that happen if someone clicks "SCORE" | |
| +after someone else clicked "IMPOSSIBLE". The player who clicked | |
| +"IMPOSSIBLE" gets two points, more than compensating for the initial | |
| +one point deduction. The function "loser2" is called, causing a | |
| +message to be displayed as follows: | |
| + | |
| ```javascript | |
| var loser2 = function (x) { | |
| $("#output").html(""); | |
| - $("#output3").html("<h2>Deduct one point from " + x + "<br>One point for " + impossiblePlayer + "</h2>"); | |
| + $("#output3").html("<h2>Deduct one point from " + x + "<br>One point for " + impossiblePlayer + "</h2>"); | |
| } | |
| ``` | |
| -The variable "impossiblePlayer" that was set in each browser when someone clicked "IMPOSSIBLE" is used to announce the outcome of the completed round. | |
| - | |
| - | |
| - | |
| - | |
| - | |
| - | |
| - | |
| +The variable "impossiblePlayer" that was set in each browser when | |
| +someone clicked "IMPOSSIBLE" is used to announce the outcome of the | |
| +completed round. | |
| diff --git a/yesod-websockets/Game-Example/report.html b/yesod-websockets/Game-Example/report.html | |
| deleted file mode 100644 | |
| index 768ec1b..0000000 | |
| --- a/yesod-websockets/Game-Example/report.html | |
| +++ /dev/null | |
| @@ -1,178 +0,0 @@ | |
| -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> | |
| -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> | |
| -<head> | |
| -<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" /> | |
| -<title>HLint Report</title> | |
| -<script type='text/javascript'> | |
| - | |
| -/* == Algorithm for show/unshow == | |
| - Each hint/file is given a number, hint# or file# | |
| - When we say showOnly with a class name we add the rules to | |
| - the css #content div {display:none}, #content div.className {display:block} | |
| - When going back to showAll we remove these results | |
| -*/ | |
| - | |
| -// CSS MANIPULATION // | |
| - | |
| -function deleteRules(n) | |
| -{ | |
| - var css = document.styleSheets[0]; | |
| - for (var i = 0; i < n; i++) | |
| - css.deleteRule(css.cssRules.length-1); | |
| -} | |
| - | |
| -function insertRule(s) | |
| -{ | |
| - var css = document.styleSheets[0]; | |
| - css.insertRule(s, css.cssRules.length); | |
| -} | |
| - | |
| -// SHOW/HIDE LOGIC // | |
| - | |
| -var last = ""; | |
| - | |
| -function show(id) | |
| -{ | |
| - if (id == last) return; | |
| - if (id == "") | |
| - { | |
| - deleteRules(3); | |
| - insertRule(".all {font-weight: bold;}"); | |
| - } | |
| - else | |
| - { | |
| - if (last == "") | |
| - { | |
| - deleteRules(1); | |
| - insertRule("#content div {display:none;}"); | |
| - } | |
| - else | |
| - { | |
| - deleteRules(2); | |
| - } | |
| - insertRule("#content div." + id + " {display:block;}"); | |
| - insertRule("#" + id + "{font-weight:bold;}"); | |
| - } | |
| - | |
| - last = id; | |
| -} | |
| - | |
| -</script> | |
| -<style type="text/css"> | |
| -/* These rules are manipulated by the script. | |
| - The commented form is how it looks with an id selected */ | |
| - | |
| -.all {font-weight: bold;} /* #content div {display:none;} */ | |
| - /* #content div.id {display:block;} */ | |
| - /* #id {font-weight: bold;} */ | |
| - | |
| -</style> | |
| -<style type="text/css"> | |
| -/* See http://www.webreference.com/programming/css_frames/ */ | |
| -body { | |
| - margin:0; | |
| - border:0; | |
| - padding:0; | |
| - height:100%; | |
| - max-height:100%; | |
| - font-family: sans-serif; | |
| - font-size:76%; | |
| - overflow: hidden; | |
| -} | |
| - | |
| -#leftbar { | |
| - position:absolute; | |
| - top:0px; | |
| - left:0px; | |
| - width: 215px; | |
| - bottom: 0px; | |
| - overflow:auto; | |
| - background:rgb(202,223,255); | |
| - margin: 10px; | |
| - padding-top: 0; | |
| - padding-left: 7px; | |
| - padding-right: 7px; | |
| - -moz-border-radius: 5px; | |
| - -webkit-border-radius: 5px; | |
| - | |
| - display:none; /* Override if script present */ | |
| -} | |
| - | |
| -#content { | |
| - position:absolute; | |
| - top:0; | |
| - bottom:0; | |
| - right:0; | |
| - overflow:auto; | |
| - padding-bottom: 15px; | |
| - padding-right: 7px; | |
| - | |
| - left:10px; /* Override if script present */ | |
| -} | |
| - | |
| -#leftbar ul {margin-top: 0px; padding-left: 15px;} | |
| -#leftbar p {margin-bottom: 0px;} | |
| -.note {color: gray; font-size: smaller;} | |
| - | |
| -pre { | |
| - font-family: "lucida console", monospace; | |
| - padding-left: 15px; | |
| - margin: 2px; | |
| -} | |
| - | |
| -#content div { | |
| - margin-bottom: 10px; | |
| - margin-right: 10px; | |
| - padding-top: 4px; | |
| - border-top: 1px solid #ccc; | |
| -} | |
| - | |
| -.script #content {left:250px;} | |
| -.script #leftbar {display: block;} | |
| - | |
| -/* From HsColour */ | |
| -.hs-keyglyph, .hs-layout {color: red;} | |
| -.hs-keyword {color: blue;} | |
| -.hs-comment, .hs-comment a {color: green;} | |
| -.hs-str, .hs-chr {color: teal;} | |
| -</style> | |
| -</head> | |
| -<body> | |
| - | |
| -<script type='text/javascript'> | |
| -document.body.className = "script"; | |
| -</script> | |
| - | |
| -<div id="leftbar" valign="top" style="min-width:200px"> | |
| - | |
| -<p><a class="all" href="javascript:show('')">All hints</a></p> | |
| -<ul> | |
| -<li><a id="hint0" href="javascript:show('hint0')">Warning: Parse error: ; (1)</a></li> | |
| -</ul> | |
| - | |
| -<p><a class="all" href="javascript:show('')">All files</a></p> | |
| -<ul> | |
| -<li><a id="file0" href="javascript:show('file0')">Fm.hs (1)</a></li> | |
| -</ul> | |
| - | |
| -</div> | |
| -<div id="content" valign="top" width="100%"> | |
| -<p> | |
| - Report generated by <a href="http://community.haskell.org/~ndm/hlint/">HLint</a> | |
| -v1.9.13 | |
| - - a tool to suggest improvements to your Haskell code. | |
| -</p> | |
| - | |
| -<div class="hint0 file0"> | |
| -Fm.hs:52:1: Warning: Parse error: ;<br/> | |
| -Found<br/> | |
| -<pre><span class='hs-varop'>></span> <span class='hs-definition'>g</span> <span class='hs-varid'>x</span> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>x</span> <span class='hs-num'>3</span> <span class='hs-num'>2</span> <span class='hs-varop'>==</span> <span class='hs-num'>5</span> <span class='hs-keyglyph'>=</span> <span class='hs-str'>" + "</span> | |
| - <span class='hs-keyglyph'>|</span> <span class='hs-varid'>x</span> <span class='hs-num'>3</span> <span class='hs-num'>2</span> <span class='hs-varop'>==</span> <span class='hs-num'>1</span> <span class='hs-keyglyph'>=</span> <span class='hs-str'>" - "</span> | |
| - <span class='hs-keyglyph'>|</span> <span class='hs-varid'>x</span> <span class='hs-num'>3</span> <span class='hs-num'>2</span> <span class='hs-varop'>==</span> <span class='hs-num'>6</span> <span class='hs-keyglyph'>=</span> <span class='hs-str'>" * "</span> | |
| -</pre> | |
| - | |
| -</div> | |
| - | |
| -</div> | |
| -</body> | |
| -</html> | |
| diff --git a/yesod-websockets/Game-Example/score.hs b/yesod-websockets/Game-Example/score.hs | |
| index c410bd8..8abf55b 100755 | |
| --- a/yesod-websockets/Game-Example/score.hs | |
| +++ b/yesod-websockets/Game-Example/score.hs | |
| @@ -1,16 +1,27 @@ | |
| -{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings #-} | |
| -import Yesod.Core | |
| -import Yesod.WebSockets | |
| -import Control.Monad (forever) | |
| -import Control.Monad.Trans.Reader | |
| -import Control.Concurrent (threadDelay) | |
| -import Conduit | |
| -import Data.Monoid ((<>)) | |
| -import Control.Concurrent.STM.Lifted | |
| -import Data.Text (Text, pack, isPrefixOf) | |
| -import Fm hiding (main) | |
| -import Control.Exception.Base-- import Network.Wai.Handler.Warp hiding (defaultShouldDisplayException) | |
| -import Text.Julius | |
| +{-# LANGUAGE OverloadedStrings #-} | |
| +{-# LANGUAGE QuasiQuotes #-} | |
| +{-# LANGUAGE TemplateHaskell #-} | |
| +{-# LANGUAGE TypeFamilies #-} | |
| + | |
| +import Conduit | |
| +import Control.Concurrent (threadDelay) | |
| +import Control.Concurrent.STM.Lifted | |
| +import Control.Exception.Base | |
| +import Control.Monad (forever) | |
| +import Control.Monad.Trans.Reader | |
| +import Data.Monoid ((<>)) | |
| +import Data.Text (Text, isPrefixOf, pack) | |
| +import Fm hiding (main) | |
| +import Text.Julius | |
| +import Yesod.Core | |
| +import Yesod.WebSockets | |
| + | |
| + | |
| +main :: IO () | |
| +main = do | |
| + chan <- atomically newBroadcastTChan | |
| + warp 3000 $ App chan | |
| + | |
| han :: String -> IO () -> IO () | |
| han s = handle (\(SomeException _) -> print s) | |
| @@ -28,27 +39,31 @@ mkYesod "App" [parseRoutes| | |
| |] | |
| scoreApp :: WebSocketsT Handler () | |
| -scoreApp = do | |
| +scoreApp = do | |
| App writeChan <- getYesod | |
| - readChan <- atomically $ do | |
| + readChan <- atomically $ do | |
| writeTChan writeChan greeting | |
| dupTChan writeChan | |
| -- ps <- liftIO new | |
| - race_ | |
| - (forever $ atomically (readTChan readChan) >>= sendTextData) | |
| - (sourceWS $$ mapM_C (\msg -> | |
| - if msg == go | |
| - then do | |
| + race_ | |
| + (forever $ atomically (readTChan readChan) >>= sendTextData) | |
| + (sourceWS $$ mapM_C (\msg -> | |
| + if msg == go | |
| + then do | |
| let x = roll 6 6 12 20 | |
| y <- liftIO $ truck x | |
| let z = map round x | |
| - liftIO $ han "Problem forwarding a roll" $ atomically $ writeTChan writeChan $ go <> pack (show z) | |
| - liftIO $ han "Problem forwarding solutions" $ atomically $ writeTChan writeChan $ solutions <> pack y | |
| - else | |
| - liftIO $ han "Problem forwarding a message" $ atomically $ writeTChan writeChan msg )) | |
| + liftIO $ han "Problem forwarding a roll" | |
| + $ atomically $ writeTChan writeChan | |
| + $ go <> pack (show z) | |
| + liftIO $ han "Problem forwarding solutions" | |
| + $ atomically $ writeTChan writeChan | |
| + $ solutions <> pack y | |
| + else | |
| + liftIO $ han "Problem forwarding a message" $ atomically $ writeTChan writeChan msg )) | |
| getHomeR :: Handler Html | |
| -getHomeR = do | |
| +getHomeR = do | |
| webSockets scoreApp | |
| defaultLayout $ do | |
| [whamlet| | |
| @@ -61,7 +76,7 @@ getHomeR = do | |
| <div #output3> | |
| <button type="submit" class="score1" id="SCORE1">SCORE</button> | |
| - <button type="submit" class="score1" id="SCORE3">SCORE</button> | |
| + <button type="submit" class="score1" id="SCORE3">SCORE</button> | |
| <button type="submit" class="score1" id="IMPOSSIBLE">IMPOSSIBLE</button> | |
| <button type="submit" class="score1" id="roll">ROLL</button> | |
| @@ -69,62 +84,62 @@ getHomeR = do | |
| <input #input> | |
| <div #out2> | |
| - <div #out3> | |
| - | |
| - <input type="radio" name="day" id="x0" checked> | |
| + <div #out3> | |
| + | |
| + <input type="radio" name="day" id="x0" checked> | |
| <label for="x0" class="radio"><span id="0">blank</span></label> | |
| - | |
| - <input type="radio" name="day" id="x1" > | |
| + | |
| + <input type="radio" name="day" id="x1" > | |
| <label for="x1" class="radio"><span id="1">blank</span></label> | |
| - | |
| - <input type="radio" name="day" id="x2" > | |
| + | |
| + <input type="radio" name="day" id="x2" > | |
| <label for="x2" class="radio"><span id="2">blank</span></label> | |
| - | |
| - <input type="radio" name="day" id="x3" > | |
| + | |
| + <input type="radio" name="day" id="x3" > | |
| <label for="x3" class="radio"><span id="3">blank</span></label> | |
| - | |
| + | |
| <br> | |
| <input type="radio" name="ops" value="0" id="x4" checked> | |
| <label for="x4" class="radio"><span id="4">blank</span></label> | |
| - | |
| + | |
| <input type="radio" name="ops" value="1" id="x5"> | |
| <label for="x5" class="radio"><span id="5">blank</span></label> | |
| - | |
| + | |
| <input type="radio" name="ops" value="2" id="x6"> | |
| <label for="x6" class="radio"><span id="6">blank</span></label> | |
| - | |
| - <input type="radio" name="ops" value="3" id="x7"> | |
| + | |
| + <input type="radio" name="ops" value="3" id="x7"> | |
| <label for="x7" class="radio"><span id="7">blank</span></label> | |
| - | |
| - <input type="radio" name="ops" value="4" id="x8"> | |
| + | |
| + <input type="radio" name="ops" value="4" id="x8"> | |
| <label for="x8" class="radio"><span id="8">blank</span></label> | |
| <br> | |
| - | |
| - <input type="radio" name="night" id="x9" checked> | |
| + | |
| + <input type="radio" name="night" id="x9" checked> | |
| <label for="x9" class="radio"><span id="9">blank</span></label> | |
| - | |
| - <input type="radio" name="night" id="x10" > | |
| + | |
| + <input type="radio" name="night" id="x10" > | |
| <label for="x10" class="radio"><span id="10">blank</span></label> | |
| - | |
| - <input type="radio" name="night" id="x11" > | |
| + | |
| + <input type="radio" name="night" id="x11" > | |
| <label for="x11" class="radio"><span id="11">blank</span></label> | |
| - | |
| - <input type="radio" name="night" id="x12" > | |
| + | |
| + <input type="radio" name="night" id="x12" > | |
| <label for="x12" class="radio"><span id="12">blank</span></label> | |
| - | |
| + | |
| <br> | |
| <button type="submit" class="score1" id="submitA">EVALUATE</button> | |
| <button type="submit" class="score1" id="submitB">EVALUATE</button> | |
| <button type="submit" class="score1" id="submitC">EVALUATE</button> | |
| - <div #out7> | |
| + <div #out7> | |
| <br><br> | |
| - <button type="submit" class="score1" id="sol">SOLUTIONS</button> | |
| - <button type="submit" class="score1" id="erase">ERASE</button> | |
| - <div #out8> | |
| - <h3>All Solutions</h3> | |
| + <button type="submit" class="score1" id="sol">SOLUTIONS</button> | |
| + <button type="submit" class="score1" id="erase">ERASE</button> | |
| + <div #out8> | |
| + <h3>All Solutions</h3> | |
| <div id="out9"><button type="submit" class="score1" id="erase2">ERASE</button></div> | |
| - | |
| + | |
| <div id="right"> | |
| <h2>Score Board | |
| <div id="rightOne"> | |
| @@ -148,7 +163,7 @@ getHomeR = do | |
| float: left; | |
| width: 60%; | |
| } | |
| - | |
| + | |
| #right { | |
| float: right; | |
| width:30%; | |
| @@ -220,23 +235,29 @@ getHomeR = do | |
| position:relative; | |
| // top:1px; | |
| } | |
| - | |
| + | |
| |] | |
| toWidget [julius| | |
| -// *************************************** timer control variables *** | |
| + // *************************************** timer control variables *** | |
| var T; // Used for countdown in SCORE and IMPOSSIBLE. | |
| - var T2; // Used for private countdowns in the individual browser. The file is countDown | |
| - var T3; // Used for private countdowns. The file is countDown2. This is for SCORE after IMPOSSIBLE. | |
| - var T4; // Used for countdown in SCORE after IMPOSSIBLE has been clicked. | |
| -// ************************************* end timer control variables *** | |
| + var T2; // Used for private countdowns in the individual browser. | |
| + //The file is countDown | |
| + | |
| + var T3; // Used for private countdowns. The file is countDown2. | |
| + // This is for SCORE after IMPOSSIBLE. | |
| + | |
| + var T4; // Used for countdown in SCORE after IMPOSSIBLE has | |
| + // been clicked. | |
| + | |
| + // ************************************* end timer control variables *** | |
| var player = "Default Player"; | |
| var impossiblePlayer = "Bozo the Clown"; | |
| - var score = 0; | |
| + var score = 0; | |
| var solutions = ""; | |
| playerList = []; | |
| players = {}; | |
| @@ -251,10 +272,10 @@ getHomeR = do | |
| var TOG = "off"; | |
| -// ********************************************************** Page setup **************** | |
| + // ********************************************************** Page setup **************** | |
| $(document).ready( function () { | |
| - $("#output2").html("To get started, please enter a nickname."); | |
| + $("#output2").html("To get started, please enter a nickname."); | |
| $("#roll").hide(); | |
| $("#SCORE3").hide(); | |
| $("#SCORE1").hide(); | |
| @@ -278,28 +299,28 @@ getHomeR = do | |
| $("#8").val("concat"); | |
| }); | |
| -// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ FUNCTIONS | |
| +// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ FUNCTIONS | |
| // ***************************************************** Repeating functions *** | |
| setInterval (function () { | |
| - conn.send("COWS," + player + "," + score); | |
| + conn.send("COWS," + player + "," + score); | |
| }, 1000); | |
| setInterval (function () { | |
| - game = {}; | |
| + game = {}; | |
| }, 10000); | |
| setInterval (function () { | |
| $("#rightOne").html(""); | |
| for (players in game) { | |
| $("#rightOne").append(game[players].player + " " + game[players].score + "<br>"); | |
| - } | |
| + } | |
| }, 500); | |
| SCH_t = 3600 | |
| setInterval (function () { | |
| - SCH_t = SCH_t - 1; | |
| + SCH_t = SCH_t - 1; | |
| var timer = function () { | |
| if (T < 1) { | |
| return; | |
| @@ -309,7 +330,7 @@ getHomeR = do | |
| $("#output").html(T); | |
| } | |
| } | |
| - timer(); | |
| + timer(); | |
| }, 1000); | |
| // ********************************************************* Sign-in screener *** | |
| @@ -325,7 +346,7 @@ getHomeR = do | |
| $("#form").hide(); | |
| $("#roll").show(); | |
| } | |
| - } | |
| + } | |
| // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Player clicked: SCORE, IMPOSSIBLE, or SCORE2 ^^^ | |
| @@ -339,8 +360,8 @@ getHomeR = do | |
| score -= 1; | |
| conn.send("LOSER" + player) | |
| return; | |
| - } | |
| - else return; | |
| + } | |
| + else return; | |
| }, 1000) | |
| } | |
| @@ -354,8 +375,8 @@ getHomeR = do | |
| score += 2; | |
| conn.send("WINNER" + player); | |
| return; | |
| - } | |
| - else return; | |
| + } | |
| + else return; | |
| }, 1000) | |
| } | |
| @@ -371,7 +392,7 @@ getHomeR = do | |
| score -= 1; | |
| conn.send("LOSER2" + player); | |
| return; | |
| - } | |
| + } | |
| else { | |
| return; | |
| } | |
| @@ -387,13 +408,13 @@ getHomeR = do | |
| var loser = function (x) { | |
| $("#output").html(""); | |
| - $("#output3").html("<h2>Deduct one point from " + x + "</h2>"); | |
| + $("#output3").html("<h2>Deduct one point from " + x + "</h2>"); | |
| } | |
| var loser2 = function (x) { | |
| $("#output").html(""); | |
| - $("#output3").html("<h2>Deduct one point from " + x + "<br>One point for " + impossiblePlayer + "</h2>"); | |
| - } | |
| + $("#output3").html("<h2>Deduct one point from " + x + "<br>One point for " + impossiblePlayer + "</h2>"); | |
| + } | |
| // ********************************************** Click callback functions *** | |
| @@ -401,7 +422,7 @@ getHomeR = do | |
| conn.send("GO"); | |
| }); | |
| - $("#SCORE1").click( function () { | |
| + $("#SCORE1").click( function () { | |
| $("#submitA").show(); | |
| conn.send("THIRTY"); | |
| T2 = 31; | |
| @@ -446,7 +467,7 @@ getHomeR = do | |
| conn.send("SIXTY" + player); | |
| T3 = 61; | |
| localCalc2(); | |
| - }); | |
| + }); | |
| $("#SCORE3").click( function () { // After "Impossible" | |
| $("#submitA").show(); | |
| @@ -455,21 +476,21 @@ getHomeR = do | |
| localCalc3(); | |
| }); | |
| -// *************************************************************** Solutions ********** | |
| - $("#sol").click( function () { | |
| - $("#out8").append(solutions); | |
| - conn.send("LOOKED" + player); | |
| +// *************************************************************** Solutions ********** | |
| + $("#sol").click( function () { | |
| + $("#out8").append(solutions); | |
| + conn.send("LOOKED" + player); | |
| }); | |
| - $("#erase").click( function () { | |
| + $("#erase").click( function () { | |
| $("#out8").html(""); | |
| }); | |
| - $("#erase2").click( function () { | |
| + $("#erase2").click( function () { | |
| $("#out8").html(""); | |
| }); | |
| -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Computation preparation ^^^ | |
| +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Computation preparation ^^^ | |
| var firstCalc = function (a,b,c) { | |
| var res; | |
| @@ -486,7 +507,7 @@ getHomeR = do | |
| } | |
| return res; | |
| }; | |
| - | |
| + | |
| var calculate = function (a,b,c) { | |
| var res; | |
| switch (b) { | |
| @@ -502,7 +523,7 @@ getHomeR = do | |
| } | |
| if (res == 20) { | |
| conn.send("WINNER" + player) | |
| - } | |
| + } | |
| return res; | |
| }; | |
| @@ -599,10 +620,10 @@ getHomeR = do | |
| var gak = [yak2.a, yak2.b, yak2.c, res, cow2[0]]; | |
| $("#output3").html(""); | |
| $("#submitD").show(); | |
| - if (res === 20) { | |
| - score += 1; | |
| - conn.send("WINNER" + player); | |
| - return gak; | |
| + if (res === 20) { | |
| + score += 1; | |
| + conn.send("WINNER" + player); | |
| + return gak; | |
| } | |
| else {return gak}; | |
| } | |
| @@ -643,25 +664,25 @@ getHomeR = do | |
| else if (a != b) { | |
| $("#output3").html(""); | |
| var rs = calculate(yak3.a, yak3.b, yak3.c); | |
| - var gak = [yak3.a, yak3.b, yak3.c, rs]; | |
| - $("#submitD").hide(); | |
| + var gak = [yak3.a, yak3.b, yak3.c, rs]; | |
| + $("#submitD").hide(); | |
| - if (rs !== 20 && TOG == "off") { | |
| + if (rs !== 20 && TOG == "off") { | |
| score -= 1; | |
| - conn.send("LOSER" + player) | |
| - return gak; | |
| + conn.send("LOSER" + player) | |
| + return gak; | |
| } | |
| - if (rs !== 20 && TOG == "on") { | |
| + if (rs !== 20 && TOG == "on") { | |
| score -= 1; | |
| - conn.send("LOSER2" + player) | |
| - return gak; | |
| - } | |
| - | |
| - if (rs === 20) { | |
| - score += 1; | |
| - conn.send("WINNER" + player); | |
| - return gak; | |
| + conn.send("LOSER2" + player) | |
| + return gak; | |
| + } | |
| + | |
| + if (rs === 20) { | |
| + score += 1; | |
| + conn.send("WINNER" + player); | |
| + return gak; | |
| } | |
| } | |
| } | |
| @@ -671,21 +692,21 @@ getHomeR = do | |
| conn.onmessage = function(e) { | |
| var data = e.data; | |
| var p = document.createElement("p"); | |
| - p.appendChild(document.createTextNode(e.data)); | |
| + p.appendChild(document.createTextNode(e.data)); | |
| if (e.data.substring(0,4) == "COWS") { | |
| var x = e.data; | |
| - var l = x.split(","); | |
| + var l = x.split(","); | |
| var pl = l[1]; | |
| - var sc = l[2]; | |
| + var sc = l[2]; | |
| game[pl] = {"player" : pl, "score" : sc}; | |
| - players[pl] = pl | |
| - } | |
| + players[pl] = pl | |
| + } | |
| if (e.data.substring(0,9) == "SOLUTIONS") { | |
| var a = e.data; | |
| solutions = a.substring(9); | |
| - } | |
| + } | |
| if (data.substring(0,2) == "GO") { | |
| TOG = "off"; | |
| @@ -706,10 +727,10 @@ getHomeR = do | |
| $("#12").show(); | |
| $("#output2").html("Click 'SCORE' to begin calculating, <br> or 'IMPOSSIBLE' if you think competitors can't find a solution within 60 seconds. "); | |
| $("#out2").html(""); | |
| - $("#out3").show(); | |
| + $("#out3").show(); | |
| $("#SCORE1").show(); | |
| $("#SCORE3").hide() | |
| - $("#IMPOSSIBLE").show(); | |
| + $("#IMPOSSIBLE").show(); | |
| var l = data.substring(3); | |
| ls = l.split(","); | |
| $("#output4").html(ls + "<br>"); | |
| @@ -738,8 +759,8 @@ getHomeR = do | |
| $("#x9").val(a); | |
| $("#x10").val(b); | |
| $("#x11").val(c); | |
| - $("#x12").val(d); | |
| - } | |
| + $("#x12").val(d); | |
| + } | |
| if (data == "ONE") { | |
| $("#3").hide(); | |
| @@ -756,7 +777,7 @@ getHomeR = do | |
| $("#10").hide(); | |
| } | |
| - if (data.substring(0,6) == "EVAL_A") { | |
| + if (data.substring(0,6) == "EVAL_A") { | |
| var zx = e.data.split(","); | |
| var a = zx[1] | |
| var b = zx[2] | |
| @@ -789,9 +810,9 @@ getHomeR = do | |
| if (data == "THIRTY") { | |
| T = 31; | |
| - $("#IMPOSSIBLE").hide(); | |
| - $("#SCORE1").hide(); | |
| - $("#roll").hide(); | |
| + $("#IMPOSSIBLE").hide(); | |
| + $("#SCORE1").hide(); | |
| + $("#roll").hide(); | |
| $("#output2").html(""); | |
| } | |
| @@ -805,8 +826,8 @@ getHomeR = do | |
| T = 31; | |
| T3 = (-1); | |
| $("#IMPOSSIBLE").hide(); | |
| - $("#SCORE3").hide(); | |
| - $("#roll").hide(); | |
| + $("#SCORE3").hide(); | |
| + $("#roll").hide(); | |
| } | |
| if (data.substring(0,5) == "SIXTY") { | |
| @@ -817,10 +838,10 @@ getHomeR = do | |
| $("#submitB").hide(); | |
| $("#SCORE1").hide(); | |
| $("#IMPOSSIBLE").hide(); | |
| - $("#output2").show(); | |
| + $("#output2").show(); | |
| $("#output2").html("The deduction from " + name + "'s score might be temporary.") | |
| - impossiblePlayer = e.data.substring(5); | |
| - $("#output4").html("impossiblePlayer is " + impossiblePlayer); | |
| + impossiblePlayer = e.data.substring(5); | |
| + $("#output4").html("impossiblePlayer is " + impossiblePlayer); | |
| } | |
| if (data.substring(0,6) == "WINNER") { // The browsers keep score | |
| @@ -835,13 +856,13 @@ getHomeR = do | |
| $("#submitC").hide(); | |
| $("#submitD").hide(); | |
| $("#SCORE3").hide(); | |
| - winner(win); | |
| - } | |
| + winner(win); | |
| + } | |
| - if (data.substring(0,5) == "LOSER") { | |
| + if (data.substring(0,5) == "LOSER") { | |
| T = -1; | |
| t2 = -1; | |
| - var lose = e.data.substring(5); | |
| + var lose = e.data.substring(5); | |
| $("#roll").show(); | |
| $("#submitA").hide(); | |
| $("#submitB").hide(); | |
| @@ -851,14 +872,14 @@ getHomeR = do | |
| loser(lose); | |
| } | |
| - if (data.substring(0,6) == "LOSER2") { | |
| + if (data.substring(0,6) == "LOSER2") { | |
| T = -1; | |
| T4 = -1; | |
| var lose = e.data.substring(6); | |
| if (player == impossiblePlayer) { | |
| score += 2; | |
| } | |
| - $("#output2").html(""); | |
| + $("#output2").html(""); | |
| $("#roll").show(); | |
| $("#submitA").hide(); | |
| $("#submitB").hide(); | |
| @@ -866,11 +887,11 @@ getHomeR = do | |
| $("#submitD").hide(); | |
| $("#SCORE3").hide(); | |
| loser2(lose); | |
| - } | |
| + } | |
| else if (data.substring(0,5) == "LOGIN") { | |
| $("#output").html(e.data.substring(5) + " has joined."); | |
| - } | |
| + } | |
| }; | |
| // ************************************************************* Sign-in *** | |
| @@ -883,8 +904,3 @@ getHomeR = do | |
| }); | |
| |] | |
| - | |
| -main :: IO () | |
| -main = do | |
| - chan <- atomically newBroadcastTChan | |
| - warp 3000 $ App chan |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment