diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,15 @@
+# 0.3.7.2
+
+Stops Tag Soup from escaping &"<> which breaks HTML entities
+
+# 0.3.7.1
+
+add max height and max width as valid style attributes
+
+# 0.3.7
+
+clear the contents of style and script tags instead of escaping them
+
+# 0.3.5.6
+
+expose safeTagName
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
 # Summary
 
+[![Tests](https://github.com/yesodweb/haskell-xss-sanitize/actions/workflows/tests.yml/badge.svg)](https://github.com/yesodweb/haskell-xss-sanitize/actions/workflows/tests.yml)
+
 xss-sanitize allows you to accept html from untrusted sources by first filtering it through a white list.
 The white list filtering is fairly comprehensive, including support for css in style attributes, but there are limitations enumerated below.
 
@@ -55,7 +57,7 @@
 
 Ultimately this is where your security comes from. I would expect that a faulty white list would act as a strong deterrent, but this library strives for correctness.
 
-The [source code of html5lib](http://code.google.com/p/html5lib/source/browse/python/html5lib/sanitizer.py) is the source of the white list and my implementation reference. If you feel a tag is missing from the white list, check to see if it has been added there.
+The [source code of html5lib](https://github.com/html5lib/html5lib-python/blob/master/html5lib/filters/sanitizer.py) is the source of the white list and my implementation reference. If you feel a tag is missing from the white list, check to see if it has been added there.
 
 If anyone knows of better sources or thinks a particular tag/attribute/value may be vulnerable, please let me know.
 [HTML Purifier](http://htmlpurifier.org/live/smoketests/printDefinition.php) does have a more permissive and configurable (yet safe) white list if you are looking to add anything.
diff --git a/Text/HTML/SanitizeXSS.hs b/Text/HTML/SanitizeXSS.hs
deleted file mode 100644
--- a/Text/HTML/SanitizeXSS.hs
+++ /dev/null
@@ -1,266 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
--- | Sanatize HTML to prevent XSS attacks.
---
--- See README.md <http://github.com/gregwebs/haskell-xss-sanitize> for more details.
-module Text.HTML.SanitizeXSS
-    (
-    -- * Sanitize
-      sanitize
-    , sanitizeBalance
-    , sanitizeXSS
-
-    -- * Custom filtering
-    , filterTags
-    , safeTags
-    , balanceTags
-
-    -- * Utilities
-    , sanitizeAttribute
-    , sanitaryURI
-    ) where
-
-import Text.HTML.SanitizeXSS.Css
-
-import Text.HTML.TagSoup
-
-import Data.Set (Set(), member, notMember, (\\), fromList, fromAscList)
-import Data.Char ( toLower )
-import Data.Text (Text)
-import qualified Data.Text as T
-
-import Network.URI ( parseURIReference, URI (..),
-                     isAllowedInURI, escapeURIString, uriScheme )
-import Codec.Binary.UTF8.String ( encodeString )
-
-import qualified Data.Map as Map
-import Data.Maybe (catMaybes)
-
-
--- | Sanitize HTML to prevent XSS attacks.  This is equivalent to @filterTags safeTags@.
-sanitize :: Text -> Text
-sanitize = sanitizeXSS
-
--- | alias of sanitize function
-sanitizeXSS :: Text -> Text
-sanitizeXSS = filterTags safeTags
-
--- | Sanitize HTML to prevent XSS attacks and also make sure the tags are balanced.
---   This is equivalent to @filterTags (balanceTags . safeTags)@.
-sanitizeBalance :: Text -> Text
-sanitizeBalance = filterTags (balanceTags . safeTags)
-
--- | Filter which makes sure the tags are balanced.  Use with 'filterTags' and 'safeTags' to create a custom filter.
-balanceTags :: [Tag Text] -> [Tag Text]
-balanceTags = balance Map.empty
-
--- | Parse the given text to a list of tags, apply the given filtering function, and render back to HTML.
---   You can insert your own custom filtering but make sure you compose your filtering function with 'safeTags'!
-filterTags :: ([Tag Text] -> [Tag Text]) -> Text -> Text
-filterTags f = renderTagsOptions renderOptions {
-    optMinimize = \x -> x `member` voidElems -- <img><img> converts to <img />, <a/> converts to <a></a>
-  } .  f . canonicalizeTags . parseTags
-
-voidElems :: Set T.Text
-voidElems = fromAscList $ T.words $ T.pack "area base br col command embed hr img input keygen link meta param source track wbr"
-
-balance :: Map.Map Text Int -> [Tag Text] -> [Tag Text]
-balance m [] =
-    concatMap go $ Map.toList m
-  where
-    go (name, i)
-        | noClosing name = []
-        | otherwise = replicate i $ TagClose name
-    noClosing = flip member voidElems
-balance m (t@(TagClose name):tags) =
-    case Map.lookup name m of
-        Nothing -> TagOpen name [] : TagClose name : balance m tags
-        Just i ->
-            let m' = if i == 1
-                        then Map.delete name m
-                        else Map.insert name (i - 1) m
-             in t : balance m' tags
-balance m (TagOpen name as : tags) =
-    TagOpen name as : balance m' tags
-  where
-    m' = case Map.lookup name m of
-            Nothing -> Map.insert name 1 m
-            Just i -> Map.insert name (i + 1) m
-balance m (t:ts) = t : balance m ts
-
--- | Filters out any usafe tags and attributes. Use with filterTags to create a custom filter.
-safeTags :: [Tag Text] -> [Tag Text]
-safeTags [] = []
-safeTags (t@(TagClose name):tags)
-    | safeTagName name = t : safeTags tags
-    | otherwise = safeTags tags
-safeTags (TagOpen name attributes:tags)
-  | safeTagName name = TagOpen name
-      (catMaybes $ map sanitizeAttribute attributes) : safeTags tags
-  | otherwise = safeTags tags
-safeTags (t:tags) = t:safeTags tags
-
-safeTagName :: Text -> Bool
-safeTagName tagname = tagname `member` sanitaryTags
-
-safeAttribute :: (Text, Text) -> Bool
-safeAttribute (name, value) = name `member` sanitaryAttributes &&
-  (name `notMember` uri_attributes || sanitaryURI value)
-
--- | low-level API if you have your own HTML parser. Used by safeTags.
-sanitizeAttribute :: (Text, Text) -> Maybe (Text, Text)
-sanitizeAttribute ("style", value) =
-    let css = sanitizeCSS value
-    in  if T.null css then Nothing else Just ("style", css)
-sanitizeAttribute attr | safeAttribute attr = Just attr
-                       | otherwise = Nothing
-         
-
--- | Returns @True@ if the specified URI is not a potential security risk.
-sanitaryURI :: Text -> Bool
-sanitaryURI u =
-  case parseURIReference (escapeURI $ T.unpack u) of
-     Just p  -> (null (uriScheme p)) ||
-                ((map toLower $ init $ uriScheme p) `member` safeURISchemes)
-     Nothing -> False
-
-
--- | Escape unicode characters in a URI.  Characters that are
--- already valid in a URI, including % and ?, are left alone.
-escapeURI :: String -> String
-escapeURI = escapeURIString isAllowedInURI . encodeString
-
-safeURISchemes :: Set String
-safeURISchemes = fromList acceptable_protocols
-
-sanitaryTags :: Set Text
-sanitaryTags = fromList (acceptable_elements ++ mathml_elements ++ svg_elements)
-  \\ (fromList svg_allow_local_href) -- extra filtering not implemented
-
-sanitaryAttributes :: Set Text
-sanitaryAttributes = fromList (allowed_html_uri_attributes ++ acceptable_attributes ++ mathml_attributes ++ svg_attributes)
-  \\ (fromList svg_attr_val_allows_ref) -- extra unescaping not implemented
-
-allowed_html_uri_attributes :: [Text]
-allowed_html_uri_attributes = ["href", "src", "cite", "action", "longdesc"]
-
-uri_attributes :: Set Text
-uri_attributes = fromList $ allowed_html_uri_attributes ++ ["xlink:href", "xml:base"]
-
-acceptable_elements :: [Text]
-acceptable_elements = ["a", "abbr", "acronym", "address", "area",
-    "article", "aside", "audio", "b", "big", "blockquote", "br", "button",
-    "canvas", "caption", "center", "cite", "code", "col", "colgroup",
-    "command", "datagrid", "datalist", "dd", "del", "details", "dfn",
-    "dialog", "dir", "div", "dl", "dt", "em", "event-source", "fieldset",
-    "figcaption", "figure", "footer", "font", "form", "header", "h1", "h2",
-    "h3", "h4", "h5", "h6", "hr", "i", "img", "input", "ins", "keygen",
-    "kbd", "label", "legend", "li", "m", "main", "map", "menu", "meter", "multicol",
-    "nav", "nextid", "ol", "output", "optgroup", "option", "p", "pre",
-    "progress", "q", "s", "samp", "section", "select", "small", "sound",
-    "source", "spacer", "span", "strike", "strong", "sub", "sup", "table",
-    "tbody", "td", "textarea", "time", "tfoot", "th", "thead", "tr", "tt",
-    "u", "ul", "var", "video"]
-  
-mathml_elements :: [Text]
-mathml_elements = ["maction", "math", "merror", "mfrac", "mi",
-    "mmultiscripts", "mn", "mo", "mover", "mpadded", "mphantom",
-    "mprescripts", "mroot", "mrow", "mspace", "msqrt", "mstyle", "msub",
-    "msubsup", "msup", "mtable", "mtd", "mtext", "mtr", "munder",
-    "munderover", "none"]
-
--- this should include altGlyph I think
-svg_elements :: [Text]
-svg_elements = ["a", "animate", "animateColor", "animateMotion",
-    "animateTransform", "clipPath", "circle", "defs", "desc", "ellipse",
-    "font-face", "font-face-name", "font-face-src", "g", "glyph", "hkern",
-    "linearGradient", "line", "marker", "metadata", "missing-glyph",
-    "mpath", "path", "polygon", "polyline", "radialGradient", "rect",
-    "set", "stop", "svg", "switch", "text", "title", "tspan", "use"]
-  
-acceptable_attributes :: [Text]
-acceptable_attributes = ["abbr", "accept", "accept-charset", "accesskey",
-    "align", "alt", "autocomplete", "autofocus", "axis",
-    "background", "balance", "bgcolor", "bgproperties", "border",
-    "bordercolor", "bordercolordark", "bordercolorlight", "bottompadding",
-    "cellpadding", "cellspacing", "ch", "challenge", "char", "charoff",
-    "choff", "charset", "checked", "class", "clear", "color",
-    "cols", "colspan", "compact", "contenteditable", "controls", "coords",
-    -- "data", TODO: allow this with further filtering
-    "datafld", "datapagesize", "datasrc", "datetime", "default",
-    "delay", "dir", "disabled", "draggable", "dynsrc", "enctype", "end",
-    "face", "for", "form", "frame", "galleryimg", "gutter", "headers",
-    "height", "hidefocus", "hidden", "high", "hreflang", "hspace",
-    "icon", "id", "inputmode", "ismap", "keytype", "label", "leftspacing",
-    "lang", "list", "loop", "loopcount", "loopend",
-    "loopstart", "low", "lowsrc", "max", "maxlength", "media", "method",
-    "min", "multiple", "name", "nohref", "noshade", "nowrap", "open",
-    "optimum", "pattern", "ping", "point-size", "prompt", "pqg",
-    "radiogroup", "readonly", "rel", "repeat-max", "repeat-min",
-    "replace", "required", "rev", "rightspacing", "rows", "rowspan",
-    "rules", "scope", "selected", "shape", "size", "span", "start",
-    "step",
-    "style", -- gets further filtering
-    "summary", "suppress", "tabindex", "target",
-    "template", "title", "toppadding", "type", "unselectable", "usemap",
-    "urn", "valign", "value", "variable", "volume", "vspace", "vrml",
-    "width", "wrap", "xml:lang"]
-
-acceptable_protocols :: [String]
-acceptable_protocols = [ "ed2k", "ftp", "http", "https", "irc",
-    "mailto", "news", "gopher", "nntp", "telnet", "webcal",
-    "xmpp", "callto", "feed", "urn", "aim", "rsync", "tag",
-    "ssh", "sftp", "rtsp", "afs" ]
-
-mathml_attributes :: [Text]
-mathml_attributes = ["actiontype", "align", "columnalign", "columnalign",
-    "columnalign", "columnlines", "columnspacing", "columnspan", "depth",
-    "display", "displaystyle", "equalcolumns", "equalrows", "fence",
-    "fontstyle", "fontweight", "frame", "height", "linethickness", "lspace",
-    "mathbackground", "mathcolor", "mathvariant", "mathvariant", "maxsize",
-    "minsize", "other", "rowalign", "rowalign", "rowalign", "rowlines",
-    "rowspacing", "rowspan", "rspace", "scriptlevel", "selection",
-    "separator", "stretchy", "width", "width", "xlink:href", "xlink:show",
-    "xlink:type", "xmlns", "xmlns:xlink"]
-
-svg_attributes :: [Text]
-svg_attributes = ["accent-height", "accumulate", "additive", "alphabetic",
-    "arabic-form", "ascent", "attributeName", "attributeType",
-    "baseProfile", "bbox", "begin", "by", "calcMode", "cap-height",
-    "class", "clip-path", "color", "color-rendering", "content", "cx",
-    "cy", "d", "dx", "dy", "descent", "display", "dur", "end", "fill",
-    "fill-opacity", "fill-rule", "font-family", "font-size",
-    "font-stretch", "font-style", "font-variant", "font-weight", "from",
-    "fx", "fy", "g1", "g2", "glyph-name", "gradientUnits", "hanging",
-    "height", "horiz-adv-x", "horiz-origin-x", "id", "ideographic", "k",
-    "keyPoints", "keySplines", "keyTimes", "lang", "marker-end",
-    "marker-mid", "marker-start", "markerHeight", "markerUnits",
-    "markerWidth", "mathematical", "max", "min", "name", "offset",
-    "opacity", "orient", "origin", "overline-position",
-    "overline-thickness", "panose-1", "path", "pathLength", "points",
-    "preserveAspectRatio", "r", "refX", "refY", "repeatCount",
-    "repeatDur", "requiredExtensions", "requiredFeatures", "restart",
-    "rotate", "rx", "ry", "slope", "stemh", "stemv", "stop-color",
-    "stop-opacity", "strikethrough-position", "strikethrough-thickness",
-    "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap",
-    "stroke-linejoin", "stroke-miterlimit", "stroke-opacity",
-    "stroke-width", "systemLanguage", "target", "text-anchor", "to",
-    "transform", "type", "u1", "u2", "underline-position",
-    "underline-thickness", "unicode", "unicode-range", "units-per-em",
-    "values", "version", "viewBox", "visibility", "width", "widths", "x",
-    "x-height", "x1", "x2", "xlink:actuate", "xlink:arcrole",
-    "xlink:href", "xlink:role", "xlink:show", "xlink:title", "xlink:type",
-    "xml:base", "xml:lang", "xml:space", "xmlns", "xmlns:xlink", "y",
-    "y1", "y2", "zoomAndPan"]
-
--- the values for these need to be escaped
-svg_attr_val_allows_ref :: [Text]
-svg_attr_val_allows_ref = ["clip-path", "color-profile", "cursor", "fill",
-    "filter", "marker", "marker-start", "marker-mid", "marker-end",
-    "mask", "stroke"]
-
-svg_allow_local_href :: [Text]
-svg_allow_local_href = ["altGlyph", "animate", "animateColor",
-    "animateMotion", "animateTransform", "cursor", "feImage", "filter",
-    "linearGradient", "pattern", "radialGradient", "textpath", "tref",
-    "set", "use"]
-
diff --git a/Text/HTML/SanitizeXSS/Css.hs b/Text/HTML/SanitizeXSS/Css.hs
deleted file mode 100644
--- a/Text/HTML/SanitizeXSS/Css.hs
+++ /dev/null
@@ -1,140 +0,0 @@
-{-# LANGUAGE OverloadedStrings, CPP #-}
-module Text.HTML.SanitizeXSS.Css (
-  sanitizeCSS
-#ifdef TEST
-, allowedCssAttributeValue
-#endif
-  ) where
-
-import Data.Text (Text)
-import qualified Data.Text as T
-import Data.Attoparsec.Text
-import Data.Text.Lazy.Builder (toLazyText)
-import Data.Text.Lazy (toStrict)
-import Data.Set (member, fromList, Set)
-import Data.Char (isDigit)
-import Control.Applicative ((<|>), pure)
-import Text.CSS.Render (renderAttrs)
-import Text.CSS.Parse (parseAttrs)
-import Prelude hiding (takeWhile)
-
--- import FileLocation (debug, debugM)
-
-
--- this is a direct translation from sanitizer.py, except
---   sanitizer.py filters out url(), but this is redundant
-sanitizeCSS :: Text -> Text
-sanitizeCSS css = toStrict . toLazyText .
-    renderAttrs . filter isSanitaryAttr . filterUrl $ parseAttributes
-  where
-    filterUrl :: [(Text,Text)] -> [(Text,Text)]
-    filterUrl = map filterUrlAttribute
-      where
-        filterUrlAttribute :: (Text, Text) -> (Text, Text)
-        filterUrlAttribute (prop,value) =
-            case parseOnly rejectUrl value of
-              Left _ -> (prop,value)
-              Right noUrl -> filterUrlAttribute (prop, noUrl)
-
-        rejectUrl = do
-          pre <- manyTill anyChar (string "url")
-          skipMany space
-          _<-char '('
-          skipWhile (/= ')')
-          _<-char ')'
-          rest <- takeText
-          return $ T.append (T.pack pre) rest
-
-
-    parseAttributes = case parseAttrs css of
-      Left _ -> []
-      Right as -> as
-
-    isSanitaryAttr (_, "") = False
-    isSanitaryAttr ("",_)  = False
-    isSanitaryAttr (prop, value)
-      | prop `member` allowed_css_properties = True
-      | (T.takeWhile (/= '-') prop) `member` allowed_css_unit_properties &&
-          all allowedCssAttributeValue (T.words value) = True
-      | prop `member` allowed_svg_properties = True
-      | otherwise = False
-
-    allowed_css_unit_properties :: Set Text
-    allowed_css_unit_properties = fromList ["background","border","margin","padding"]
-
-allowedCssAttributeValue :: Text -> Bool
-allowedCssAttributeValue val =
-  val `member` allowed_css_keywords ||
-    case parseOnly allowedCssAttributeParser val of
-        Left _ -> False
-        Right b -> b
-  where
-    allowedCssAttributeParser = do
-      rgb <|> hex <|> rgb <|> cssUnit
-
-    aToF = fromList "abcdef"
-
-    hex = do
-      _ <- char '#'
-      hx <- takeText
-      return $ T.all (\c -> isDigit c || (c `member` aToF)) hx
-
-    -- should have used sepBy (symbol ",")
-    rgb = do
-      _<- string "rgb("
-      skipMany1 digit >> skipOk (== '%')
-      skip (== ',')
-      skipMany digit >> skipOk (== '%')
-      skip (== ',')
-      skipMany digit >> skipOk (== '%')
-      skip (== ')')
-      return True
-
-    cssUnit = do
-      skip isDigit
-      skipOk isDigit
-      skipOk (== '.')
-      skipOk isDigit >> skipOk isDigit
-      skipSpace
-      unit <- takeText
-      return $ T.null unit || unit `member` allowed_css_attribute_value_units
-
-skipOk :: (Char -> Bool) -> Parser ()
-skipOk p = skip p <|> pure ()
-
-allowed_css_attribute_value_units :: Set Text
-allowed_css_attribute_value_units = fromList
-  [ "cm", "em", "ex", "in", "mm", "pc", "pt", "px", "%", ",", "\\"]
-
-allowed_css_properties :: Set Text
-allowed_css_properties = fromList acceptable_css_properties
-  where
-    acceptable_css_properties = ["azimuth", "background-color",
-      "border-bottom-color", "border-collapse", "border-color",
-      "border-left-color", "border-right-color", "border-top-color", "clear",
-      "color", "cursor", "direction", "display", "elevation", "float", "font",
-      "font-family", "font-size", "font-style", "font-variant", "font-weight",
-      "height", "letter-spacing", "line-height", "overflow", "pause",
-      "pause-after", "pause-before", "pitch", "pitch-range", "richness",
-      "speak", "speak-header", "speak-numeral", "speak-punctuation",
-      "speech-rate", "stress", "text-align", "text-decoration", "text-indent",
-      "unicode-bidi", "vertical-align", "voice-family", "volume",
-      "white-space", "width"]
-
-allowed_css_keywords :: Set Text
-allowed_css_keywords = fromList acceptable_css_keywords
-  where
-    acceptable_css_keywords = ["auto", "aqua", "black", "block", "blue",
-      "bold", "both", "bottom", "brown", "center", "collapse", "dashed",
-      "dotted", "fuchsia", "gray", "green", "!important", "italic", "left",
-      "lime", "maroon", "medium", "none", "navy", "normal", "nowrap", "olive",
-      "pointer", "purple", "red", "right", "solid", "silver", "teal", "top",
-      "transparent", "underline", "white", "yellow"]
-
--- used in css filtering
-allowed_svg_properties :: Set Text
-allowed_svg_properties = fromList acceptable_svg_properties
-  where
-    acceptable_svg_properties = [ "fill", "fill-opacity", "fill-rule",
-        "stroke", "stroke-width", "stroke-linecap", "stroke-linejoin",
-        "stroke-opacity"]
diff --git a/src/Text/HTML/SanitizeXSS.hs b/src/Text/HTML/SanitizeXSS.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/SanitizeXSS.hs
@@ -0,0 +1,311 @@
+{-# LANGUAGE OverloadedStrings #-}
+-- | Sanatize HTML to prevent XSS attacks.
+--
+-- See README.md <http://github.com/gregwebs/haskell-xss-sanitize> for more details.
+module Text.HTML.SanitizeXSS
+    (
+    -- * Sanitize
+      sanitize
+    , sanitizeBalance
+    , sanitizeXSS
+
+    -- * Custom filtering
+    , filterTags
+    , safeTags
+    , safeTagsCustom
+    , clearTags
+    , clearTagsCustom
+    , balanceTags
+
+    -- * Utilities
+    , safeTagName
+    , sanitizeAttribute
+    , sanitaryURI
+    ) where
+
+import Text.HTML.SanitizeXSS.Css
+
+import Text.HTML.TagSoup
+
+import Data.Set (Set(), member, notMember, (\\), fromList, fromAscList)
+import Data.Char ( toLower )
+import Data.Text (Text)
+import qualified Data.Text as T
+
+import Network.URI ( parseURIReference, URI (..),
+                     isAllowedInURI, escapeURIString, uriScheme )
+import Codec.Binary.UTF8.String ( encodeString )
+
+import Data.Maybe (mapMaybe)
+
+
+-- | Sanitize HTML to prevent XSS attacks.  This is equivalent to @filterTags safeTags@.
+sanitize :: Text -> Text
+sanitize = sanitizeXSS
+
+-- | alias of sanitize function
+sanitizeXSS :: Text -> Text
+sanitizeXSS = filterTags (safeTags . clearTags)
+
+-- | Sanitize HTML to prevent XSS attacks and also make sure the tags are balanced.
+--   This is equivalent to @filterTags (balanceTags . safeTags)@.
+sanitizeBalance :: Text -> Text
+sanitizeBalance = filterTags (balanceTags . safeTags . clearTags)
+
+-- | Filter which makes sure the tags are balanced.  Use with 'filterTags' and 'safeTags' to create a custom filter.
+balanceTags :: [Tag Text] -> [Tag Text]
+balanceTags = balance []
+
+-- | Parse the given text to a list of tags, apply the given filtering
+-- function, and render back to HTML. You can insert your own custom
+-- filtering, but make sure you compose your filtering function with
+-- 'safeTags' and 'clearTags' or 'safeTagsCustom' and 'clearTagsCustom'.
+filterTags :: ([Tag Text] -> [Tag Text]) -> Text -> Text
+filterTags f = renderTagsOptions renderOptions {
+    optEscape = id -- stops &"<> from being escaped which breaks existing HTML entities
+  , optMinimize = \x -> x `member` voidElems -- <img><img> converts to <img />, <a/> converts to <a></a>
+  } .  f . canonicalizeTags . parseTagsOptions (parseOptionsEntities (const Nothing))
+
+voidElems :: Set T.Text
+voidElems = fromAscList $ T.words $ T.pack "area base br col command embed hr img input keygen link meta param source track wbr"
+
+balance :: [Text] -- ^ unclosed tags
+        -> [Tag Text] -> [Tag Text]
+balance unclosed [] = map TagClose $ filter (`notMember` voidElems) unclosed
+balance (x:xs) tags'@(TagClose name:tags)
+    | x == name = TagClose name : balance xs tags
+    | x `member` voidElems = balance xs tags'
+    | otherwise = TagOpen name [] : TagClose name : balance (x:xs) tags
+balance unclosed (TagOpen name as : tags) =
+    TagOpen name as : balance (name : unclosed) tags
+balance unclosed (t:ts) = t : balance unclosed ts
+
+-- | Filters out unsafe tags and sanitizes attributes. Use with
+-- filterTags to create a custom filter.
+safeTags :: [Tag Text] -> [Tag Text]
+safeTags = safeTagsCustom safeTagName sanitizeAttribute
+
+-- | Filters out unsafe tags and sanitizes attributes, like
+-- 'safeTags', but uses custom functions for determining which tags
+-- are safe and for sanitizing attributes. This allows you to add or
+-- remove specific tags or attributes on the white list, or to use
+-- your own white list.
+--
+-- @safeTagsCustom safeTagName sanitizeAttribute@ is equivalent to
+-- 'safeTags'.
+--
+-- @since 0.3.6
+safeTagsCustom ::
+     (Text -> Bool)                       -- ^ Select safe tags, like
+                                          -- 'safeTagName'
+  -> ((Text, Text) -> Maybe (Text, Text)) -- ^ Sanitize attributes,
+                                          -- like 'sanitizeAttribute'
+  -> [Tag Text] -> [Tag Text]
+safeTagsCustom _ _ [] = []
+safeTagsCustom safeName sanitizeAttr (t@(TagClose name):tags)
+    | safeName name = t : safeTagsCustom safeName sanitizeAttr tags
+    | otherwise = safeTagsCustom safeName sanitizeAttr tags
+safeTagsCustom safeName sanitizeAttr (TagOpen name attributes:tags)
+  | safeName name = TagOpen name (mapMaybe sanitizeAttr attributes) :
+      safeTagsCustom safeName sanitizeAttr tags
+  | otherwise = safeTagsCustom safeName sanitizeAttr tags
+safeTagsCustom n a (t:tags) = t : safeTagsCustom n a tags
+
+-- | Directly removes tags even if they are not closed properly.
+-- This is importent to clear out both the script and iframe tag 
+-- in sequences like "<script><iframe></iframe>".
+clearTags :: [Tag Text] -> [Tag Text]
+clearTags = clearTagsCustom clearableTagName
+
+-- | Directly removes tags, like clearTags, but uses a custom
+-- function for determining which tags are safe.
+--
+-- @clearTagsCustom clearableTagName@ is equivalent to
+-- 'clearTags'.
+clearTagsCustom :: (Text -> Bool) -> [Tag Text] -> [Tag Text]
+clearTagsCustom _ [] = []
+clearTagsCustom clearableName (tag@(TagOpen name _) : tags)
+    | clearableName name = tag : go 0 tags
+    | otherwise = tag : clearTagsCustom clearableName tags
+  where
+    go d (t@(TagOpen n _) : ts)
+        | n /= name = go d ts
+        | otherwise = go (d + 1) ts
+    go d (t@(TagClose n) : ts)
+        | n /= name = go d ts
+        | d == 0 = t : clearTagsCustom clearableName ts
+        | otherwise = go (d - 1) ts
+    go d (t : ts) = go d ts
+    go d [] = []
+clearTagsCustom clearableName (t : tags) = t : clearTagsCustom clearableName tags
+
+safeTagName :: Text -> Bool
+safeTagName tagname = tagname `member` sanitaryTags
+
+safeAttribute :: (Text, Text) -> Bool
+safeAttribute (name, value) = name `member` sanitaryAttributes &&
+  (name `notMember` uri_attributes || sanitaryURI value)
+
+clearableTagName :: Text -> Bool
+clearableTagName tagname = tagname `member` clearableTags
+
+-- | low-level API if you have your own HTML parser. Used by safeTags.
+sanitizeAttribute :: (Text, Text) -> Maybe (Text, Text)
+sanitizeAttribute ("style", value) =
+    let css = sanitizeCSS value
+    in  if T.null css then Nothing else Just ("style", css)
+sanitizeAttribute attr | safeAttribute attr = Just attr
+                       | otherwise = Nothing
+         
+
+-- | Returns @True@ if the specified URI is not a potential security risk.
+sanitaryURI :: Text -> Bool
+sanitaryURI u =
+  case parseURIReference (escapeURI $ T.unpack u) of
+     Just p  -> (null (uriScheme p)) ||
+                ((map toLower $ init $ uriScheme p) `member` safeURISchemes)
+     Nothing -> False
+
+
+-- | Escape unicode characters in a URI.  Characters that are
+-- already valid in a URI, including % and ?, are left alone.
+escapeURI :: String -> String
+escapeURI = escapeURIString isAllowedInURI . encodeString
+
+safeURISchemes :: Set String
+safeURISchemes = fromList acceptable_protocols
+
+sanitaryTags :: Set Text
+sanitaryTags = fromList (acceptable_elements ++ mathml_elements ++ svg_elements)
+  \\ (fromList svg_allow_local_href) -- extra filtering not implemented
+
+sanitaryAttributes :: Set Text
+sanitaryAttributes = fromList (allowed_html_uri_attributes ++ acceptable_attributes ++ mathml_attributes ++ svg_attributes)
+  \\ (fromList svg_attr_val_allows_ref) -- extra unescaping not implemented
+
+clearableTags :: Set Text
+clearableTags = fromList ["script", "style"]
+
+allowed_html_uri_attributes :: [Text]
+allowed_html_uri_attributes = ["href", "src", "cite", "action", "longdesc"]
+
+uri_attributes :: Set Text
+uri_attributes = fromList $ allowed_html_uri_attributes ++ ["xlink:href", "xml:base"]
+
+acceptable_elements :: [Text]
+acceptable_elements = ["a", "abbr", "acronym", "address", "area",
+    "article", "aside", "audio", "b", "big", "blockquote", "br", "button",
+    "canvas", "caption", "center", "cite", "code", "col", "colgroup",
+    "command", "datagrid", "datalist", "dd", "del", "details", "dfn",
+    "dialog", "dir", "div", "dl", "dt", "em", "event-source", "fieldset",
+    "figcaption", "figure", "footer", "font", "form", "header", "h1", "h2",
+    "h3", "h4", "h5", "h6", "hr", "i", "img", "input", "ins", "keygen",
+    "kbd", "label", "legend", "li", "m", "main", "map", "menu", "meter", "multicol",
+    "nav", "nextid", "ol", "output", "optgroup", "option", "p", "pre",
+    "progress", "q", "s", "samp", "section", "select", "small", "sound",
+    "source", "spacer", "span", "strike", "strong", "sub", "sup", "table",
+    "tbody", "td", "textarea", "time", "tfoot", "th", "thead", "tr", "tt",
+    "u", "ul", "var", "video"]
+  
+mathml_elements :: [Text]
+mathml_elements = ["maction", "math", "merror", "mfrac", "mi",
+    "mmultiscripts", "mn", "mo", "mover", "mpadded", "mphantom",
+    "mprescripts", "mroot", "mrow", "mspace", "msqrt", "mstyle", "msub",
+    "msubsup", "msup", "mtable", "mtd", "mtext", "mtr", "munder",
+    "munderover", "none"]
+
+-- this should include altGlyph I think
+svg_elements :: [Text]
+svg_elements = ["a", "animate", "animateColor", "animateMotion",
+    "animateTransform", "clipPath", "circle", "defs", "desc", "ellipse",
+    "font-face", "font-face-name", "font-face-src", "g", "glyph", "hkern",
+    "linearGradient", "line", "marker", "metadata", "missing-glyph",
+    "mpath", "path", "polygon", "polyline", "radialGradient", "rect",
+    "set", "stop", "svg", "switch", "text", "title", "tspan", "use"]
+  
+acceptable_attributes :: [Text]
+acceptable_attributes = ["abbr", "accept", "accept-charset", "accesskey",
+    "align", "alt", "autocomplete", "autofocus", "axis",
+    "background", "balance", "bgcolor", "bgproperties", "border",
+    "bordercolor", "bordercolordark", "bordercolorlight", "bottompadding",
+    "cellpadding", "cellspacing", "ch", "challenge", "char", "charoff",
+    "choff", "charset", "checked", "class", "clear", "color",
+    "cols", "colspan", "compact", "contenteditable", "controls", "coords",
+    -- "data", TODO: allow this with further filtering
+    "datafld", "datapagesize", "datasrc", "datetime", "default",
+    "delay", "dir", "disabled", "draggable", "dynsrc", "enctype", "end",
+    "face", "for", "form", "frame", "galleryimg", "gutter", "headers",
+    "height", "hidefocus", "hidden", "high", "hreflang", "hspace",
+    "icon", "id", "inputmode", "ismap", "keytype", "label", "leftspacing",
+    "lang", "list", "loop", "loopcount", "loopend",
+    "loopstart", "low", "lowsrc", "max", "maxlength", "media", "method",
+    "min", "multiple", "name", "nohref", "noshade", "nowrap", "open",
+    "optimum", "pattern", "ping", "point-size", "prompt", "pqg",
+    "radiogroup", "readonly", "rel", "repeat-max", "repeat-min",
+    "replace", "required", "rev", "rightspacing", "rows", "rowspan",
+    "rules", "scope", "selected", "shape", "size", "span", "start",
+    "step",
+    "style", -- gets further filtering
+    "summary", "suppress", "tabindex", "target",
+    "template", "title", "toppadding", "type", "unselectable", "usemap",
+    "urn", "valign", "value", "variable", "volume", "vspace", "vrml",
+    "width", "wrap", "xml:lang"]
+
+acceptable_protocols :: [String]
+acceptable_protocols = [ "ed2k", "ftp", "http", "https", "irc",
+    "mailto", "news", "gopher", "nntp", "telnet", "webcal",
+    "xmpp", "callto", "feed", "urn", "aim", "rsync", "tag",
+    "ssh", "sftp", "rtsp", "afs" ]
+
+mathml_attributes :: [Text]
+mathml_attributes = ["actiontype", "align", "columnalign", "columnalign",
+    "columnalign", "columnlines", "columnspacing", "columnspan", "depth",
+    "display", "displaystyle", "equalcolumns", "equalrows", "fence",
+    "fontstyle", "fontweight", "frame", "height", "linethickness", "lspace",
+    "mathbackground", "mathcolor", "mathvariant", "mathvariant", "maxsize",
+    "minsize", "other", "rowalign", "rowalign", "rowalign", "rowlines",
+    "rowspacing", "rowspan", "rspace", "scriptlevel", "selection",
+    "separator", "stretchy", "width", "width", "xlink:href", "xlink:show",
+    "xlink:type", "xmlns", "xmlns:xlink"]
+
+svg_attributes :: [Text]
+svg_attributes = ["accent-height", "accumulate", "additive", "alphabetic",
+    "arabic-form", "ascent", "attributeName", "attributeType",
+    "baseProfile", "bbox", "begin", "by", "calcMode", "cap-height",
+    "class", "clip-path", "color", "color-rendering", "content", "cx",
+    "cy", "d", "dx", "dy", "descent", "display", "dur", "end", "fill",
+    "fill-opacity", "fill-rule", "font-family", "font-size",
+    "font-stretch", "font-style", "font-variant", "font-weight", "from",
+    "fx", "fy", "g1", "g2", "glyph-name", "gradientUnits", "hanging",
+    "height", "horiz-adv-x", "horiz-origin-x", "id", "ideographic", "k",
+    "keyPoints", "keySplines", "keyTimes", "lang", "marker-end",
+    "marker-mid", "marker-start", "markerHeight", "markerUnits",
+    "markerWidth", "mathematical", "max", "min", "name", "offset",
+    "opacity", "orient", "origin", "overline-position",
+    "overline-thickness", "panose-1", "path", "pathLength", "points",
+    "preserveAspectRatio", "r", "refX", "refY", "repeatCount",
+    "repeatDur", "requiredExtensions", "requiredFeatures", "restart",
+    "rotate", "rx", "ry", "slope", "stemh", "stemv", "stop-color",
+    "stop-opacity", "strikethrough-position", "strikethrough-thickness",
+    "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap",
+    "stroke-linejoin", "stroke-miterlimit", "stroke-opacity",
+    "stroke-width", "systemLanguage", "target", "text-anchor", "to",
+    "transform", "type", "u1", "u2", "underline-position",
+    "underline-thickness", "unicode", "unicode-range", "units-per-em",
+    "values", "version", "viewBox", "visibility", "width", "widths", "x",
+    "x-height", "x1", "x2", "xlink:actuate", "xlink:arcrole",
+    "xlink:href", "xlink:role", "xlink:show", "xlink:title", "xlink:type",
+    "xml:base", "xml:lang", "xml:space", "xmlns", "xmlns:xlink", "y",
+    "y1", "y2", "zoomAndPan"]
+
+-- the values for these need to be escaped
+svg_attr_val_allows_ref :: [Text]
+svg_attr_val_allows_ref = ["clip-path", "color-profile", "cursor", "fill",
+    "filter", "marker", "marker-start", "marker-mid", "marker-end",
+    "mask", "stroke"]
+
+svg_allow_local_href :: [Text]
+svg_allow_local_href = ["altGlyph", "animate", "animateColor",
+    "animateMotion", "animateTransform", "cursor", "feImage", "filter",
+    "linearGradient", "pattern", "radialGradient", "textpath", "tref",
+    "set", "use"]
diff --git a/src/Text/HTML/SanitizeXSS/Css.hs b/src/Text/HTML/SanitizeXSS/Css.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/SanitizeXSS/Css.hs
@@ -0,0 +1,140 @@
+{-# LANGUAGE OverloadedStrings, CPP #-}
+module Text.HTML.SanitizeXSS.Css (
+  sanitizeCSS
+#ifdef TEST
+, allowedCssAttributeValue
+#endif
+  ) where
+
+import Data.Text (Text)
+import qualified Data.Text as T
+import Data.Attoparsec.Text
+import Data.Text.Lazy.Builder (toLazyText)
+import Data.Text.Lazy (toStrict)
+import Data.Set (member, fromList, Set)
+import Data.Char (isDigit)
+import Control.Applicative ((<|>), pure)
+import Text.CSS.Render (renderAttrs)
+import Text.CSS.Parse (parseAttrs)
+import Prelude hiding (takeWhile)
+
+-- import FileLocation (debug, debugM)
+
+
+-- this is a direct translation from sanitizer.py, except
+--   sanitizer.py filters out url(), but this is redundant
+sanitizeCSS :: Text -> Text
+sanitizeCSS css = toStrict . toLazyText .
+    renderAttrs . filter isSanitaryAttr . filterUrl $ parseAttributes
+  where
+    filterUrl :: [(Text,Text)] -> [(Text,Text)]
+    filterUrl = map filterUrlAttribute
+      where
+        filterUrlAttribute :: (Text, Text) -> (Text, Text)
+        filterUrlAttribute (prop,value) =
+            case parseOnly rejectUrl value of
+              Left _ -> (prop,value)
+              Right noUrl -> filterUrlAttribute (prop, noUrl)
+
+        rejectUrl = do
+          pre <- manyTill anyChar (string "url")
+          skipMany space
+          _<-char '('
+          skipWhile (/= ')')
+          _<-char ')'
+          rest <- takeText
+          return $ T.append (T.pack pre) rest
+
+
+    parseAttributes = case parseAttrs css of
+      Left _ -> []
+      Right as -> as
+
+    isSanitaryAttr (_, "") = False
+    isSanitaryAttr ("",_)  = False
+    isSanitaryAttr (prop, value)
+      | prop `member` allowed_css_properties = True
+      | (T.takeWhile (/= '-') prop) `member` allowed_css_unit_properties &&
+          all allowedCssAttributeValue (T.words value) = True
+      | prop `member` allowed_svg_properties = True
+      | otherwise = False
+
+    allowed_css_unit_properties :: Set Text
+    allowed_css_unit_properties = fromList ["background","border","margin","padding"]
+
+allowedCssAttributeValue :: Text -> Bool
+allowedCssAttributeValue val =
+  val `member` allowed_css_keywords ||
+    case parseOnly allowedCssAttributeParser val of
+        Left _ -> False
+        Right b -> b
+  where
+    allowedCssAttributeParser = do
+      rgb <|> hex <|> rgb <|> cssUnit
+
+    aToF = fromList "abcdef"
+
+    hex = do
+      _ <- char '#'
+      hx <- takeText
+      return $ T.all (\c -> isDigit c || (c `member` aToF)) hx
+
+    -- should have used sepBy (symbol ",")
+    rgb = do
+      _<- string "rgb("
+      skipMany1 digit >> skipOk (== '%')
+      skip (== ',')
+      skipMany digit >> skipOk (== '%')
+      skip (== ',')
+      skipMany digit >> skipOk (== '%')
+      skip (== ')')
+      return True
+
+    cssUnit = do
+      skip isDigit
+      skipOk isDigit
+      skipOk (== '.')
+      skipOk isDigit >> skipOk isDigit
+      skipSpace
+      unit <- takeText
+      return $ T.null unit || unit `member` allowed_css_attribute_value_units
+
+skipOk :: (Char -> Bool) -> Parser ()
+skipOk p = skip p <|> pure ()
+
+allowed_css_attribute_value_units :: Set Text
+allowed_css_attribute_value_units = fromList
+  [ "cm", "em", "ex", "in", "mm", "pc", "pt", "px", "%", ",", "\\"]
+
+allowed_css_properties :: Set Text
+allowed_css_properties = fromList acceptable_css_properties
+  where
+    acceptable_css_properties = ["azimuth", "background-color",
+      "border-bottom-color", "border-collapse", "border-color",
+      "border-left-color", "border-right-color", "border-top-color", "clear",
+      "color", "cursor", "direction", "display", "elevation", "float", "font",
+      "font-family", "font-size", "font-style", "font-variant", "font-weight",
+      "height", "letter-spacing", "line-height", "max-height", "max-width",
+      "overflow", "pause", "pause-after", "pause-before", "pitch", "pitch-range",
+      "richness", "speak", "speak-header", "speak-numeral", "speak-punctuation",
+      "speech-rate", "stress", "text-align", "text-decoration", "text-indent",
+      "unicode-bidi", "vertical-align", "voice-family", "volume",
+      "white-space", "width"]
+
+allowed_css_keywords :: Set Text
+allowed_css_keywords = fromList acceptable_css_keywords
+  where
+    acceptable_css_keywords = ["auto", "aqua", "black", "block", "blue",
+      "bold", "both", "bottom", "brown", "center", "collapse", "dashed",
+      "dotted", "fuchsia", "gray", "green", "!important", "italic", "left",
+      "lime", "maroon", "medium", "none", "navy", "normal", "nowrap", "olive",
+      "pointer", "purple", "red", "right", "solid", "silver", "teal", "top",
+      "transparent", "underline", "white", "yellow"]
+
+-- used in css filtering
+allowed_svg_properties :: Set Text
+allowed_svg_properties = fromList acceptable_svg_properties
+  where
+    acceptable_svg_properties = [ "fill", "fill-opacity", "fill-rule",
+        "stroke", "stroke-width", "stroke-linecap", "stroke-linejoin",
+        "stroke-opacity"]
diff --git a/test/main.hs b/test/main.hs
--- a/test/main.hs
+++ b/test/main.hs
@@ -11,12 +11,25 @@
   let result = f actual
   result @?= expected
 
-sanitized :: Text -> Text -> Expectation
+sanitized, sanitizedB, sanitizedC :: Text -> Text -> Expectation
 sanitized = test sanitize
 sanitizedB = test sanitizeBalance
+sanitizedC = test sanitizeCustom
 
+sanitizeCustom :: Text -> Text
+sanitizeCustom = filterTags $ safeTagsCustom mySafeName mySanitizeAttr
+  where
+    mySafeName t = t `elem` myTags || safeTagName t
+    mySanitizeAttr (key, val) | key `elem` myAttrs = Just (key, val)
+    mySanitizeAttr x = sanitizeAttribute x
+    myTags = ["custtag"]
+    myAttrs = ["custattr"]
+
 main :: IO ()
 main = hspec $ do
+  describe "Sanitized HTML is not changed" $ do
+    it "HTML entities should not be escaped" $ do
+      test (filterTags safeTags) "text&nbsp;more text" "text&nbsp;more text"
   describe "html sanitizing" $ do
     it "big test" $ do
       let testHTML = " <a href='http://safe.com'>safe</a><a href='unsafe://hack.com'>anchor</a> <img src='evil://evil.com' /> <unsafe></foo> <bar /> <br></br> <b>Unbalanced</div><img src='http://safe.com'>"
@@ -85,3 +98,17 @@
       sanitizedB "<img><hr/>" "<img><hr />"
     it "removes closing voids" $ do
       sanitizedB "<img></img>" "<img />"
+    it "interleaved" $
+      sanitizedB "<i>hello<b>world</i>" "<i>hello<b>world<i></i></b></i>"
+
+  describe "customized white list" $ do
+    it "does not filter custom tags" $ do
+      let custtag = "<p><custtag></custtag></p>"
+      sanitizedC custtag custtag
+    it "filters non-custom tags" $ do
+      sanitizedC "<p><weird></weird></p>" "<p></p>"
+    it "does not filter custom attributes" $ do
+      let custattr = "<p custattr=\"foo\"></p>"
+      sanitizedC custattr custattr
+    it "filters non-custom attributes" $ do
+      sanitizedC "<p weird=\"bar\"></p>" "<p></p>"
diff --git a/xss-sanitize.cabal b/xss-sanitize.cabal
--- a/xss-sanitize.cabal
+++ b/xss-sanitize.cabal
@@ -1,59 +1,69 @@
-name:            xss-sanitize
-version:         0.3.5.3
-license:         BSD3
-license-file:    LICENSE
-author:          Greg Weber <greg@gregweber.info>
-maintainer:      Greg Weber <greg@gregweber.info>
-synopsis:        sanitize untrusted HTML to prevent XSS attacks
-description:     run untrusted HTML through Text.HTML.SanitizeXSS.sanitizeXSS to prevent XSS attacks. see README.md <http://github.com/yesodweb/haskell-xss-sanitize> for more details
-
-category:        Web
-stability:       Stable
-cabal-version:   >= 1.8 
-build-type:      Simple
-homepage:        http://github.com/yesodweb/haskell-xss-sanitize
-extra-source-files: README.md
+cabal-version: 1.12
 
-flag network-uri
-  description: Get Network.URI from the network-uri package
-  default: True
+-- This file has been generated from package.yaml by hpack version 0.35.1.
+--
+-- see: https://github.com/sol/hpack
 
-library
-    build-depends:    base == 4.*, containers
-                    , tagsoup     >= 0.12.2   && < 1
-                    , utf8-string >= 0.3      && < 1
-                    , css-text    >= 0.1.1    && < 0.2
-                    , text        >= 0.11     && < 2
-                    , attoparsec  >= 0.10.0.3 && < 1
+name:           xss-sanitize
+version:        0.3.7.2
+synopsis:       sanitize untrusted HTML to prevent XSS attacks
+description:    run untrusted HTML through Text.HTML.SanitizeXSS.sanitizeXSS to prevent XSS attacks. see README.md <http://github.com/yesodweb/haskell-xss-sanitize> for more details
+category:       Web
+stability:      Stable
+homepage:       https://github.com/yesodweb/haskell-xss-sanitize#readme
+bug-reports:    https://github.com/yesodweb/haskell-xss-sanitize/issues
+author:         Greg Weber <greg@gregweber.info>
+maintainer:     Michael Snoyman <michael@snoyman.com>
+license:        BSD2
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.md
+    ChangeLog.md
 
-    if flag(network-uri)
-      build-depends: network-uri >= 2.6
-    else
-      build-depends: network < 2.6
+source-repository head
+  type: git
+  location: https://github.com/yesodweb/haskell-xss-sanitize
 
-    exposed-modules: Text.HTML.SanitizeXSS
-    other-modules:   Text.HTML.SanitizeXSS.Css
-    ghc-options:     -Wall
+library
+  exposed-modules:
+      Text.HTML.SanitizeXSS
+  other-modules:
+      Text.HTML.SanitizeXSS.Css
+      Paths_xss_sanitize
+  hs-source-dirs:
+      src
+  build-depends:
+      attoparsec >=0.10.0.3 && <1
+    , base >=4.9.1 && <5
+    , containers
+    , css-text >=0.1.1 && <0.2
+    , network-uri >=2.6
+    , tagsoup >=0.12.2 && <1
+    , text >=0.11 && <2.1
+    , utf8-string >=0.3 && <1.1
+  default-language: Haskell2010
 
 test-suite test
-    type: exitcode-stdio-1.0
-    main-is: test/main.hs
-    cpp-options: -DTEST
-    build-depends:    base == 4.* , containers
-                    , tagsoup     >= 0.12.2   && < 1
-                    , utf8-string >= 0.3      && < 1
-                    , css-text    >= 0.1.1    && < 0.2
-                    , text        >= 0.11     && < 2
-                    , attoparsec  >= 0.10.0.3 && < 1
-                    , hspec       >= 1.3
-                    , HUnit       >= 1.2
-
-    if flag(network-uri)
-      build-depends: network-uri >= 2.6
-    else
-      build-depends: network < 2.6
-
-
-source-repository head
-  type:     git 
-  location: http://github.com/yesodweb/haskell-xss-sanitize.git
+  type: exitcode-stdio-1.0
+  main-is: main.hs
+  other-modules:
+      Text.HTML.SanitizeXSS
+      Text.HTML.SanitizeXSS.Css
+      Paths_xss_sanitize
+  hs-source-dirs:
+      test
+      src
+  cpp-options: -DTEST
+  build-depends:
+      HUnit >=1.2
+    , attoparsec >=0.10.0.3 && <1
+    , base >=4.9.1 && <5
+    , containers
+    , css-text >=0.1.1 && <0.2
+    , hspec >=1.3
+    , network-uri >=2.6
+    , tagsoup >=0.12.2 && <1
+    , text >=0.11 && <2.1
+    , utf8-string >=0.3 && <1.1
+  default-language: Haskell2010
