diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2021, Galen
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Galen nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.MD b/README.MD
new file mode 100644
--- /dev/null
+++ b/README.MD
@@ -0,0 +1,150 @@
+# Scrappy #
+
+# <img src="./scrappy-logo.png.png" width="200">
+
+
+provides a number of functions that allow for easily scraping certain patterns from websites as well control functions that allow you to rotate between multiple sites and rotate proxies in order to deal with common bot detection problems faced by scrapers. 
+
+## Scraping ## 
+
+Scraping is parsing, where we don't care about the placement of our match in a chunk of data. ScraperT is really just ParsecT (ParsecT String () Identity a)
+
+## How to depend on this project ## 
+
+Scrappy is currently not on Hackage because I honestly don't have time to perfect version bounds however through [Nix](https://nixos.org/download) you can get the package the following way:
+
+OR!! Just clone scrappy-tutorial and rename it 
+
+OR if you really want to learn (hey good for you!) 
+
+```bash 
+# assuming you've done nix-setup... I'd show you how but it depends what setup you prefer and its super simple
+nix-env -f https://github.com/obsidiansystems/nix-thunk/archive/master.tar.gz -iA command
+nix-shell -p cabal2nix
+cd yourProjectDirectory
+cabal init 
+# follow prompts
+mkdir deps 
+git clone https://github.com/Ace-Interview-Prep/scrappy.git deps/scrappy # or SSH url 
+nix-thunk pack deps/scrappy # this is technically optional but recommended
+# add scrappy to your cabal file under build-depends
+cabal2nix . --shell > shell.nix -- this will create an easy to use shell.nix file with all of your build depends
+nix-shell #you could also do nix-shell shell.nix
+cabal run my-project-name-in-cabal-file 
+```
+
+
+## Tutorials ## 
+
+- https://medium.com/p/135283dc2af
+- https://github.com/Ace-Interview-Prep/scrappy-tutorial
+
+## Main functions, Types, and Classes ## 
+
+```haskell
+
+class ElementRep (a :: * -> *) where
+--type InnerHTMLRep a = something 
+  elTag :: a b -> Elem
+  attrs :: a b -> Attrs
+  innerText' :: a b -> String 
+  matches' :: a b -> [b]
+
+instance ElementRep (Elem') where
+  elTag = _el
+  attrs = _attrs
+  innerText' = innerHtmlFull
+  matches' = innerMatches
+
+data Elem' a = Elem' { _el :: Elem 
+                     , _attrs :: Map String String 
+                     , innerMatches :: [a] 
+                     , innerHtmlFull :: String
+                     } deriving Show
+
+-- | Manager returned may be a new manager, if the given manager failed 
+getHtml :: Manager -> Url -> IO (Manager, Html) 
+getHtml' :: Url -> IO Html
+
+scrape :: ScraperT a -> Html -> Maybe [a]
+
+-- | For more advanced control over inner structure see Elem.TreeElemParser
+elemParser :: Elem -> [(String, Maybe String)] 
+            -> Maybe (ParsecT s u m a) -- Optionally scraped pattern inside this el, if specified, return element must have at least 1 
+            -> ScraperT (Elem' a)
+
+el :: Elem -> [(String, String)] -> ScraperT (Elem' String)
+
+-- | Find any expressive pattern as long as it is inside of some HTML context 
+contains :: ScraperT (Elem' a) -> ScraperT a -> ScraperT a 
+
+
+:t fmap snd getHtml' "https://google.com" >>= return . (runScraperOnHtml (el "a" [])   
+>>> IO (Maybe [Elem' a])
+
+-- Will get all <a id="link"> 's on the url that are inside
+-- divs with a class of xyz
+example :: IO (Maybe [Elem' a])
+example = runScraperOnUrl url $ el "div" [("class", "xyz")] `contains`
+        el "a" [("id", "link")]
+
+
+```
+
+Currently with this library you can request HTML and run a multitude of scraper-patterns on it, for example:
+- Scrape an element
+- Scrape an element with a specific inner pattern
+- Scrape an element with an attribute that fits a specific parser-pattern 
+- Scrape an element with a specific inner DOM-tree 
+- Scrape a group of elements that *kinda* repeats 
+   - For example, if you want a complex group that varies from page to page but to the user's eye looks the exact same (think of search results on a nice website) or even largely the same, then use the `htmlGroup` function from Scrappy.Elem.TreeElemParser  
+- Scrape any **arbitrary** parser from the [parsec library](https://hackage.haskell.org/package/parsec)
+
+You can also deeply chain! 
+- Inside any instance of the ElementRep class (Elem', TreeHTML) through contains and contains'! 
+   - For example use: think of getting all prices 
+- In a sequence!
+   - skipToBody: to avoid matches in the <head>
+   - (</>>=) and (</>>) which are sequencers that take two parsers like Monadic actions (hence the characters chosen) but unlike running two parsers one after the other, there may be whatever random stuff in between! 
+
+
+## TODO ## 
+
+As this is an Open Source ambitious project, there is much that is left to do which follows from the potential of this library as a result of it's inner workings
+
+- Upload to Hackage
+- Be included in the haskellPackages attribute of nixpkgs
+- grep/regex replacement (and streamEdit across multiple files, see below) 
+  - I hate ReGeX with a burning passion. No way will I ever come back to an expression and say "Oh that must match on emails!". 
+  - It would be neat to have a way to write haskell at the command line like "grepScrappy -sR "char 'a' >> some digit >> char 'b'" but this string would quickly get massive so I wonder if there's a happy medium that exists such as shortforms for the most common parsers (char, many, some, digit, string, etc) that while we would still allow for any haskell string (which typifies to a ParsecT) there would be ways to shorten expressions
+- Improve `contains` and similar functions to be able to somehow apply the 'contained' parser to inside the start and end tags
+- More Generic typing and Monads for a SiteT, HistoryT, and WebT (an accumulator of new undiscovered sites)
+   - I have a number of complicated Monads all with their own varied implementations that could be greatly reduced to a SiteT which keeps state of what branches of the Site tree have been visited or seen.
+      - With a SiteT it would easily allow for logic to gather all new links (see Scrappy.Links) upon getting a new HTML via getHTML or sibling functions, and perhaps a new sibling function like getNextHTML which gets the next untouched HTML page 
+      - SiteT extension would mean that we could create functions like `scrapeSite` which might look for all pattern matches across the site-tree. By extension this could apply to HistoryT and WebT via an incredibly simple interface. 
+   - The concept of a SiteT implies there may be use in a HistoryT (ie all Sites visited with their respective site-trees) and a WebT which is meant to represent the entire web in the sense that it continues to extend and is not constrained to past history.
+   - Hopefully this gives intriguing ideas to why scrappy-nlp might be so powerful
+- Concurrency with streamEdits 
+   - This functionality will help both for making it easier+quicker to perform concurrency when scraping (which is actually quite easy for different pages due to forkIO and standard library functions) but also makes a scrappy-DOM (see below) much easier to imagine as a robust web framework (imagine how long 10+ prerender-like scrapers would take or rather 10 passthroughs). I see this as the biggest blocker to a 1st version of scrappy-DOM (which wouldn't yet have FRP or GHCJS functionality.. you could still write raw JavaScript in V1 though) 
+   - Extending this idea, lazy-js (see below) is effectively a streamEdit performer and so this logic would also provide incredible speed to this 'category' of the DOM as well. 
+- Break up into scrappy-core and scrappy-requests
+   - This is so that scrappy-core can be used in frontend apps that are built using GHCJS. GHCJS purposely doesn't build networking packages. 
+- Fork a streamEdit package
+   - A lot of streamEdit packages are exceptionally complex while library functions like Data.Text leave much to be desired. scrappy-streamEdit would be a perfect medium
+- Fork a scrappy-staleLink (or better name) package 
+   - For use with [Obelisk](https://github.com/obsidiansystems/obelisk) the static directory which will provide a list of static assets which are no longer in use and might be good to delete
+- Fork a scrappy-templates package
+   - This is in the works currently for templating files/strings with variables such as large prompts for GPT-*, for example you could template a prompt for resumes that is job dependent in an ergonomic/easy-to-use way
+   - See Scrappy.Templates
+   - To reduce runtime errors from performing IO, it would be nice to have a staticFile finder like with staticWhich: a package that ensures an executable's existence *at compile time* 
+- scrappy + nlp
+   - It would be advantageous to use certain functions like a recursive scraper from pageN -> page(N+M), where M is based on a stop condition and/or the arrow a successful pattern match (see Scrappy.Run). While this can be easily done with HTML patterns, this extends and lends well to NLP analysis for the text that is contained in the structural HTML
+- scrappy-DOM
+   - I currently have a bone to pick with the `prerender` function from [reflex-dom](https://github.com/reflex-frp/reflex-dom) as it can easily fail. For example, if the browser insists on inserting a <tbody> inside a <table> tag then reflex-dom panics because the DOM is not as expected, even if the DOM area is on a completely different branch and way earlier than it. Intuitively, using streamEdit on an element with an attribute like prerenderID="some unique string" would be an incredibly dependable solution. 
+   - The blockers to this are of course that it's only worth doing if it will be an improvement to reflex-dom as a whole (or maybe we integrate with reflex-dom) and reflex-dom is truly exceptional with FRP, GHCJS bindings, and mobile-readiness 
+- scrappy-headless
+   - This is effectively a headless browser which has the ability to read and run JS in response to events. A lot of work has been done on this in the Scrappy.BuildActions module and in [lazy-js](https://github.com/augyg/lazy-js) which is a fork of this project
+   - Also need to implement httpHistory in a more robust way to make a headless browser more legit 
+- lazy-js 
+   - This is a foundational project for both scrappy-headless and scrappy-DOM which is a lazy reader and writer of JavaScript. An example use is virtualizing clicking a link to bypass any JavaScript bot detectors and/or just to follow JavaScript based events like a button which calls some JS to change window.location (like a fancy href)
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/scrappy-requests.cabal b/scrappy-requests.cabal
new file mode 100644
--- /dev/null
+++ b/scrappy-requests.cabal
@@ -0,0 +1,75 @@
+cabal-version:       2.4
+name:                scrappy-requests
+-- PVP summary:      +-+------- breaking API changes
+--                   | | +----- non-breaking API additions
+--                   | | | +--- code changes with no API change
+version:             0.1.0.0
+synopsis:            html pattern matching library and high-level interface concurrent requests lib for webscraping
+description:
+        Scrappy is meant to be a fully expressive library for all aspects of webscraping.
+        In this sense it is meant to be as undetectable as using Selenium but with a design
+        specifically for webscraping (where Selenium was never intended for webscraping nor do
+        it's maintainers seek to provide features that allow for more expressive scraping if it
+        would not help testing). The Elem.* modules provide a wide range of expressive pattern matching
+        functions while adding no more complexity in needing to learn this library over parsing.
+        .
+        In addition to expressive patterns to fit your specific patterns you hope to scrape, scrappy
+        provides helper functions for complex control flows such as running multiple different
+        parser-scrapers on respective sites based on a rotating ConcurrentStream when users have many
+        target sites that they can rotate working on to not overload a given site and thus avoid detection
+        .
+        For simpler control flows such as scraping a large number of pages on a single site, scrappy currently
+        provides functions like getHtml, which not only is a super simple interface to http requests,
+        but a persistent function that gurantees retrieval of the HTML document to be scraped
+        .
+        This package is labelled as uncurated, and so suggestions are very much welcome and this package is
+        expected to grow based on feedback. The primary focus will be on running Javascript to allow for greater
+        access to information on sites
+
+-- URL for the project homepage or repository.
+homepage:            https://github.com/Ace-Interview-Prep/scrappy
+license:             BSD-3-Clause
+license-file:        LICENSE
+author:              Galen Sprout
+maintainer:          galen.sprout@gmail.com
+bug-reports:         https://github.com/Ace-Interview-Prep/scrappy/issues
+x-curated:           uncurated-seeking-adoption
+stability:           Experimental
+category:            Webscraping
+build-type:          Simple
+extra-source-files:  README.MD
+source-repository head
+  type: git                                
+  location: https://github.com/Ace-Interview-Prep/scrappy-requests                  
+                     
+library
+  exposed-modules:    Scrappy.Requests.BuildActions
+                    , Scrappy.Requests.Requests
+                    , Scrappy.Requests.Types
+                    -- Needs a lot of work, is more like an idea rn
+                    -- , Concurrencies
+                    , Scrappy.Requests.Proxies
+                    --, Scrappy.JS
+
+  build-depends: aeson >= 2.2.3 && < 2.3
+               , base >= 4.20.2 && < 4.21
+               , bytestring >= 0.12.2 && < 0.13
+               , containers >= 0.7 && < 0.8
+               , directory >= 1.3.8 && < 1.4
+               , exceptions >= 0.10.9 && < 0.11
+               , http-client >= 0.7.19 && < 0.8
+               , http-client-tls >= 0.3.6 && < 0.4
+               , http-types >= 0.12.4 && < 0.13
+               , lens >= 5.3.6 && < 5.4
+               , modern-uri >= 0.3.6 && < 0.4
+               , mtl >= 2.3.1 && < 2.4
+               , network-uri >= 2.6.4 && < 2.7
+               , parsec >= 3.1.18 && < 3.2
+               , parser-combinators >= 1.3.1 && < 1.4
+               , scrappy-core >= 0.1.0 && < 0.2
+               , text >= 2.1.3 && < 2.2
+               , time >= 1.12.2 && < 1.13
+               , transformers >= 0.6.1 && < 0.7
+                         
+  hs-source-dirs:      src
+  default-language:    Haskell2010
diff --git a/src/Scrappy/Requests/BuildActions.hs b/src/Scrappy/Requests/BuildActions.hs
new file mode 100644
--- /dev/null
+++ b/src/Scrappy/Requests/BuildActions.hs
@@ -0,0 +1,1676 @@
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE RankNTypes #-}
+
+module Scrappy.Requests.BuildActions where
+
+--import Scrappy.Requests 
+import Scrappy.Elem.SimpleElemParser (elemParser)
+-- import Elem.ElemHeadParse 
+import Scrappy.Elem.Types (TreeHTML, Elem, Elem'(..), ElemHead, ElementRep, Attrs, ShowHTML, innerText', elTag, attrs, UrlPagination(..), matches', showH)
+import Scrappy.Elem.ElemHeadParse (hrefParser', hrefParser, attrsParser, parseOpeningTag, attrsMatch')
+-- import Links (Link, Option, Namespace, UrlPagination(..), maybeUsefulUrl)
+
+import Scrappy.Links (maybeUsefulUrl, Url, BaseUrl, Link(..) )
+import Scrappy.Find (findNaive, findSomeHTMLNaive)
+import Scrappy.Scrape
+import Scrappy.Requests.Types (CookieManager)
+
+import Network.HTTP.Client (Request, queryString, method, parseRequest)
+import Network.HTTP.Types.Method (Method, methodPost, methodGet)
+--import Control.Monad.Catch (MonadThrow)
+import Control.Monad (when)
+import Text.Parsec (ParsecT, ParseError, Stream, many, parse, string, (<|>), parserZero, try)
+import Text.Parsec.Error (Message (Message))
+import Data.Bifunctor (bimap)
+import Data.Either (fromRight)
+import Data.Text (Text, pack, unpack)
+import Data.Text.Encoding (encodeUtf8)
+import Data.Map as Map (Map, insert, adjust, findWithDefault, toList, fromList, lookup, union, empty, insertWith, keys)
+import Data.Maybe (fromMaybe, fromJust, catMaybes)
+import qualified Text.URI as URI  
+import Data.Char (digitToInt, toLower)
+import Data.List (isPrefixOf)
+import Control.Monad.IO.Class
+
+
+
+-- | This process for processing forms to URLs is done by creating 4 different flows
+
+-- | 1. 1 =: 1 ; single valid value for the eventual key ;; typically for verification purposes
+-- | 2. 1 =: { Set of Strings } ; we have some amount of Text inputs which allow arbitrary input ;;
+--    --> we use this to skew search results to our best efforts through info on domain/keywords
+-- | 3 -- A) Select-like Elements
+-- |   -- B) Radio Elements
+
+-- | 3A & 3B result in same type eventually -> Map (Namespace/Key) [Option]
+    --optimal solution begins generating "stream" of urls on new instance of (2) 
+
+-- | In our business logic, it revolves around 2. ; we have maybe no way of knowing for sure which
+-- | textinput is which and how they interrelate
+-- |    -> (eg. CASE1: 1st is paper title, 2nd is author\
+-- |            CASE2: Only 1 text input for any)
+
+-- | We assume 1st is most likely but if it fails or gives unusual responses then we go to next
+-- | But for lack of free development time we are hoping this just works the first time and doesn't
+-- | need a ton of attention/error handling
+
+--for interacting with the web page solely through HTML
+
+-- When run, the most basic case will be chosen first 
+data FilledForm = FilledForm { actionUrl :: Url -- | from action attribute
+                             , reqMethod :: Method
+                             , searchTerm :: Term 
+                             -- , actnAttr :: Action
+                             , textInputOpts :: [TInputOpt]
+                             , qStringVariants :: [QueryString] --  List of all possible queries given the parsed form. 
+                             }
+
+data EditableForm = EditableForm { _actionUrl :: Url
+                                 , rMethod :: Method
+                                 , params :: Map Namespace Option
+                                 } deriving (Eq, Show)
+
+-- data InputElem = Radio Namespace Option | SelectElem (Namespace, [Option]) | Basic Namespace (Maybe Option)
+data ParsedForm = ParsedForm Action Method [InputElem] deriving Show 
+
+-- | Should make a record type for signins with an instance of Default
+
+
+
+type QueryString = [(Namespace, Option)] 
+-- buildSearchUrlSubsets (mkSubsetVars variable radio) 
+
+
+-- | This may introduce a small need for lenses 
+mkEditableForm :: ParsedForm -> BaseUrl -> EditableForm
+mkEditableForm (ParsedForm act meth inpEls) (Link baseUrl) =
+  EditableForm (baseUrl <> "/" <> (unpack act)) meth map 
+  where
+    map = simplify $ mkQParams "" inpEls
+    simplify :: ([QueryString], [QueryString]) -> Map Namespace Option
+    -- simplify = \(a,b) -> fromList $ zip a b
+    simplify (a,b) = fromList $ head a <> head b 
+
+-- head of each listOfQueryStrings then concat them then toMap 
+
+-- mkQParams :: String -> [InputElem] -> ([TInputOpt], [QueryString]) 
+-- mkQParams searchTerm inputs = mkFormInputs searchTerm $ sepElems' inputs mempty 
+
+    
+-- toKeyVal :: [InputElem] -> QueryString
+-- toKeyVal = \case
+--   -- we need to filter 
+--   Radio n o
+
+-- renderEditableForm :: EditableForm -> Url
+-- renderEditableForm form = 
+
+-- | Unless we want to use 
+-- submitEditableForm :: EditableForm -> Html
+
+
+-- hypothesis: fillForm with searchTerm == ""
+
+
+-- not actually sure if i use this 
+fillForm :: ParsedForm -> Url -> String -> FilledForm
+fillForm (ParsedForm act'' meth formInputs) baseUrl searchTerm =
+  let
+    act = unpack act''
+    act' = if isPrefixOf baseUrl act then act
+           else
+             if isPrefixOf "/" act then baseUrl <> act
+             else baseUrl <> "/" <> act
+    (tInputs, subsets) = mkQParams searchTerm formInputs 
+  in
+    FilledForm act' meth searchTerm tInputs subsets
+
+-- | Lazily build FilledForm so that the full list of possible querystrings is not evaluated
+mkFilledForm :: Url -> String -> Elem' String -> Either FormError FilledForm
+mkFilledForm baseUrl searchTerm element = case elTag element of
+  "form" ->
+    case parse formElem "" (innerText' element) of
+      Right (ParsedForm act meth formInputs) ->
+        let
+          (tInputs, subsets) = mkQParams searchTerm formInputs 
+        in
+          return $ FilledForm (baseUrl <> "/" <> (unpack act)) meth searchTerm tInputs subsets
+      Left err -> Left $ ParsecError err
+  _ -> Left InvalidElement
+
+
+
+mkQParams :: String -> [InputElem] -> ([TInputOpt], [QueryString]) 
+mkQParams searchTerm inputs = mkFormInputs searchTerm $ sepElems' inputs mempty 
+
+
+
+-- | (Radio | Var | Basic | TInput)
+mkFormInputs :: String -> SepdStruct -> ([TInputOpt], [QueryString])
+mkFormInputs searchTerm (radio, var, basic, tInput) = 
+  let
+    radio' = radiosToMap radio
+    variable' = fromList var
+    -- textInput' = ( fmap (pack . (fromMaybe "") . (Map.lookup "name") . attrs) tInput
+                 -- , fmap (pack . (findWithDefault "" "value") . attrs) tInput)
+
+    textInput' = (tInput, replicate (length tInput) "")
+    textInputOpts' = fmap (basic <>) (genTInputOpts' (pack searchTerm) textInput') 
+    subPaths' = buildSearchUrlSubsets (union variable' radio')
+    subPaths'' = case length (take 1 subPaths') == 1 of
+      True -> subPaths'
+      False -> mempty : mempty 
+ in (textInputOpts', subPaths'')
+
+
+--temp
+type SelectElem = Elem'
+-- I could use datakinds to promote "select"
+
+
+
+-- | Name and Namespace are really same shit; might just converge
+-- | Refer to literally "name" attribute
+type Namespace = Text
+
+-- | This is an operationally focused type where
+-- | a certain namespace is found to have n num of Options
+type Option = Text 
+
+
+
+data QParams = Opt (Map Namespace [Option]) | SimpleKV (Text, Text)
+
+
+data Signin = Signin { user :: String
+                     , pass :: String
+                     , signinLink :: Url
+                     }
+
+executeSignin :: CookieManager -> Signin -> IO CookieManager
+executeSignin = undefined
+
+handleMKNewManagerWithChangeCookie :: CookieManager -> Signin -> IO CookieManager
+handleMKNewManagerWithChangeCookie = undefined
+
+
+
+-- pageKey=param
+
+
+
+
+
+
+--PLACEHOLDER
+type ReqBody = String
+
+
+
+
+-- | I believe this could instead compose Name/Namespace
+-- | OR!! Is the [String] the list of Options? 
+type FormOptionRadio = Map String [String] -- ?
+type FormOptionRadio' = Map Namespace [Option]
+
+
+-- Note: Upon further research, it would be useful to generalize to FormOption which reps
+-- a well formed input to a URL generator
+  -- the only difference for type="radio" is how we get this info
+
+  -- radio:
+
+         -- elem + elem + << .. >> + elem + << .. >> + elem
+
+  -- select
+
+         -- InContext $ (elem + elem + elem + elem)
+
+
+  -- but both eval to a Query Param with options
+
+  -- We could even have:
+                      
+
+
+getContainedUrls :: Elem' a -> Maybe [String]
+getContainedUrls e = findSomeHTMLNaive hrefParser (innerText' e)
+
+
+
+
+-------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------
+-----Above is outside of research websites domain and below is actions on resDB's------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
+
+inputTypesCondensed = []
+
+data FormRes = FormLinks [Text]
+
+-- type Hrefs = Link
+-- data PageLinker = PL' URL [FormRes] [Hrefs]
+-- |since it can have multiple forms
+-- | This is more for my understanding of the bigger picture of links management
+  -- if say:
+  --  -> we found ALL forms and created ALL links
+  -- but this would be full of trash ofc
+
+-- 2 Options
+-- 1) get next page -> do ...
+--  1.5) pull from page >>cond=> get x page -> do ...
+-- 2) pull from page -> pdf
+
+-- 3) Error handling
+
+-- | A key goal of the link management system is to allow for precedence ; ie we've found browsing
+-- | page but prefer search page
+   -- therefore: we continue to look for hrefs in such a case until we've exhausted the basic site
+   -- tree
+type HrefsOfPage = [Text]
+
+data HrefsSite = HrefsSite [HrefsOfPage]
+
+type URL = Text
+data PageLinker' = PL URL [FormRes] [HrefsSite]
+
+
+-- runParserOnHTML :: ToHTML a => a -> [HtmlGenParser a]
+-- -- where goal would just be to take a specific collection of patterns then grab all in one go
+-- -- * this would neeeeed arrows due to garbage collection and size of said garbage
+
+
+
+
+
+finish :: [String] -> [String] -> String
+finish [] _ = ""
+finish (x:xs) (y:ys) = "&" <> x <> "=" <> y <> finish xs ys
+
+finish' :: ([String], [String]) -> Int -> String -> String
+finish' (paramA:paramAs, paramB:paramBs) idx term = case idx of
+  -- SO we are at the right index if 0 
+  0 -> "&" <> paramA <> "=" <> term <> finish paramAs paramBs
+  _ -> "&" <> paramA <> "=" <> paramB <> finish' (paramAs, paramBs) (idx-1) term 
+
+
+
+
+finish'' :: [Text] -> [Text] -> QueryString
+finish'' [] _ = []
+finish'' (x:xs) (y:ys) = (x, y) : finish'' xs ys 
+  --"&" <> x <> "=" <> y <> finish xs ys
+
+finish''' :: ([Text], [Text]) -> Int -> Text -> QueryString
+finish''' (paramA:paramAs, paramB:paramBs) idx term = case idx of
+  0 -> (paramA, term) : finish'' paramAs paramBs 
+    -- "&" <> paramA <> "=" <> term <> finish'' paramAs paramBs
+  _ -> (paramA, paramB) : finish''' (paramAs, paramBs) (idx - 1) term
+    -- "&" <> paramA <> "=" <> paramB <> finish''' (paramAs, paramBs) (idx-1) term 
+
+
+
+-- | Basically just calls finish' with starting state 
+genTInputOpts' :: Text -> ([Text], [Text]) -> [QueryString]
+genTInputOpts' searchTerm params =
+  if (length $ snd params) /= (length $ fst params) 
+  then
+    undefined
+  else
+    reverse $ go searchTerm start params --(start, params) 
+  where
+    start = (length . fst $ params) - 1
+    go :: Text -> Int -> ([Text], [Text]) -> [QueryString]
+    go term idx params = if idx == -1 then [] else finish''' params idx term : go term (idx-1) params 
+
+
+
+-- | Basically just calls finish' with starting state 
+genSerchStrm :: String -> ([String], [String]) -> [Text]
+genSerchStrm searchTerm params =
+  if (length $ snd params) /= (length $ fst params) 
+  then
+    undefined
+  else
+    reverse $ fmap (pack ) $ go searchTerm start params --(start, params) 
+  where
+    start = (length . fst $ params) - 1
+    go :: String -> Int -> ([String], [String]) -> [String]
+    go term idx params = if idx == -1 then [] else finish' params idx term : go term (idx-1) params 
+
+    -- 1 use of idx sets the next eval'd string , the other subtracts until its at that piece and
+    -- sees 0 thus evaluating the logical placement 
+    
+    
+    -- go _ _ ([],_) _ = []
+    -- -- go term 0 (paramA:paramAs, paramB:paramBs) (stateIdx, state1) =
+    -- --   --in this case, idx will always be 0
+    -- --   (paramA <> "=" <> term <> "&" <> finish paramAs paramBs) : go term (stateIdx+1) state1 (stateIdx,state1)
+           
+    -- go term idx params = 
+      
+
+      -- Seems like I need a go-like function which is forced to return Text/String not [Text]
+       -- would need idx, params, term
+       -- would literally be iter1 <> iter2 
+
+
+    -- so if they havent hit pattern: idx==0 yet but no more left to pull and create then the
+    -- idx must exceed the length of the list 
+
+allElems :: [String]
+allElems = ["this is a placeholder for describing all html tags as a type system"]
+
+-- case 1
+  
+-- 84 : input
+-- 7 : Select
+-- 8 : button
+-- else 0 
+
+-- case 2
+  
+-- 83 : select + input 
+
+
+-- | input has attr: type="" which determines value type for form url
+-- | Attrs that I care about really are refs@( name || id ) , (Maybe) value, type,
+inputElems :: Maybe [String] 
+inputElems = Just [ "input"
+                  , "textarea"
+                  , "button"
+                  , "meter"
+                  , "progress"
+                  ]
+
+-- Another idea is a type family for Elem tags that allows for certain functions to specify
+-- if they only work with a subset of tags ; if it works with all : it specifies the type family
+-- as the input arg
+
+inputTypes :: [String]
+inputTypes = ["button", "checkbox", "color", "date", "datetime-local", "email", "file", "hidden", "image", "month", "number", "password", "radio", "range", "reset", "search", "submit", "tel", "text", "week", "time", "url"]
+
+
+    -- <input type="button">
+    -- <input type="checkbox">
+    -- <input type="color">
+    -- <input type="date">
+    -- <input type="datetime-local">
+    -- <input type="email">
+    -- <input type="file">
+    -- <input type="hidden">
+    -- <input type="image">
+    -- <input type="month">
+    -- <input type="number">
+    -- <input type="password">
+    -- <input type="radio">
+    -- <input type="range">
+    -- <input type="reset">
+    -- <input type="search"> --> Is just a text box
+    -- <input type="submit">
+    -- <input type="tel">
+    -- <input type="text">
+    -- <input type="time">
+    -- <input type="url">
+    -- <input type="week">
+             --src: https://www.w3schools.com/html/html_form_input_types.asp
+
+  -- How are buttons handled?
+
+  -- How should we handle cases like file? Should we specify value = Nothing?
+
+-- | Seems sepElems is not yet perfected for the whole scope of HTML Possibilities but
+-- | All functions that pull from (,,,) / 4[]
+
+
+-- | Could we just use parseElemHead here?
+  -- probably gonna be waaaaay more efficient with self-closing tags and I dont think there's
+  -- any relevance of the (maybe innerText)
+-- | && shouldnt this specify certain attrs? 145
+
+-- both Option and Value ~ Text
+data InputElem = Radio Namespace Option
+               | SelectElem (Namespace, [Option])
+               | Basic Namespace (Maybe Option)
+               deriving (Show, Eq)
+                                                              -- Maybe distinguishes between basic
+-- | SO:
+
+
+
+
+
+  -- Radio case is also "input" elem tag
+
+-- (radio, variable, (basic, tInput))
+
+-- structure based on filtering steps based on Constructors
+
+-- - Instead of searchForm as arg, will be filtered, parsed form including sorted input elems 
+
+
+instance ShowHTML InputElem where
+  showH = show -- TEMPORARY
+
+
+-- data ParsedForm = ParsedForm Action Method [InputElem] deriving Show 
+
+
+-- f :: ParsedForm -> FilledForm
+
+
+-- basic, textInput, variable, radio
+     ------                       NOT READY               READY AS IS
+     
+-- | (Radio | Var | Basic | TInput)
+type SepdStruct = ([(Namespace, Option)], [(Namespace, [Option])], [(Namespace, Option)], [Namespace])
+
+
+
+sepElems' :: [InputElem] -> SepdStruct -> SepdStruct
+sepElems' [] s = s
+sepElems' (elem:elems) (a,b,c,d) =(case elem of
+  Radio nom opt -> sepElems' elems ((nom, opt) : a, b, c, d)
+  SelectElem selEl -> sepElems' elems (a, selEl : b, c, d)
+  Basic namesp (Just opt) -> sepElems' elems (a, b, (namesp, opt) : c, d) 
+  Basic namesp (Nothing) -> sepElems' elems (a, b, c, namesp : d))
+
+
+  -- elems = ( filter fBasic elems
+  --                 , filter fTextInp elems
+  --                 , filter fVar elems
+  --                 , filter fRadio elems
+  --                 )
+  -- where
+  --   fBasic e =
+  --     (elTag e == "input")
+  --     && (let typ = fromJust $ Map.lookup "type" (attrs e) in not $ elem typ ["text", "radio"])
+
+  --   fTextInp e = ( elTag e == "textarea" )
+  --                || (elTag e == "input" && (fromJust (Map.lookup "type" (attrs e)) == "text"))
+
+  --   fVar e = elem (elTag e) ["select", "datalist"]
+
+  --   fRadio e = elTag e == "input" && (fromJust (Map.lookup "type" (attrs e)) == "radio")
+     
+
+-- ...
+-- any ->
+-- fmap (any,) (getValue any)
+--  case getValue any of
+--    Just a -> (any, a)
+--    Nothing -> Nothing
+--     OR
+--     case type' of
+--       -- so back to the starting calc, just not handled specially or dynamically ; we do the bare minimum
+--       -- We throw out if we can 
+
+
+instance ShowHTML a => ShowHTML (Maybe a) where
+  showH (Just a) = showH a
+  showH Nothing = "" 
+
+invalidSearchElems :: [Maybe InputElem] -> ParsecT s u m [InputElem]  
+invalidSearchElems matches = 
+  if (length $ filter (==Nothing) matches) == 0
+  then return $ catMaybes matches
+  else parserZero
+
+ -- length (matches' e) < 3
+
+-- -- | Scape pattern that matches on search forms
+-- -- | is like formElem but forces find 
+-- searchForm :: Stream s m Char => ParsecT s u m (Elem' String)
+-- searchForm = do
+--   let 
+--     f = (try $ string "search") <|> (try $ string "Search")
+--   e <- elemParser (Just ["form"]) (Just $ f) []
+--   if length (matches' e) < 3
+--     then parserZero
+--     else return e
+
+-- | Like formElem except that it also checks if the form is for searching, via a dumb manner
+searchForm :: Stream s m Char => ParsecT s u m ParsedForm
+searchForm = do
+  Elem' _ as matches innerT <- elemParser (Just ["form"]) (Just inputElem) []
+  let
+    count = length $ fromMaybe [] $ runScraperOnHtml ((try $ string "Search") <|> string "search") innerT
+    getAction = pack . fromJust . (Map.lookup "action")
+    getMethod as = case fromJust ((Map.lookup "method") as) of
+                  "get" -> methodGet
+                  "post" -> methodPost
+
+  if count < (min count (length matches))
+    then parserZero
+    else return $ ParsedForm (getAction as) (getMethod as) (catMaybes matches)
+  
+
+-- | Scape pattern that matches on search forms as well as extracting the action and method attributes  
+formElem :: Stream s m Char => ParsecT s u m ParsedForm
+formElem = do
+  Elem' _ as matches innerT <- elemParser (Just ["form"]) (Just inputElem) []
+  return $ ParsedForm (getAction as) (getMethod as) (catMaybes matches) 
+  where 
+    getAction = pack . fromJust . (Map.lookup "action")
+    getMethod as = case fmap toLower $ fromJust ((Map.lookup "method") as) of
+                  "get" -> methodGet
+                  "post" -> methodPost
+  
+  -- if count < (min count (length matches))
+  --   then parserZero
+  --   else return $ ParsedForm (getAction as) (getMethod as) matchesSafe
+
+    
+-- | Scrape pattern for <input> element
+inputElem :: Stream s m Char => ParsecT s u m (Maybe InputElem)
+inputElem = (try radioBasic') <|> (fmap Just selectEl)
+
+-- -- checks el tag then returns either radio or 
+-- radioBasic :: Stream s m Char => ParsecT s u m InputElem
+-- radioBasic = do
+--   (e, attrs) <- parseOpeningTag (Just ["input"]) [] 
+--   if (fromMaybe "" $ Map.lookup "type" attrs) == "radio"
+--     then return $ Radio (pack . fromJust $ Map.lookup "name" attrs) (pack . fromJust $ Map.lookup "value" attrs)
+--     else return $ Basic (pack . fromJust $ Map.lookup "name" attrs) (fmap pack $ Map.lookup "value" attrs)
+
+
+
+-- checks el tag then returns either radio or
+-- | parserZero means we dont care, Nothing means this form is invalid
+radioBasic' :: (Stream s m Char) => ParsecT s u m (Maybe InputElem)
+radioBasic' = do
+  (e, attrs) <- parseOpeningTag (Just ["input", "textarea"]) []
+  let
+    type' = fromJust $ Map.lookup "type" attrs
+  case e of
+    "textarea" ->
+      return . Just $ Basic (pack . fromJust $ Map.lookup "name" attrs) (fmap pack $ Map.lookup "value" attrs)
+    "input" -> processInputEl attrs 
+    _ -> undefined 
+            
+                -- case type' of
+                -- "date", "datetime", "MONTH"+"week", "number", "range",, "time" -> doSomething
+                -- "date" -> parserZero
+                -- "range" -> parserZero -- | speciallyHandleRange
+                -- "time" -> parserZero
+                -- (SomethingImportant ) -> ""
+                -- _ -> parserZero 
+        
+        --WEIIRDD
+        -- Date | Number ( Range ) | Search | Time
+             
+-- | Handles differences in implications from all input types
+-- | When an input given its type, would not impact the query url, it's discarded 
+processInputEl :: Attrs -> ParsecT s u m (Maybe InputElem)
+processInputEl attrs =
+  let
+    type' = fromJust $ Map.lookup "type" attrs
+  in
+    case type' of 
+      "radio" ->
+        return . Just $ Radio (pack . fromJust $ Map.lookup "name" attrs) (pack . fromJust $ Map.lookup "value" attrs)
+      "text" -> 
+        return . Just $ Basic (pack . fromJust $ Map.lookup "name" attrs) (fmap pack $ Map.lookup "value" attrs)
+      "hidden" ->
+        return . Just $ Basic (pack . fromJust $ Map.lookup "name" attrs) (fmap pack $ Map.lookup "value" attrs)
+      "submit" -> parserZero
+      "checkbox" ->
+        if (elem "checked" (keys attrs))
+        then return . Just $ Basic (pack . fromJust $ Map.lookup "name" attrs) (fmap pack $ Map.lookup "value" attrs)
+        else parserZero
+        -- DONT CURRRR
+      "button" -> parserZero
+      "color" -> parserZero
+      "submit" -> parserZero
+      "search" -> parserZero
+
+        -- WEIRDDDD -> 99% chance not a search form
+      "email" -> case (Map.lookup "value" attrs) of
+        -- check value, if its not set, this should throw parserZero unless definitely a search form
+        Just a -> return . Just $ Basic (pack . fromJust $ Map.lookup "name" attrs) (fmap pack $ Map.lookup "value" attrs)   -- (type', a)
+        Nothing -> return Nothing
+          
+      "file" -> return Nothing  ---SHOULD FAIL WHOLE FORM
+      "image" -> return Nothing
+      "password" -> return . Just $ Basic (pack . fromMaybe "password" $ Map.lookup "name" attrs) Nothing
+      "reset" -> return Nothing
+      "tel" -> return Nothing
+      "url"  -> return Nothing
+      "range" -> handleNumber attrs
+      "number" -> handleNumber attrs 
+      _ ->
+        case (Map.lookup "value" attrs) of
+          Just a -> return . Just $ Basic (pack . fromJust $ Map.lookup "name" attrs) (Just $ pack a)
+          Nothing -> return . Just $ Basic (pack . fromJust $ Map.lookup "name" attrs) (Just "")
+
+handleNumber :: Attrs -> ParsecT s u m (Maybe InputElem)
+handleNumber attrs = do
+  let
+    name = (pack . fromJust . (Map.lookup "name")) attrs
+    value = Map.lookup "value" attrs
+    minn = Map.lookup "min" attrs
+    maxx = Map.lookup "max" attrs
+    
+  case value of
+    Just val -> return . Just $ Basic name (Just $ pack val)
+    Nothing ->
+      case minn of
+        Just valMin -> return . Just $ Basic name (Just $ pack valMin)
+        Nothing ->
+          case maxx of
+            Just valMax -> return . Just $ Basic name (Just $ pack valMax)
+            Nothing -> parserZero
+          
+-- speciallyHandleNumber = speciallyHandleRange
+
+-- speciallyHandleRange attrs = (name, min, max)  --> then iterate some interval between the min and max 
+
+-- SelectElem Name [Option]
+
+-- | formRaw <- elemParser (Just ["form"]) (Just $ inputElem) [] 
+-- | return ParsedForm Action $ build (matches formRaw)... 
+
+-- | Matches on 
+selectEl :: Stream s m Char => ParsecT s u m InputElem
+selectEl = do
+  e <- elemParser (Just ["select", "datalist"]) (Just optionParser) []
+  return $ SelectElem ((pack . fromJust . (Map.lookup "name") . attrs $ e), (reverse $ fmap pack $ matches' e))
+  where
+    name e = pack . fromJust . (Map.lookup "name") . attrs $ e
+    opts e = fmap pack (matches' e)
+
+-- parseOpeningTag (Just ["option"])
+
+optionParser :: Stream s m Char => ParsecT s u m String
+optionParser = do
+  (_, a) <- parseOpeningTag (Just ["option"]) []
+  return $ (fromJust . (Map.lookup "value")) a
+
+
+  -- _ <- string "<option "
+  -- x <- fmap (fromRight (parserZero :: ParsecT s u m ) (attrsParser [])
+  -- return $ (fromJust . (Map.lookup "value")) x
+               
+  
+  
+
+
+-- innerFormParser' :: Stream s m Char => ParsecT s u m [InputElem]
+-- innerFormParser' = do
+--   x <- findNaive (inputElemParser inputElems Nothing [])
+--   case x of
+--     Just listOfElems -> return listOfElems
+--     Nothing -> undefined --return []
+
+innerFormParser :: Stream s m Char => ParsecT s u m [Elem' String]
+innerFormParser = do
+  x <- findNaive (elemParser inputElems Nothing [])
+  case x of
+    Just listOfElems -> return listOfElems
+    Nothing -> undefined --return []
+
+-- type SearchQuery = Text
+type TInputOpt = QueryString
+type Action = Text
+ 
+
+instance Show FilledForm where
+  show (FilledForm a b c d _) = "FilledForm " <> a <> " " <> show b <> " " <> c <> " " <> (f d) <> " SomeQStrs"
+    where f d = if length d > 20 then show (take 20 d) <> "...textInputOpts..."
+              else show d 
+                  
+-- | If I instead just pass a baseUrl to buildFormSummary then I can return as:
+
+
+-- Searches ( PerformSearch  _    _  [FilledForm]  _ )
+-- Searches [PeformSearch _    _   FilledForm _ ] 
+
+
+-- data SearchSumm = SearchSumm Term Method Action [TInputOpt] [QueryString] 
+
+
+--  -- | then for resPapScrap, ((\Form' term reqs -> PerformSearch term reqs stuff) . mkSearch)
+--  -- | Then voila we have (with appropriate auth wrapping and fmapping to all genres
+--         -- | we have the next SiteState!!
+
+-- | IMPLEMENTATION
+-- | *** MAIN of forms / search
+-- mkSearchEnum :: Url -> Elem' a -> Term -> Either FormError SearchEnum
+-- mkSearchEnum baseUrl form term = do 
+  -- (FilledForm baseUrl reqMethod term aAttr searchQueriesTextOpts searchQueriesEnumd) <- buildFormSummary baseUrl term form 
+  -- mkSearch' baseUrl reqMethod term aAttr (head searchQueriesTextOpts) searchQueriesEnumd
+
+type Term = String 
+-- data SearchEnum = SearchEnum Term [Request]
+-- mkSearch' :: Url -> Method -> Term -> Action -> QueryString -> [QueryString] -> Either FormError SearchEnum 
+-- mkSearch' baseUrl reqMethod term action textIOpt queriesEnumd = do
+--   case parseRequest $ baseUrl <> (unpack action) of
+--     Right req -> do
+--       let
+--         req2 = req { method = reqMethod }
+--       return $ SearchEnum term
+--         $ fmap (\query -> req2 { queryString = encodeUtf8 $ showQString (textIOpt <> query) }) queriesEnumd 
+--     Left _ -> Left UrlError 
+  
+showQString :: [(Namespace, Option)] -> Text
+showQString xs = f (head xs) <> showQSInner (tail xs) 
+  where
+    f (n, v) = n <> "=" <> v
+    showQSInner [] = ""
+    showQSInner (y:ys) = "&" <> (fst y) <> "=" <> (snd y) <> (showQSInner ys)
+    
+
+-- -- | This function's goal is to give the full callable, valid paths that get this genre some results
+-- mkGenredSearch :: Url -> Elem' a -> Genre -> Either FormError Search -- (Genre, [SearchQuery])
+-- mkGenredSearch baseUrl formE genre = do
+--   (method, queries) <- buildFullSearchQuerys genre formE
+--   return $ Search [Request] --  method genre (fmap (baseUrl <>) queries)
+
+  -- fmap (genre,) $ (fmap . fmap) (baseUrl <>) (buildFullSearchQuerys genre formE)
+  -- fmap (Search _ genre) $ (fmap . fmap) (baseUrl <>) $ (method,queries) = buildFullSearchQuerys genre formE)
+
+  
+type SearchQuery = Query 
+type Query = Text 
+
+data FormError = InvalidElement
+               | ParsecError ParseError
+               | UrlError
+               deriving Show
+-- -- | Note that buildFormUrlEndings gives a list of different configs of text inputs for a single search term
+-- -- | as well as the in order list of selected options -> So really this function is  just a means to a long
+-- -- | list of results for a given query/search term
+
+-- -- | In future we will add fallback in the case of a very useless text box like say if we found the author input
+-- -- | and erroneously used it as (title OR anywhere) text input 
+-- buildFullSearchQuerys :: Term -> Elem' a -> Either FormError (RequestMethod, [SearchQuery])
+-- buildFullSearchQuerys genre formE = case buildFormSummary genre formE of
+--   Right (Form method actionAttr (textInput:_) subsets) ->
+--      Right $ (method, fmap ((unpack textInput <>) . unpack) subsets)
+--   Left str -> Left $ OtherError str --undefined -- Left OtherError str
+
+  -- (Form method actionAttr (textInput:_) subsets) <- buildFormSummary genre formE
+  -- return 
+
+
+
+         
+
+
+-- -- IN Respapscrap
+
+-- FormSummary -> Search
+
+-- data Search = Search RequestMethod [BaseUrl] [QueryString]
+-- data Search' = Search [Request] =<< querystring, base url and method `from` Form ...
+
+-- data S = S BaseUrl RequestMethod [Queries]
+
+
+-- formToSearch' (Form reqMethod action   = do
+
+
+                  
+-- WAIT!!!!!!!!!!!!
+
+
+
+
+
+                  -- Is it really [BaseUrl] ? or just baseUrl .... from state so: method <+> queries as Search
+
+
+
+
+
+
+-- type FormInput a = Elem' a  
+
+-- buildFormSummary' :: Url -> String -> [FormInput] -> FilledForm 
+-- buildFormSummary baseUrl searchTerm inputs =
+  -- let
+    -- (basic, textInput, variable, radio) = sepElems inputs
+    -- method e = case (fromJust $ ((Map.lookup "method") . attrs) e) of
+      -- "get" -> methodGet
+      -- "post" -> methodPost 
+    -- subPaths = searchTermSubPaths (mkSubsetVars variable radio) (mkBasicParams' basic)
+    -- textInput' = ( (pack . (fromMaybe "") . (Map.lookup "name") . attrs) <$> textInput
+                 -- , fmap (pack . (findWithDefault "" "value") . attrs) textInput)
+    -- textInputOpts = (genTInputOpts' (pack searchTerm) textInput') -- :: [String]
+  -- in FilledForm baseUrl (method formElem) searchTerm (actionAttr formElem) textInputOpts subPaths
+
+
+-- {-# DEPRECATED mkFilledForm' "Use mkFilledForm" #-}
+-- mkFilledForm' :: Url -> String -> Elem' a -> ([Elem' a], [Elem' a], [Elem' a], [Elem' a]) -> FilledForm
+-- mkFilledForm' baseUrl searchTerm formElem (basic, textInput, variable, radio) = 
+--   let
+--     method e = case (fromJust $ ((Map.lookup "method") . attrs) e) of
+--      "get" -> methodGet
+--      "post" -> methodPost
+    
+--     basic' = mkBasicParams' basic
+--     radio' = radiosToMap (fmap mkNameVal radio)
+--     variable' = mkOptMaps' variable
+--     subPaths' = buildSearchUrlSubsets (union variable' radio')
+--     textInputOpts' = fmap (basic' <>) (genTInputOpts' (pack searchTerm) textInput') 
+    
+--     -- subPaths = searchTermSubPaths (mkSubsetVars variable radio) (mkBasicParams' basic)
+--     textInput' = ( fmap (pack . (fromMaybe "") . (Map.lookup "name") . attrs) textInput
+--                  , fmap (pack . (findWithDefault "" "value") . attrs) textInput)
+    
+--     textInputOpts = (genTInputOpts' (pack searchTerm) textInput') -- :: [String]
+--  -- in return (subPaths, textInputOpts)
+--  in FilledForm (baseUrl <> "/" <> (unpack $actionAttr formElem)) (method formElem) searchTerm textInputOpts' subPaths'
+
+
+-- Elem' a -> (N, Opt) --> [(N, Opt)]
+
+
+
+-- Elem' String --> ParsedForm ( [InputElems] )                    --> FilledForm
+
+--                             ^^--> ([TInputOptsWithBasic, Subsets]) ---^^^
+
+
+-- | NOTE: formElem is a specialized
+
+findForms :: String -> Maybe [ParsedForm]
+findForms html = runScraperOnHtml formElem html
+
+-- mkForm :: Elem' a -> Either FormError ParsedForm
+-- mkForm element = 
+
+
+
+
+-- -- The interface for starting forms processing in ResPapScrap
+-- getFormInputElems :: Elem' String
+--                   -> Either FormError 
+-- getFormInputElems formElem = case elTag formElem of
+--   "form" ->
+--     case fmap sepElems' $ parse formElem "" (innerText' formElem) of
+--       Left err -> Left $ ParsecError err
+--       Right a -> return a
+--   _ -> Left InvalidElement
+
+--  This would likely be way more efficient if we parsed as TreeHTML then "trimmed" down to
+--  what we want but it could also be less efficient 
+--  would be fed from some initial parser
+-- {-# DEPRECATED buildFormSummary "replaced by mkFilledForm (new version) " #-}
+-- buildFormSummary :: Url -> String -> Elem' String -> Either FormError FilledForm
+-- buildFormSummary baseUrl searchTerm formElem = case elTag formElem of
+--   "form" -> do --Either a b is the Monad
+--     case fmap sepElems $ parse innerFormParser "" (innerText' formElem) of
+--       Left err -> Left $ ParsecError err
+--       Right (basic, textInput, variable, radio) ->
+--         return $ mkFilledForm' baseUrl searchTerm formElem (basic, textInput, variable, radio) 
+--         -- let
+--         --   method e = case (fromJust $ ((Map.lookup "method") . attrs) e) of
+--         --     "get" -> methodGet
+--         --     "post" -> methodPost 
+--         --   subPaths = searchTermSubPaths (mkSubsetVars variable radio) (mkBasicParams' basic)
+--         --   textInput' = ( (pack . (fromMaybe "") . (Map.lookup "name") . attrs) <$> textInput
+--         --                , fmap (pack . (findWithDefault "" "value") . attrs) textInput)
+--         --   textInputOpts = (genTInputOpts' (pack searchTerm) textInput') -- :: [String]
+--         -- -- in return (subPaths, textInputOpts)
+--         -- in return $ FilledForm baseUrl (method formElem) searchTerm (actionAttr formElem) textInputOpts subPaths
+--         --  at macro, can build then try Url ... case Fail -> build, try next
+--   _ -> Left InvalidElement      
+
+
+-- -- | This would likely be way more efficient if we parsed as TreeHTML then "trimmed" down to
+-- -- | what we want but it could also be less efficient 
+-- -- | would be fed from some initial parser
+-- buildFormUrlEndings :: String -> Elem' a -> Either String ([Text], [Text])
+-- buildFormUrlEndings searchTerm formElem = case elTag formElem of
+
+--   -- What about the base tag for the website that this ending will get applied to?
+--   -- ie how will we determine that?
+--     --  We can get this from the western database site
+
+--   -- Some may have query parameter of accountid=Int
+
+--   -- Would this logic work? :
+--     -- get redirected base URL
+--     -- concat this + whatever paths & params
+  
+--   "form" -> do --Either a b is the Monad
+--     case fmap sepElems (parse innerFormParser "" (innerText' formElem)) of
+--       Left err -> Left $ show err
+--       Right (basic, textInput, variable, radio) ->
+--         let
+--           -- actionAttr :: Text
+--           -- actionAttr = (pack . fromJust . (Map.lookup "action") . attrs) formElem
+--           -- basic' :: Text
+--           -- basic' = actionAttr <> (createBasicQKVPairs basic)
+--           -- vars :: Map Namespace [Option] 
+--           -- vars = fromList (mkOptMaps variable)
+--           -- radio' :: Map Namespace [Option]
+--           -- radio' = iterRadios radio empty 
+--           -- subsetVariables = union vars radio'
+--           -- subsetVars = [ basic' <> x | x <- buildSearchUrlSubsets subsetVariables]
+--           subPaths = searchTermSubPaths (mkSubsetVars variable radio) (mkBasicPart (actionAttr formElem) basic)
+--           textInput' = ( ((fromMaybe "") . (Map.lookup "name") . attrs) <$> textInput
+--                        , fmap (findWithDefault "" "value" . attrs) textInput)
+--           -- textInput'' = fmap (basic' <>) (genSerchStrm searchTerm textInput') -- :: [String]
+--           textInput'' = (genSerchStrm searchTerm textInput') -- :: [String]
+
+--           -- i think basic got repeated
+--           -- textInput'' expected length is 10
+--           -- subsetVars length is of range (0, 30000)
+--         in return (searchTermSubPaths (subPaths, textInput'')
+--         --  at macro, can build then try Url ... case Fail -> build, try next
+
+--   _ -> Left "This only has utility on form elements"
+
+
+       
+--     let searchTermParam = cycle (with = searchTerm, txtElems !! 0 ) --in fail case -> cycle to next, this logic can be performed easily anywhere
+
+--     try: mkReq searchTermParam (splitup then created elemsTotal :: [Text]) <- may write to tmp file so that we can easily perform concurrent scraping of diff websites 
+--     case fail -> newSearchTermParam ; success -> go for some amount of times 
+
+--
+
+actionAttr :: Elem' a -> Text
+actionAttr formElem = (pack . fromJust . (Map.lookup "action") . attrs) formElem
+
+-- mkBasicPart :: Text -> [Elem' a] -> Text
+-- mkBasicPart actionAttr basicEs = actionAttr <> (createBasicQKVPairs basicEs)
+
+mkBasicParams' :: [Elem' a] -> QueryString -- [(Namespace, Option)]
+mkBasicParams' = createBasicQKVPairs
+
+mkSubsetVars :: [Elem' a] -> [Elem' a] -> Map Namespace [Option]
+mkSubsetVars variable radio = union (fromList (mkOptMaps variable)) (iterRadios radio empty)
+
+searchTermSubPaths :: Map Namespace [Option] -> QueryString -> [QueryString] 
+searchTermSubPaths subsetVariables basicPath = fmap (basicPath <>) (buildSearchUrlSubsets subsetVariables)
+
+-- buildSearchUrlSubsets (mkSubsetVars variable radio) 
+
+
+
+getAttrVal :: String -> Elem' a -> String 
+getAttrVal name formElem = (fromJust . (Map.lookup name) . attrs) formElem
+
+-- | With a Map of an html Namespace and all its possible defined options, lazily create all possible search queries
+-- | for a given Search term 
+buildSearchUrlSubsets :: Map Namespace [Option] -> [QueryString]
+buildSearchUrlSubsets mappy = singlefOp' (mempty :mempty) (toList mappy) -- I believe "" is just state 
+
+-- <> of base + set pairs
+-- | Note: this url may fail
+
+-- | SHOULD I? create a list of baseUrls, where each could fail and if so, next
+-- buildBaseFormUrl baseUrl generalSearchTermToSearchForTextbox ((Elem'{..}):elems)
+  --  elem == "textarea" = genSearchTermTBox
+  -- plus when input type attribute is text 
+  --  elem == "button" = ""
+
+-- baseFormUrlVariants :: a -> [Url]
+                          --- basic || textinput || variable || Radio input-type
+
+sepElems2 elems = ( filter fBasic elems
+                  , filter fTextInp elems
+                  , filter fVar elems
+                  , filter fRadio elems
+                  )
+  where
+    fBasic e =
+      (elTag e == "input")
+      && (let typ = fromJust $ Map.lookup "type" (attrs e) in not $ elem typ ["text", "radio"])
+
+    fTextInp e = ( elTag e == "textarea" )
+                 || (elTag e == "input" && (fromJust (Map.lookup "type" (attrs e)) == "text"))
+
+    fVar e = elem (elTag e) ["select", "datalist"]
+
+    fRadio e = elTag e == "input" && (fromJust (Map.lookup "type" (attrs e)) == "radio")
+    
+
+
+
+
+
+sepElems :: [Elem' a] -> ([Elem' a], [Elem' a], [Elem' a], [Elem' a])
+sepElems elems = go elems ([], [], [], [])
+  where go [] endState = endState
+        go (elem:elems') (a,b,c,d)
+          | elTag elem == "select" || elTag elem == "datalist" = go elems' (a, b, elem : c, d)
+          | elTag elem == "textarea" = go elems' (a, elem: b, c, d)
+          | elTag elem == "input" = 
+              case Map.lookup "type" (attrs elem) of
+                Just "text" -> go elems' (a, elem : b, c, d)
+                Just "radio" -> go elems' (a, b, c, elem : d)
+                _ -> go elems' (elem : a, b, c, d)
+                -- "hidden" ^^ 
+                
+          | elTag elem == "button" = go elems (elem : a, b, c, d)
+          -- should this change if the button is of type submit?
+
+ -- sepElems' :: [ElemHead] -> ([ElemHead], [ElemHead], [ElemHead], [ElemHead])
+-- sepElems' heads = go heads ([],[],[],[])
+--   where go :: [ElemHead]
+--           -> ([ElemHead],  [ElemHead], [ElemHead], [ElemHead])
+--           -> ([ElemHead],  [ElemHead], [ElemHead], [ElemHead]) 
+--         go [] endState = endState
+--         go ((tag, attrs):elHeads) (a,b,c,d)
+--           | tag == "select" || tag == "datalist" = go elHeads (a, b, elem : c, d)
+--           | tag == "textarea" = go elHeads (a, elem: b, c, d)
+--           | tag == "input" = 
+--               case Map.lookup "type" (attrs elem) of
+--                 Just "text" -> go elHeads (a, elem : b, c, d)
+--                 Just "radio" -> go elHeads (a, b, c, elem : d)
+--                 _ -> go elHeads (elem : a, b, c, d)
+--                 -- "hidden" ^^ 
+                
+--           | tag == "button" = go elHeads (elem : a, b, c, d)
+
+  
+  -- (fromJust $ Map.lookup "name" (attrs elem)
+  -- , case parse formOptionsParser "bsSourceName" (innerHtmlFull elem) of
+  --     Left _ -> Nothing -- dont care why it failed, just that it did
+  --     Right a -> Just $ fmap pack a)
+  
+-- | above should check if : el elem == "select"
+
+
+-- f :: ParsecT s u m SelectElem
+
+
+data SelectElem' = SelectElem' Namespace [Option]
+
+mkOptMaps :: [SelectElem a] -> [(Namespace, [Option])]  --- -> Map
+mkOptMaps [] = [] 
+mkOptMaps (elem:elems) = case mkOptMapSingle elem of
+                           Just a -> a : mkOptMaps elems
+                           Nothing -> mkOptMaps elems 
+ 
+-- |for variable elems, this will be a case where we need to parse inner text again for the option elements
+
+mkOptMaps' :: [(Namespace, [Option])] -> Map Namespace [Option]
+mkOptMaps' = fromList 
+
+mkOptMaps'' :: [SelectElem a] -> Map Namespace [Option]
+mkOptMaps'' es = fromList $! catMaybes (fmap mkOptMapSingle es)
+
+-- | This likely has a far better implementation although im honestly not sure how much "overhead"
+-- | would be removed by not using parser again
+-- | Likely tho; -> best option always is 1 pass parsing
+  -- every time we call "parse" I believe its equivalent to parse str where str = strFullHtml ++ strInnerHtmlSpec
+  -- where all input is consumed and each index has N number of (->Boolean) functions as options thru <|>
+mkOptMapSingle :: SelectElem a -> Maybe (Namespace, [Option])
+mkOptMapSingle elem = --confirm is "select" then parse options ; \case (options) of Just a -> fmap pack a)
+  if elTag elem /= "select" --can expand to elemOf 
+  then Nothing
+  else 
+    case parse formOptionsParser "bsSourceName" (innerText' elem) of
+      Left _ -> Nothing -- dont care why it failed, just that it did
+      Right a -> Just $ (pack $ fromJust $ Map.lookup "id" (attrs elem), fmap pack a)
+
+
+
+
+
+
+
+--func idea:
+applyFailStream :: (a -> Bool) -> [a] -> [a]
+applyFailStream = undefined
+
+optionElemsPat :: Maybe [String]
+optionElemsPat = Just ("option":[])
+
+formOptionsParser :: Stream s m Char => ParsecT s u m [String]
+formOptionsParser = (findNaive $ elemParser optionElemsPat (Nothing :: Maybe (ParsecT s u m String)) [])
+  >>= return . (fmap (fromJust . Map.lookup "value" . attrs)) . fromJust
+
+
+-- -- this can safely assume that no inner text exists
+-- formOptionsParser :: Stream s m Char => ParsecT s u m [String]
+-- formOptionsParser = do
+--   (elems :: [Elem' String]) <- many (elemParser optionElemsPat Nothing []) -- :: (Stream s m Char, ShowHTML a) => ParsecT s u m [Elem' a]
+--   -- type Elem'
+--   -- let
+--     -- attrssToFVals :: [Map String String] -> [String]
+--     attrssToFVals [] = []
+--     attrssToFVals (attrs:attrss) = case Map.lookup "value" attrs of
+--                                        Just a -> a : attrssToFVals attrss
+--                                        Nothing -> "" : attrssToFVals attrss
+
+--   fmap attrs elem :: [Map k a]
+  
+--   return $ attrssToFVals (fmap attrs elems)
+
+--gonna run on innerHTMLFull elem --> [(Name, [Option])]
+
+   -- 1:2:3 (:) 4:5:6 IFF (:)[] 
+
+-- | I have to use (<>) to deal with the fact that the end of the list would look the exact same as an "inner end"
+-- | but this doesnt mean that I will have infinite listing ending up with something like [[[[[[[[a]]]]]]]]
+
+-- | Although, ^ this may be more likely a problem if using cons, (:) since it creates a more complex type
+-- | which works fine at the last iteration where strings are thus being operated like so
+
+    -- string : (f x --rec--> [string])
+  
+-- | Meaning that at whateverrr depth we will be able to (<>) the [string]
+
+   -- [string] <> [string] --> [string]
+
+-- | Meaning this will work for any depth of tree
+
+-- | Should always be singleton !!! 
+toLis2' :: [(Namespace, Option)] -> Namespace -> Option -> [(Namespace, Option)] 
+toLis2' lis namesp opt = lis <> ((namesp, opt) :[]) 
+
+toStr2 :: Text -> Namespace -> Option -> Text
+toStr2 txt name value = txt <> "&" <> name <> "=" <> value 
+
+-- | singlefOp can be thought of as a state carrying function which evaluates to N number of
+-- | functions which evaluate to a list of the expression of toStr2 
+
+singlefOp' :: [(Namespace, Option)] -> [(Namespace, [Option])] -> [[(Namespace, Option)]] 
+singlefOp' lis [] = []
+singlefOp' lis (("", _):_) = undefined
+singlefOp' lis ((namespace, []):[]) = [] -- allows for => x : singlefOp
+singlefOp' lis ((namespace, []):levels) = singlefOp' lis levels --omitting potential path of namespace=""
+singlefOp' lis ((namespace, x:[]):levels) = singlefOp' (toLis2' lis namespace x) levels
+singlefOp' lis ((namespace, xs):[]) = [ toLis2' lis namespace x | x <- xs ]
+-- Main: 
+singlefOp' lis ((namespace, (x:xs)):levels) = -- Divide ->
+  singlefOp' (toLis2' lis namespace x) levels -- Branch 1 
+  <> singlefOp' lis ((namespace, xs):levels) -- Branch 2
+
+
+-- | Is essentially the core of buildFormUrlEndings; creates all url search queries
+singlefOp :: Text -> [(Namespace, [Option])] -> [Text]
+-- Final Cases:
+singlefOp str [] = []
+singlefOp str (("", _):_) = undefined
+singlefOp str ((namespace, []):[]) = [] -- allows for => x : singlefOp
+singlefOp str ((namespace, []):levels) = singlefOp str levels --omitting potential path of namespace=""
+singlefOp str ((namespace, x:[]):levels) = singlefOp (toStr2 str namespace x) levels
+singlefOp str ((namespace, xs):[]) = [ toStr2 str namespace x | x <- xs ]
+-- Main: 
+singlefOp str ((namespace, (x:xs)):levels) = -- Divide ->
+  singlefOp (toStr2 str namespace x) levels -- Branch 1 
+  <> singlefOp str ((namespace, xs):levels) -- Branch 2
+
+
+
+
+  
+-- singlefOp s xs = [pack $ show (take 5 xs)] 
+
+
+
+-- singlefOp :: Text -> [(Namespace, [Option])] -> [Text]
+-- singlefOp str [] = [] 
+-- singlefOp str ((namespace, []):[]) = [] -- allows for => x : singlefOp
+-- singlefOp str ((namespace, xs):[]) = [ toStr2 str namespace x | x <- xs ]
+-- singlefOp str ((namespace, x:[]):levels) = singlefOp (toStr2 str namespace x) levels
+-- singlefOp str ((namespace, (x:xs)):levels) =
+--   singlefOp (toStr2 str namespace x) levels <> singlefOp str ((namespace, xs):levels)
+-- singlefOp 
+--                                       --still same namespace but next iteration of namespace
+--                                       --with new value
+-- -- | This ^ creates actual strings then recurses with (:)
+-- | Creates specifically last branch ^^
+-- levels to go (below) no levels to go (up)
+
+-- | So maybe f takes a state parameter that is determined by the higher-level-set value
+
+
+-- Could also be that we'll need slightly different unpacking for going across vs in
+  --and that one could end up as an mconcat / <>
+
+-- both in || to side deal with leftover params
+  
+
+-- | SO add the results of f :: ItemOfCurrentList -> [ItemOCL] -> [String]
+  
+-- | for basic
+createBasicQKVPair :: Elem' a -> (Namespace, Option) 
+createBasicQKVPair elem =
+  (  (pack (fromJust (Map.lookup "name" (attrs elem)))) , (pack (findWithDefault "" "value" (attrs elem))) )
+                          -- <> "=" <> 
+                          
+
+createBasicQKVPairs :: [Elem' a] -> QueryString -- [(Namespace, Option)] 
+createBasicQKVPairs [] = []
+createBasicQKVPairs (elem:elems) = createBasicQKVPair elem : createBasicQKVPairs elems
+
+-- | NOTE: this below function sucks createQKVP...Term
+-- | Instead i will do a cycle pattern that controls it 
+                    
+-- |case request of
+-- |  Fail -> move first query param to end of list/string and move the search term
+-- |  Success -> well then do ya thang shawty
+
+
+
+-- | NOT REFERENCED
+createQKVPairWithTerm :: Text -> [Elem' a] -> [Text]
+createQKVPairWithTerm _ [] = []
+createQKVPairWithTerm term (next:tInputElems) =
+  (pack . fromJust) (Map.lookup "name" (attrs next)) <> "=" <> term : createQKVPairWithTerm term tInputElems
+--   :
+
+
+-- I : Attrs ~ Map Attr{especially "name", "value"} AttrValue
+
+-- O : [(Name, [Options]), (Name2, [Options2]) ... ]
+
+-- radiosToMap :: [Elem' a] -> Map Namespace [Option]
+-- radiosToMap (e:es) = singleton _name _value <> radiosToMap
+  -- where
+    -- _name <+> _value >>= Namespace Option
+
+
+type NamespacePair = (Namespace, Option)
+
+mkNameVal :: Elem' a -> NamespacePair
+mkNameVal = (\a -> (pack . fromJust $ Map.lookup "name" a, pack . fromJust $ Map.lookup "value" a)) . attrs
+
+radiosToMap :: [NamespacePair] -> Map Namespace [Option]
+radiosToMap [] = mempty
+radiosToMap ((name, value):nps) = insertWith (<>) name (value:[]) (radiosToMap nps)
+
+
+
+-- let
+--   func new old = new : old
+
+  
+  
+-- do :: Maybe a 
+--   case Map.lookup "name" a of
+--     Just name -> adjust name (value:) (radiosToMap es)
+--     Nothing -> singleton name value <> radiosToMap
+  
+
+--     . (\a -> (Map.lookup "name" a, Map.lookup "value")) . attrs
+
+--     -- goal is to add name if name is new and
+
+    
+                           -- Map Attr Value
+iterRadios :: [Elem' a] -> Map Namespace [Option] -> Map Namespace [Option]
+iterRadios [] finalOptsMap = finalOptsMap 
+iterRadios (elem:elems) startingOptsMap =
+  iterRadios elems (lookupOrInsertName (attrs elem) startingOptsMap)   
+
+
+-- can even just pass empty func :: Map k a as starting optsMap 
+lookupOrInsertName :: Attrs -> Map Namespace [Option] -> Map Namespace [Option] 
+lookupOrInsertName attrsMap optsMap =
+  case Map.lookup (pack $ fromMaybe "" (Map.lookup "name" attrsMap)) optsMap of
+    Just list ->
+      adjust ((pack (fromMaybe "" (Map.lookup "value" attrsMap))) :) (pack (fromMaybe "" (Map.lookup "name" attrsMap))) optsMap
+       
+    Nothing ->
+      insert (pack (fromMaybe "" (Map.lookup "name" attrsMap))) [] optsMap
+  -- where
+  --   k = 
+
+-- | NOT REFERENCED
+-- groupRadio :: [Elem'] -> Map Name [Option]
+-- groupRadio (elem:elems) = go elems []
+--   where go [] listOut = listOut 
+--         go (elem: elems) listOut = go' elem (opt:listOut)
+
+--         go' elem (opt:listOut) = case (lookup "name" (attrs elem)) listOut of
+--                 True ->
+--                   fmap (\(a,b) (a',b') -> if a == a'
+--                                           then (a, b' <> b)
+--                                           else id) getTheValue (attrs elem)  -- :: Map String String
+--                 False -> --add param/name to listOut
+--                   ((lookup "name" (attrs elem), [lookup "value" (attrs elem)]) : listOut)
+
+
+
+-- findListingElems 
+
+
+-- listLikeElems = ["blockquote", "div", "dl" -> "dt" , "li", "p", "section", "article"
+                -- , "listing", "col","colgroup","table" || "tbody" || "td" ||| "tr", "a", "span", "div",                ,"small"
+
+
+-- likelyListElems = ["li", "tr", "dt", "div", "section", "article", "listing", "a", "p", ("td", "col"), "small"]
+
+
+
+-- | Just an arbitrarily set number of elements
+-- | Could also see if select-like elems count == 0
+searchIsBigorSmall :: [Elem' a] -> Bool
+searchIsBigorSmall = undefined
+
+
+-- | Just use substring
+-- | Will it be this page tho? Or a sort of weird response
+
+
+-- | Should use findSomeSameEl probably
+findPagination :: ParsecT s u m (TreeHTML a)
+findPagination = undefined
+
+
+structuredBrowsingLinksExist :: ParsecT s u m (TreeHTML a)
+structuredBrowsingLinksExist = undefined
+-- perhaps we should have some recursive func that scopes in and tries to find the same elem+attrs
+-- for each level of nesting, to see if at any point, theres some level of repetition potentially
+-- indicating that this is a list of similar things
+
+--------------------------------------------------------------------------------------------------------------------
+-------------------Pagination-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+-- uriParser can literally just be parser from Text.URI
+
+
+
+-- 1) Look through a parsed tree for href =
+-- 2) scan text for URI.parser ; p  
+
+validHrefs :: Stream s m Char => String -> ParsecT s u m (Maybe [String])
+validHrefs baseUrl = findNaive (getValidHref baseUrl)
+
+getValidHref :: Stream s m Char => String ->  ParsecT s u m String
+getValidHref baseUrl = hrefParser' (isPrefixOf baseUrl)
+  -- where
+    -- cheapShit :: String -> String -> Bool 
+    -- cheapShit baseU str = isPrefixOf baseU str
+
+    
+      -- case parse URI.parser( ) "" str of
+      --   -- this will work tho 
+      --   Right uri -> True
+      --   Left _ -> False 
+
+    -- orCheapShit str = isPrefixOf "https://" str 
+
+  -- get all mutually exclusive <a> with href == actualUriParser | validURI 
+  
+parseDrvPagination :: Stream s m Char => String -> ParsecT s u m UrlPagination
+parseDrvPagination baseUrl = do
+  es <- paginationElements
+  -- could instead, in order to make this reliable on all sites, return a list of trups of Elem'
+  -- then \case derivePagination -> Nothing ; try derive next 
+  case derivePagination baseUrl es of
+   Nothing -> parserZero
+   Just (UrlPagination pre post) ->
+     if isPrefixOf baseUrl pre
+     then return (UrlPagination pre post)
+     else parserZero
+
+type PaginationElems = (Elem' String, Elem' String, Elem' String)
+
+derivePagination :: Url -> PaginationElems -> Maybe UrlPagination
+derivePagination baseU (el1, el2, el3) =
+  let
+    href :: Elem' String -> Maybe String
+    href x = ((Map.lookup "href") . attrs) x
+
+    f x = case fmap (isPrefixOf baseU) x of { (Just True) -> x; _ -> Nothing }
+    -- mHrefs :: [(Url, Url, Url)]
+    xs {-a:b:c:xs-} = fromMaybe [] $ sequenceA [href el1, href el2, href el3]
+   
+    funcyAf' :: (String, String, String) -> Maybe UrlPagination
+    funcyAf' (x,y,z) = funcyAf "" x y z  
+  in
+    case xs of
+      a:b:c:xs -> 
+        tillWeGetItRight funcyAf' ((a,b,c) : commonUrlTrups (el1, el2, el3))
+      _ ->
+        tillWeGetItRight funcyAf' (commonUrlTrups (el1, el2, el3))
+
+commonUrlTrups :: PaginationElems -> [(Url, Url, Url)]
+commonUrlTrups (e1, e2, e3) = commonElHUrls (hrefElHs e1) (hrefElHs e2) (hrefElHs e3) 
+
+
+hrefElHs :: Elem' String -> [ElemHead] 
+hrefElHs e = fromMaybe [] $ runScraperOnHtml validHrefElHs (innerText' e)
+
+validHrefElHs :: Stream s m Char => ParsecT s u m ElemHead
+validHrefElHs = parseOpeningTag Nothing [("href", Nothing)]
+
+commonElHUrls :: [ElemHead] -> [ElemHead] -> [ElemHead] -> [(Url, Url, Url)]
+commonElHUrls [] _ _ = [] 
+commonElHUrls (x:xs) ys zs = 
+  let 
+    aas = findSep pred ys -- (a, as)
+    bbs = findSep pred zs -- (b, bs)
+    href = fromJust . (Map.lookup "href") . snd
+    pred = (\y -> attrsMatch' (snd x) (snd y) && ((fst x) == (fst y)))
+  in
+    case (,) <$> fst aas <*> fst bbs of
+      Just (a, b) -> (href x, href a, href b) : (commonElHUrls xs (snd aas) (snd bbs))
+      Nothing -> commonElHUrls xs ys zs 
+
+-- | Note that in use, what builds the predicate will be given in the return just not through this function 
+findSep :: (ElemHead -> Bool) -> [ElemHead] -> (Maybe ElemHead, [ElemHead])
+findSep _ [] = (Nothing, []) 
+findSep pred (x:xs) = if pred x then (Just x, xs) else consSnd x (findSep pred xs) 
+  where 
+    consSnd :: Eq a => a -> (Maybe a, [a]) -> (Maybe a, [a])
+    consSnd a (x, as) = (x, a : as) 
+
+firstJust :: (a -> Maybe b) -> [a] -> Maybe b
+firstJust = tillWeGetItRight 
+
+tillWeGetItRight :: (a -> Maybe b) -> [a] -> Maybe b
+tillWeGetItRight _ [] = Nothing -- but we got it wrooong 
+tillWeGetItRight f (x:xs) = case f x of
+                              Just a -> Just a
+                              _ -> tillWeGetItRight f xs
+
+funcyAf :: String -> String -> String -> String -> Maybe UrlPagination
+funcyAf _ [] _ _ = Nothing
+funcyAf _ _ [] _ = Nothing
+funcyAf _ _ _ [] = Nothing
+funcyAf pre (x:xs) (y:ys) (z:zs) =
+  if x == y
+  then
+    -- Pred: x y ==
+    if x == z
+    then funcyAf (pre <> (x:[])) xs ys zs -- only case that recurses
+         -- could also just reverse at end 
+    else
+      Nothing
+  else
+    if y == z
+    then Nothing
+    else 
+      if y == z
+      then Nothing
+      else
+        -- make sure of elem Num first
+        if all (flip elem  ['0'..'9']) [x,y,z]
+        then
+          if (digitToInt y - digitToInt x) - (digitToInt z - digitToInt y) == 0
+          then
+
+            case xs == ys && xs == zs of
+              True -> Just $ UrlPagination pre xs
+              False -> Nothing 
+             -- we know the index at which the page, paginates
+             -- we have 3 pieces
+             -- pre <> pgNum <> post == url
+          else Nothing 
+      
+        else
+          Nothing 
+          
+
+-- Need to stretch to handling finding many 
+-- getPgtnLks :: ElementRep e => e b -> String -> [Url]
+-- getPgtnLks elem baseUrl =
+  -- case (parse (validHrefs baseUrl) "" (innerText' elem)) of
+    -- Left _ ->
+      -- case headHref of
+        -- Just a -> a : [] 
+        -- Nothing -> []
+      -- return [] 
+
+  --   Right (Just urlList) ->
+  --     case headHref of
+  --       Just a -> a : urlList
+  --       Nothing ->  urlList 
+  -- where
+  --   headHref :: Maybe String
+  --   headHref = (Map.lookup "href" (attrs elem)) >>= maybeUsefulUrl baseUrl 
+
+
+
+-- __NEXT TO DO!!!!!!!!!!!!!____:
+
+
+-- f :: [ElemHead] -> [ElemHead] -> [ElemHead] -> Maybe [(Url, Url, Url)]
+-- f (x:xs) = f' x ys
+
+-- f (x:xs) = f x y' : f xs [y]'
+
+-- f' x (y:ys) = if x == y then Just (href x, href y) else Nothing 
+
+
+-- fTot xs ys zs = f' xs $ f' ys zs
+
+-- -- OR
+-- f' :: [a] -> [a] -> [a]
+-- f' 
+      
+    
+--   (x, a, b) : f xs as bs 
+  
+  
+--   (x,,) <$> findSep x ys <*> findSep x zs
+--   do {- inside :: [Maybe -}
+--   (a,b,c) <- (x,,) <$> find (attrsMatch' x) y <*> find (attrsMatch' x) z
+--   return (a,b,c) : f xs (del b y) (del c z) 
+
+  
+--   -- :: Maybe (Url, Url, Url) 
+
+--   if any (attrsMatch' x) y && any 
+
+--                then        href x : f xs y
+                  
+
+--                else f xs y
+--   where href = (fromJust $ Map.lookup "href") . snd 
+
+-- commonElHUrls :: [ElemHead] -> [ElemHead] -> [ElemHead] -> [(Url, Url, Url)]
+-- commonElHUrls (a:as) = if matchFor a _in (bs && cs)
+--                        then (href a, href b, href c) : commonElHUrls as bs cs 
+--                        else continue
+
+
+-- overall :: (Elem' String, Elem' String, Elem' String)
+        -- -> matches@[(Url, Url, Url)] -- if there is more than one, take head 
+
+
+
+-- -- But for all options and return first success 
+-- if ElemHeadParse.attrsMatch (ats1 ats2) && (ats1 ats3) then (href a, href b, href c) : commonElHUrls as bs cs 
+
+-- if del variantAts attrs1 == del variantAts attrs2
+
+-- if del "href" attrs1 == del "href" attrs2
+
+-- commonElHUrls (a:as) bs cs = if elem a bs && elem a cs
+--                       then a : triMap as bs cs
+--                       else triMap as bs cs
+
+
+
+
+-- | Should be replaced by a function that ensures they are the same element
+-- | If there is a union of elemHeads inside the given element then use order, we could even give a fake attribute
+-- | named position = __n__
+-- triZip :: [a] -> [b] -> [c] -> [(a,b,c)]
+-- triZip [] _ _ = []
+-- triZip _ [] _ = []
+-- triZip _ _ [] = []
+-- triZip (a:as) (b:bs) (c:cs) = (a,b,c) : triZip as bs cs
+
+-- | Note! because we must have the same ElemHead in all 3, we only need to iterate through the options
+-- | afforded by the first element 
+
+-- i would need to stop earlier and not parse down to the href but instead keep the ElemHead
+
+-- 1: look for all elems with an href
+
+
+
+    --   -- return urlList 
+
+    -- Right (Nothing) ->
+    --   -- this is exactly Left _ 
+
+
+  
+  -- do
+
+
+  
+  -- x2 <- case (parse (findNaive getValidHrefs) "" (innerText' elem)) of
+  --         Left _ -> return [] 
+  --         Right (Just urlList) -> return urlList 
+  --         Right (Nothing) -> return []
+
+  -- -- Container elem's link is first in list
+  -- case headHref of
+  --   Nothing -> x2
+  --   Just a -> return (a:x2)
+
+
+ -- case :: Maybe [x]
+ -- headhref :: Maybe a
+
+ -- (:) <$> case <*> headHref
+
+
+-- length 3 
+paginationElements :: Stream s m Char => ParsecT s u m (Elem' String, Elem' String, Elem' String)
+paginationElements = do 
+  let
+    attrs' e = (fmap . fmap) Just $ Map.toList (attrs e)
+    el' e = Just $ [elTag e]
+    strip (Left e) = e
+    strip (Right e) = e
+  
+  x <- elemParser Nothing (Just $ string "1") [] 
+  -- This could be different from option 1 but still contain 2, validly 
+  y <- Right <$> (try $ elemParser (el' x) (Just $ string "2") (attrs' x))
+       <|> Left <$> elemParser Nothing (Just $ string "2") []
+       
+  z <- case y of
+         Right elemnt -> elemParser (el' elemnt) (Just $ string "3") (attrs' x)
+         Left elemnt' -> do
+           -- check for the next two to see if same struct three times in a row
+           z1 <- elemParser (el' elemnt') (Just $ string "3") (attrs' elemnt')
+           z2 <- elemParser (el' elemnt') (Just $ string "4") (attrs' elemnt')
+           return z1
+  
+  return (x,strip y,z)
+
+
+
+                       
+catEithers :: [Either a b] -> [b]
+catEithers [] = []
+catEithers (x:xs) = case x of
+                      Left err -> catEithers xs
+                      Right a -> a : catEithers xs
+
+
+
+
+-- [Basic "t:formdata" (Just "uDJ/uU5iG21GWkfqbAMV1Zn5fBg=:H4sIAAAAAAAAALWPMUpEMRRFnwM2Tie4g7FNGqfRahphYBDhq2D5kjz/RPKT8PK+ZjbjCsRNTGHnHlyArZWFgb8CC7vLvVzOva9fcPh8D3cDCWZObrRSdEw8YNBovDA60uvoqJ6XNLIl2WUqhZDtVlHN2CJnsHg7eSZVNSkhHqAwLBP3CjPaLanGoCK8WyqbmII3qlVJrUwz0cqlp+AWHcmYT2/388+T958ZHGxgblMUTuEK20w43jziE+qAsdedsI/9Rc0CRxP2pmH/99Dqr4euOdmG6EYz+FJ8ivs3d/bw/fIxA6j5F93V05aCAQAA"),Basic "searchTerm" Nothing,Basic "hidden_2" (Just ""),Basic "hidden_1" (Just ""),Basic "hidden_0" (Just ""),Basic "hidden" (Just ""),Basic "t:formdata" (Just "xPUyg4nRPmz/Nz4dRXsk2UiZPu4=:H4sIAAAAAAAAANVUTWgTQRR+Bi2F2vqHXrzkEA9FsmlKIxIpWsRoIVRpWosFldndl2Tr7M52Zja7VfSqh969FQRv/lz1bA/SixeLd8GrUBQ8KTizm6RgRCwkKTnNzvd23ve9me+9l1/hULgI8y5K4nNmB5YUOY9xl9AcMR3JiY25Wc/GqChYwC2Uaz4KgYRbdQMjn6iQbRLhWAlmssioO7aNHggOlxivGcQnVh0NlR+F5GsFw2IcqWOq1fWZh54UxrX4SOYGZ5bKXglM1xHCYd7y4/SJ6PTboRQcKMOIxTzJGZ0jSi0cL6+QBslR4tVyFckdr3Yh8iUMJezhEix0v6a7EyBW4RGAhOEW0iOmfAdTvkdMkx1Mk+FtWO4mUwtOEO2MafX4hkq/GihTKIv44m+2iI0gO22xsX324PpYYycFqTIMW9RRf8/augptE6ToKkDbJIa0LcZaEiqxBI0fDu9BvZtVJl/UUZKRC6MaUCoxkjGgay78sxtUMjRmTAUSS5YcpHamgjLwzyxujnw++f5nRwu0axvVTAuKqayZ+l3VzF6r6njNzdf2VPXHxocUQOSHLqz0UL6PyDk2HAybBehbHJVwRAfm40Byi/2VoVUcC9XaQ06MLBrY2N5Txnw90DgY/zumy+pIppC9vvVpHB5sJe81GKLzt768+l598/HZ/oqe25PoeRVXoYokEkucuRW9sy/H4+4moQFmn77bfgLpX83ZsBtoz4bslUTLksOxhGoCF7PFJpTWWLoFVgkVGD6E+328lz/2u83YDJSbgX2WNUjNOfXNr45fPfXi4iA157mJozvn7zxfn45F/wZR7xe+kwoAAA=="),Basic "site" (Just "abicomplete")]]
diff --git a/src/Scrappy/Requests/Proxies.hs b/src/Scrappy/Requests/Proxies.hs
new file mode 100644
--- /dev/null
+++ b/src/Scrappy/Requests/Proxies.hs
@@ -0,0 +1,99 @@
+{-# LANGUAGE FlexibleContexts #-}
+
+module Scrappy.Requests.Proxies where
+
+import Scrappy.Scrape (runScraperOnHtml)
+import Scrappy.Elem.ChainHTML (containsFirst)
+import Scrappy.Elem.SimpleElemParser (el)
+import Scrappy.Elem.Types (innerText')
+
+import Text.Parsec (ParsecT, Stream, many)
+import Network.HTTP.Client (Proxy, Manager, HttpException, Response, Proxy(..), responseBody, httpLbs
+                           , parseRequest, newManager, useProxy, managerSetSecureProxy)
+import Network.HTTP.Client.TLS (tlsManagerSettings)
+import Control.Exception (catch)
+import Data.List (isInfixOf)
+import Data.Text (unpack, pack)
+import Data.Text.Encoding (encodeUtf8)
+import qualified Data.Text.Lazy as LazyTX (toStrict, Text)
+import qualified Data.Text.Lazy.Encoding as Lazy (decodeUtf8With)
+import Data.ByteString.Lazy (ByteString)
+
+
+
+ 
+testForValidProxy :: [Proxy] -> IO (Manager)
+testForValidProxy (proxy:proxies) = do
+  req <- parseRequest "https://hackage.haskell.org/package/base-4.15.0.0/docs/Control-Exception.html#v:catch"
+  trialManager <- mkManagerInternal proxy
+  print $ "hello"
+  let
+    f :: IO (Manager)
+    f = catch (httpLbs req trialManager >> return trialManager) g
+
+    g :: HttpException -> IO (Manager)
+    g = (\_ -> testForValidProxy proxies) 
+  x <- f
+  return x
+
+
+
+
+rowToProxy :: [String] -> Proxy
+rowToProxy row = Proxy ((encodeUtf8 . pack) (row !! 0)) (read (row !! 1) :: Int)
+
+mkManagerInternal :: Proxy -> IO Manager
+mkManagerInternal proxy = newManager (managerSetSecureProxy (useProxy proxy) tlsManagerSettings)
+
+  
+
+mkProxdManager :: IO (Manager)
+mkProxdManager = do
+  proxyRows <- scrapeProxyList
+  testForValidProxy proxyRows
+
+
+
+-- | Table pattern should also take a Cell where data Cell = (X,Y)
+scrapeProxyList :: IO [Proxy] -- becoming [[String]]
+scrapeProxyList = do
+  response <- getHtml' "https://free-proxy-list.net/"
+  let
+    parser = el "tr" [] `containsFirst` b
+    b :: Stream s m Char => ParsecT s u m [String]
+    b = ((fmap . fmap) innerText' $ many (el "td" []))
+
+    bePicky :: [[String]] -> [[String]]
+    bePicky rows = filter (\x -> not $ (isInfixOf "anonymous" (x !! 4)) || (isInfixOf "elite proxy" (x !! 4))) rows
+    
+    -- g :: [String] -> Proxy
+    -- g row = Proxy ((encodeUtf8 . pack) (row !! 0)) (read (row !! 1) :: Int)
+    
+  -- mapM_ print $ fromMaybe [] $ fromRight Nothing (parse (findNaive parser) "" response)
+    
+  case runScraperOnHtml parser response of
+    Just (rows) ->
+      return (fmap rowToProxy (rows))
+    Nothing -> ioError $ userError "proxy error: couldnt get proxy"
+    
+    
+------
+--Move to Internal module:https://stackoverflow.com/questions/8650297/haskell-recursive-circular-module-definitions
+------
+
+ 
+-- | Get html with no Proxy 
+getHtml' :: String -> IO String
+getHtml' url = do
+  mgrHttps <- newManager tlsManagerSettings
+  requ <- parseRequest url
+  response <- httpLbs requ mgrHttps
+  return $ extractDadBod response
+
+
+
+extractDadBod :: Response ByteString -> String 
+extractDadBod response = (unpack . LazyTX.toStrict . mySafeDecoder . responseBody) response
+
+mySafeDecoder :: ByteString -> LazyTX.Text
+mySafeDecoder = Lazy.decodeUtf8With (\_ _ -> Just '?')
diff --git a/src/Scrappy/Requests/Requests.hs b/src/Scrappy/Requests/Requests.hs
new file mode 100644
--- /dev/null
+++ b/src/Scrappy/Requests/Requests.hs
@@ -0,0 +1,1017 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Scrappy.Requests.Requests where
+
+-- TODO: should i rename as Scrappy.Requests.Class?
+
+-- Idea: a language extension that allows module organization like:
+
+-- import Control
+         -- .Monad
+           -- .IO.Class (liftIO)
+           -- .Trans
+             -- .StateT (f)
+             -- .ExceptT (g)
+import Scrappy.Requests.Proxies (mkProxdManager)
+import Scrappy.Requests.BuildActions (FilledForm(..), showQString, Namespace, QueryString, FormError(..))
+import Scrappy.Scrape (ScraperT, runScraperOnHtml, hoistMaybe)
+import Scrappy.Find (findNaive)
+import Scrappy.Elem.ChainHTML (contains)
+import Scrappy.Elem.SimpleElemParser (el)
+import Scrappy.Elem.Types (innerText', ElemHead, Clickable(..))
+import Scrappy.Links (BaseUrl, Link(..), renderLink)
+import Scrappy.Requests.Types (CookieManager(..))
+import Scrappy.Types (Html)
+
+-- import Test.WebDriver (WD, getSource, runWD, openPage, getCurrentURL, executeJS)
+-- import Test.WebDriver.Commands.Wait (waitUntil, expect, )
+-- import Test.WebDriver.Commands ( Selector(ById, ByXPath), findElem )
+-- import qualified Test.WebDriver.Commands as WD (click)
+-- import Test.WebDriver.Exceptions (InvalidURL(..))
+-- import Test.WebDriver.JSON (ignoreReturn)
+-- import Test.WebDriver.Session (getSession, WDSession)
+
+import Control.Concurrent (threadDelay)
+import Network.HTTP.Types.Header
+import Network.HTTP.Client.TLS (tlsManagerSettings)
+import Network.HTTP.Client
+import Network.HTTP.Types.Method (methodGet, Method,)
+
+import System.Directory (removeFile, copyFile, getAccessTime, listDirectory)
+import Text.Parsec (ParsecT, Parsec, ParseError, parse, Stream, many)
+import Control.Monad.IO.Class (MonadIO, liftIO )
+import Control.Monad.Trans.State (StateT, gets, put, get)
+import Control.Monad.Trans.Class (lift)
+import Control.Monad (when)
+import Control.Monad.Trans.Except (ExceptT)
+import Control.Monad.Trans.Maybe (MaybeT, runMaybeT)
+import Data.Functor.Identity (Identity)
+import Control.Exception (Exception)
+import Control.Monad.Except (throwError)
+import Control.Monad.Catch (MonadCatch, MonadThrow, catch)
+import Data.Maybe (catMaybes, fromMaybe)
+import Data.Map (Map, toList)
+import Data.List (isInfixOf, isSuffixOf, maximumBy)
+import Data.Text (Text, unpack, pack)
+import Data.Text.Encoding (encodeUtf8, decodeUtf8, decodeUtf8With)
+import qualified Data.Text.Lazy as LazyTX (toStrict, Text)
+import qualified Data.Text.Lazy.Encoding as Lazy (decodeUtf8With)
+import qualified Data.ByteString.Lazy as LBS
+import qualified Data.ByteString as BS
+import Data.Time.Clock (UTCTime)
+import Data.Time.Clock.System (SystemTime(MkSystemTime), getSystemTime, systemSeconds)
+import Data.Int (Int64)
+
+import Data.Aeson (encodeFile)
+
+data ExistT m a = ExistT { runExistT :: MaybeT m a }
+
+
+
+
+
+
+
+
+
+-- runSomeFunc :: MonadIO m => FilePath -> Url -> (Html -> MaybeT m a) -> MaybeT m a
+-- runSomeFunc fp url someFunc = do
+--   (html, _) <- liftIO $ getHtmlST url
+
+--   case someFunc html of
+--     Just a -> pure a
+--     Nothing -> do
+--       htmlV <- fetchVDOM url
+--       case someFunc htmlV of
+--         Just a -> pure . Just $ a
+--         Nothing -> do
+-- --          encodeFile (mkFileUrl url)
+--           pure . Just $ Nothing
+
+
+
+
+-- Regarding the need to model similar to a browser here's what we know
+
+--   -> The browser gets the index.html (like we do with getHtml, getHtml' ((which should be renamed to getHtmlRaw))
+--   -> When the browser gets this it parses the entire HTML structure and finds what it needs to request
+--     --> links for css (currently negligible) and scripts which do not exist in the code but have a src attribute
+--   -> Also if an action attribute is 0 then it's the current URL
+
+
+
+-- Need a section for Headers logic
+
+
+type ParsecError = ParseError
+
+
+
+
+-- runScraperM "" $ \html -> do
+--   ...
+
+
+---- Control flow
+
+(>>|=) :: Monad m => [a] -> (a -> MaybeT m a) -> MaybeT m [a]
+(>>|=) x f = successesM f x
+
+successesM :: Monad m => (a -> MaybeT m b) -> [a] -> MaybeT m [b]
+successesM fm inputs =
+  lift . (fmap catMaybes) . sequenceA $ fmap (runMaybeT . fm) inputs
+
+successesM_ :: Monad m => (a -> MaybeT m b) -> [a] -> MaybeT m ()
+successesM_ a b = successesM a b >> return ()
+
+successes :: [a] -> (a -> Maybe b) -> Maybe [b]
+successes inputs f =
+  case catMaybes $ fmap f inputs of
+    [] -> Nothing
+    xs -> Just xs
+
+------------------
+
+runScraperM :: Url -> (Html -> MaybeT IO a) -> MaybeT IO a
+runScraperM url scraper = (liftIO $ getHtml' url) >>= scraper
+
+
+
+trySiteLink :: MonadIO m => Link -> (Html -> MaybeT m ()) -> MaybeT m Link
+trySiteLink url scraperBasedEffects = do
+  html <- liftIO $ getHtml' (renderLink url)
+  scraperBasedEffects html
+  return url
+
+
+-- | propogate to requests module
+runScraperOnUrl' :: (MonadIO m, MonadThrow m) => Link -> ScraperT a -> m (Maybe [a])
+runScraperOnUrl' url p = fmap (runScraperOnHtml p) (getHtml'' url)
+
+
+-- | Get html with no Proxy
+getHtml'' :: (MonadThrow m, MonadIO m) => Link -> m Html
+getHtml'' url = do
+  mgrHttps <- liftIO $ newManager tlsManagerSettings
+  requ <- parseRequest (renderLink url)
+  response <- liftIO $ httpLbs requ mgrHttps
+  return $ extractDadBod response
+
+
+-- aside
+
+-- Also need to generalize to MonadIO
+
+-- | Should change these to name_ and then make these names do same thing except read in a
+-- | session variable
+type Url = String
+runScraperOnUrl :: Link -> Parsec Html () a -> IO (Maybe [a])
+runScraperOnUrl (Link url) p = fmap (runScraperOnHtml p) (getHtml' url)
+
+runScraperOnUrls :: [Link] -> Parsec Html () a -> IO (Maybe [a])
+runScraperOnUrls urls p = fmap (foldr (<>) Nothing) $ mapM (flip runScraperOnUrl p) urls
+
+
+-- foldr :: (a -> b -> c)
+
+foldFunc :: Maybe [a] -> Maybe [a] -> Maybe [a]
+foldFunc = undefined
+
+runScrapersOnUrls = undefined
+
+--- this is meant to be pseudo code at the moment
+type STM = IO
+
+-- | Merge Maybe [a] when multiple urls
+concurrentlyRunScrapersOnUrls :: [Link] -> [ParsecT s u m a] -> STM (Maybe [a])
+concurrentlyRunScrapersOnUrls = undefined
+  -- inner will call concurrent stream functions on the given urls
+
+
+
+-- doSignin :: ElemHead -> ElemHead -> Url
+
+-- | Get html with no Proxy
+-- | Raw af
+getHtml' :: Url -> IO Html
+getHtml' url = do
+  mgrHttps <- newManager tlsManagerSettings
+  requ <- parseRequest url
+  response <- httpLbs requ mgrHttps
+  return $ extractDadBod response
+
+
+
+
+
+-- | Gurantees retrieval of Html by replacing the proxy if we are blocked or the proxy fails
+getHtml :: Manager -> Link -> IO (Manager, Html)
+getHtml mgr url = do
+  requ <- parseRequest (renderLink url)
+  let
+    headers = [ (hUserAgent, "Mozilla/5.0 (X11; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0")
+              , (hAcceptLanguage, "en-US,en;q=0.5")
+              , (hAcceptEncoding, "gzip, deflate, br")
+              , (hConnection, "keep-alive")
+              ]
+    req = requ { requestHeaders = (fmap . fmap) (encodeUtf8 . pack) headers
+               , secure = True
+               }
+  (mgr', r) <- catch (fmap ((mgr,) . extractDadBod) $ httpLbs requ mgr) (recoverMgr' url)
+  return (mgr', r)
+
+
+recoverMgr' :: Link -> HttpException -> IO (Manager, String)
+recoverMgr' url _ = mkProxdManager >>= flip getHtml url
+
+
+
+
+
+-- -- type SiteNew sv = ReaderT (MVar [FreeSite], sv, Url) (ExceptT ScrapeException' IO) Url
+-- -- maybe but really just want this:
+
+--       scrape patttern -- implicit State
+
+-- data ImplicitState = IsUrl String | IsHtml String
+-- -- If we want to scrape we check the state
+-- -- when IsUrl $ do getHtml (=<< gets seshV) >>= putImplicit
+
+
+-- f :: SiteScraperT ()
+-- f = do
+--   scrape x
+--   scrape y
+--   fetch newUrl -- lazily puts (IsUrl String)
+
+-- -- A site could also keep hold of a Map of all urls on site
+--   -- We could also use this informatsion for patterns
+--   -- ie a Contact us section would probably be shallower a tree
+
+
+-- class MultiSite where
+--   -- really just would be a construct for this is not constrained to a single site via getUsefulLinks
+--   -- could also do where if we do fetch another site, we have a mechanism to hold
+--   -- MVars of site data from previously viewed sites performed upon fetch
+
+-- -- | Where the sv is effectively constrained to SessionState sv => sv
+type SiteM hasSv e a = StateT hasSv (ExceptT e IO) a
+
+-- | TODO: implement default
+-- | Where the sv is effectively constrained to SessionState sv => sv
+-- type SiteT sv e a = StateT sv (ExceptT e IO) a
+
+
+-- | Where the sv is effectively constrained to SessionState sv => sv
+newtype SiteT sv e a = SiteT { runSite :: StateT sv (ExceptT e IO) a }
+
+type Host = String
+type Port = String
+
+
+class SessionState a where
+  getHtmlST :: (MonadThrow m, MonadIO m) => a -> Link -> m (Html, a)
+  getHtmlAndUrl :: (MonadThrow m, MonadIO m) => a -> Link -> m (Html, Link, a)
+  submitForm :: (MonadThrow m, MonadIO m) => a -> FilledForm -> m ((Html, Link, a), FilledForm)
+  click :: (MonadThrow m, MonadIO m) => FilePath -> a -> Clickable -> m (String, a)
+  --  Download a pdf link
+  clickWritePdf :: (MonadThrow m, MonadIO m) => a -> FilePath -> Clickable -> m (Either ScrapeException a)
+  clickWriteFile :: (MonadThrow m, MonadIO m) => a -> FileExtension -> Clickable -> m (Either ScrapeException (), a)
+  clickWriteFile' :: a
+                  -> FileExtension -- desired file extension to match
+                  -> FilePath -- where to save
+                  -> Clickable
+                  -> IO (Either ScrapeException (), a)
+
+  -- askCookies :: m CookieJar
+
+
+
+
+
+instance SessionState Manager where
+  getHtmlST manager link = do
+    (m, s) <- liftIO $ getHtml manager link
+    return (s, m)
+
+  getHtmlAndUrl manager (Link url) = do
+    req <- parseRequest url
+    liftIO $ catch (baseGetHtml manager req) (saveReq' (Link url) getHtmlAndUrl)
+
+  -- Note: qStrVari has data on basic params factored in
+  submitForm manager (FilledForm actionUrl reqM term tInput qStrVari) = do
+    req <- parseRequest actionUrl
+    let
+      req2 = req { method = reqM, queryString = (encodeUtf8 . showQString) $ head tInput <> head qStrVari }
+      f2 = FilledForm actionUrl reqM term tInput (tail qStrVari)
+
+    liftIO $ fmap (, f2) $ catch (baseGetHtml manager req2) (saveReq req2 baseGetHtml)
+
+  clickWritePdf manager filepath x@(Clickable _ url) = do
+    (pdf, mgr) <- getHtmlST manager url
+    -- path <- liftIO $ resultPath searchTerm (getHost baseU) (Paper x) >>= flip writeFile pdf
+    liftIO $ writeFile filepath pdf
+    return $ Right mgr
+      -- Invalidate normal HTML responses here------
+      -- AND if file did not download then this was not a PdfLink like expected
+
+  click = undefined 
+  clickWriteFile = undefined 
+  clickWriteFile' = undefined 
+
+
+-- we only actually wanna do this in the case of
+-- getHtmlST' :: (HasSessionState hasSv, MonadIO m) => Url -> StateT hasSv m Html
+-- getHtmlST' = do
+--   (c, m) <- gets cookies <*> gets manager
+--   url <- getHtmlST (c,m) url
+--   return ""
+
+-- getHtmlReq :: CookieManager -> Request -> IO (CookieManager, Html)
+-- getHtmlReq mgr req = do
+--   fmap (mgr,) $ httpLbs req mgr -- ?
+
+-- data CookieManager = CookieManager CookieJar Manager
+
+-- getHtmlST :: Url || Form ||
+
+--- - MonadIO m, HasSessionState s) => SiteT s m a
+
+-- we dont fucking need this, just take idea with seshVar (get, put set up)
+-- class HasSessionState a sv | a -> sv where
+--   takeSession :: SessionState sv => a -> sv
+--   writeSession :: SessionState sv => sv -> a -> a
+
+setCJ :: CookieJar -> Request -> Request
+setCJ cj req = req { cookieJar = Just cj }
+
+setBasicHeaders :: Request -> Request
+setBasicHeaders req =
+  let
+    headers = [ (hUserAgent, "Mozilla/5.0 (X11; Linux x86_64; rv:98.0) Gecko/20100101 Firefox/98.0")
+              , (hAcceptLanguage, "en-US,en;q=0.5")
+              --, (hAcceptEncoding, "gzip, deflate, br")
+              , (hConnection, "keep-alive")
+              ]
+  in req { requestHeaders = (fmap . fmap) (encodeUtf8 . pack) headers
+         , secure = True
+         }
+
+
+buildReq :: MonadThrow m => CookieJar -> Link -> m Request
+buildReq cj (Link url) = do
+  req <- parseRequest url
+  pure $ (setCJ cj) . setBasicHeaders $ req
+--  ((setCJ cj) . setBasicHeaders) <$> parseRequest url
+
+
+
+-- | Gurantees retrieval of Html by replacing the proxy if we are blocked or the proxy fails
+getHtmlMgr :: Manager -> Link -> IO (Manager, Html)
+getHtmlMgr mgr url = do
+  requ <- parseRequest (renderLink url)
+  let
+    headers = [ (hUserAgent, "Mozilla/5.0 (X11; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0")
+              , (hAcceptLanguage, "en-US,en;q=0.5")
+              , (hAcceptEncoding, "gzip, deflate, br")
+              , (hConnection, "keep-alive")
+              ]
+    req = requ { requestHeaders = (fmap . fmap) (encodeUtf8 . pack) headers
+               , secure = True
+               }
+  (mgr', r) <- catch (fmap ((mgr,) . extractDadBod) $ httpLbs requ mgr) (recoverMgr' url)
+  return (mgr', r)
+
+
+{-# DEPRECATED baseGetHtml "needs extractDadBod" #-}
+baseGetHtml :: Manager -> Request -> IO (Html, Link, Manager)
+-- baseGetHtml Request -> ReaderT Manager IO (Html, Url)
+baseGetHtml manager req = do
+  hResponse <- responseOpenHistory req manager
+  let
+    finReq = hrFinalRequest hResponse
+    dadBodNew response = (unpack . decodeUtf8) response
+  finResBody <- fmap mconcat $ brConsume $ responseBody $ hrFinalResponse hResponse
+  return (dadBodNew finResBody, Link $ (unpack . decodeUtf8) $ (host finReq) <> (path finReq) <> (queryString finReq), manager)
+
+
+-- | Gurantees retrieval of Html by replacing the proxy if we are blocked or the proxy fails
+getHtmlMgr' :: Manager -> Url -> IO (Manager, Html)
+getHtmlMgr' mgr url = do
+  let
+    headers = [ (hUserAgent, "Mozilla/5.0 (X11; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0")
+              , (hAcceptLanguage, "en-US,en;q=0.5")
+              , (hAcceptEncoding, "gzip, deflate, br")
+              , (hConnection, "keep-alive")
+              ]
+  getHtmlHeaderMgr headers mgr url
+
+  -- return (mgr', r)
+
+getHtmlHeaderMgr :: [Header] -> Manager -> Url -> IO (Manager, Html)
+getHtmlHeaderMgr headers mgr url = do
+  -- (fmap.fmap) extractDadBod . $
+  (mgr, res) <- persistGet mgr =<< mkReq headers url
+  res' <- readMyBody $ hrFinalResponse res
+  pure (mgr, res')
+
+
+mkReq :: MonadThrow m => [Header] -> Url -> m Request
+mkReq headers url = fmap (setHeaders headers) $ parseRequest url
+  where setHeaders headers req = req { requestHeaders = headers }
+  -- return (mgr', r)
+
+recoverMgr :: Request
+           -> HttpException
+           -> IO (Manager, HistoriedResponse BodyReader)
+recoverMgr req _ = print "recover manager" >> (flip persistGet req =<< mkProxdManager)
+
+persistGet :: MonadIO m => Manager
+           -> Request
+           -> m (Manager, HistoriedResponse BodyReader)
+persistGet sv req = liftIO $ catch (getHtmlHistoried sv req) (recoverMgr req)
+
+-- | Only applies sv into http functions
+getHtmlHistoried :: MonadIO m => Manager
+                -> Request
+                -> m (Manager, HistoriedResponse BodyReader)
+getHtmlHistoried m r = liftIO $ fmap (m,) $ responseOpenHistory r m
+
+
+    --getHtmlFlex manager req = catch (baseGetHtml manager req) (saveReq getHtmlFlex req)
+
+
+  -- getHtm
+  -- getHtmlST url = do
+  --   CookieManager cj mgr <- gets sv
+  --   req <- parseRequest url
+  --   (m, s) <- getHtmlReq mgr $ setCJ cj req
+  --   return (s, m)
+
+-- | this fails if its a post request
+requestToUrl' :: Request -> Maybe Url
+requestToUrl' req = if methodGet == method req
+                    then Just . unpack . decodeUtf8 $ (host req) <> (path req) <> (queryString req)
+                    else Nothing
+
+-- works for any request
+getURL :: Request -> Url
+getURL req =  unpack . decodeUtf8 $ (host req) <> (path req) <> (queryString req)
+
+
+drop1qStrVar :: FilledForm -> FilledForm
+drop1qStrVar (FilledForm a b c d qStr) = FilledForm a b c d (drop 1 qStr)
+
+mkFormRequest :: MonadThrow m => Url -> Method -> QueryString -> m Request
+mkFormRequest url reqMethod qString = do
+  req <- parseRequest url
+  pure $ req { method = reqMethod
+             , queryString = encodeUtf8 . showQString $ qString
+             }
+
+
+-- extractDadBod :: Response ByteString -> String
+-- extractDadBod response = (unpack . LazyTX.toStrict . mySafeDecoder . responseBody) response
+
+
+-- mySafeDecoder :: ByteString -> LazyTX.Text
+-- mySafeDecoder = Lazy.decodeUtf8With (\_ _ -> Just '?')
+
+
+
+-- | Get html with no Proxy
+getHtmlText :: Url -> IO Text
+getHtmlText url = do
+  mgrHttps <- newManager tlsManagerSettings
+  requ <- parseRequest url
+  let
+    headers = [ (hUserAgent, "Mozilla/5.0 (X11; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0")
+              , (hAcceptLanguage, "en-US,en;q=0.5")
+              , (hAcceptEncoding, "gzip, deflate, br")
+              , (hConnection, "keep-alive")
+              ]
+    req = requ { requestHeaders = (fmap . fmap) (encodeUtf8 . pack) headers
+               , secure = True
+               }
+
+  response <- httpLbs requ mgrHttps
+  return $ extractDadBodText response
+
+
+
+
+
+extractDadBodText :: Response LBS.ByteString -> Text
+extractDadBodText = LazyTX.toStrict . mySafeDecoder . responseBody
+
+
+
+extractDadBod :: Response LBS.ByteString -> String
+extractDadBod = unpack . LazyTX.toStrict . mySafeDecoder . responseBody
+
+extractDadBod' :: LBS.ByteString -> String
+extractDadBod' = unpack . LazyTX.toStrict . mySafeDecoder
+
+mySafeDecoder :: LBS.ByteString -> LazyTX.Text
+mySafeDecoder = Lazy.decodeUtf8With (\_ _ -> Nothing) -- Just '?')
+
+getHistoriedBody res = fmap (readHtml . LBS.fromStrict) $ brRead . responseBody $ res
+
+--ewqweqq
+-- -- Since 0.4.1
+-- withResponseHistory :: Request
+--                     -> Manager
+--                     -> (HistoriedResponse BodyReader -> IO a)
+--                     -> IO a
+-- withResponseHistory req man = bracket
+--     (responseOpenHistory req man)
+--     (responseClose . hrFinalResponse)
+
+
+httpHistLbs :: Request -> Manager -> IO (HistoriedResponse LBS.ByteString)
+httpHistLbs req man = withResponseHistory req man $ \hRes -> do
+  bss <- brConsume $ responseBody . hrFinalResponse $ hRes
+--  return $ hRes { responseBody = LBS.fromChunks bss }
+  pure $ f' hRes (f (hrFinalResponse hRes) (LBS.fromChunks bss))
+  where
+    f' hr r = hr { hrFinalResponse = r }
+    f res b = res { responseBody = b }
+
+-- httpHistLbs = withResponseHistory req man $ \hrbr ->
+--   pure ()
+
+
+test2 = do
+  req <- parseRequest "https://www.google.com/"
+  mgr <- newManager tlsManagerSettings
+  hRes <- httpHistLbs req mgr
+--  print $ extractDadBod . hrFinalResponse $ hRes
+  print . fst =<< getHtmlST (CookieManager mempty mgr) (Link "https://www.google.com/")
+  -- print $ responseBody . hrFinalResponse $ hRes
+  pure ()
+
+readMyBody :: Response (IO BS.ByteString) -> IO Html
+readMyBody res = do
+  chunks <- brConsume $ ((responseBody $ res) :: BodyReader)
+  chunk <- brRead . responseBody $ res
+  print chunk
+  let
+--    body :: ByteString
+    body = LBS.fromChunks chunks
+  print "hey"
+  --print body
+  pure $ unpack . LazyTX.toStrict . mySafeDecoder  {-(readHtml . fromStrict)-} $ body
+  where
+    mySafeDeco :: LBS.ByteString -> LazyTX.Text
+    mySafeDeco = Lazy.decodeUtf8With (\_ _ -> Just '?')
+
+readHtml :: LBS.ByteString -> Html
+readHtml = unpack . LazyTX.toStrict . mySafeDecoder
+
+mkRGateUrl pgNum term = rGateBaseUrl <> "/search/publication?q=" <> term <> "&page=" <> (show pgNum)
+
+rGateBaseUrl = "https://www.researchgate.net"
+
+-- TODO(galen): rewrite these funcs to use httpHistLbs where applicable
+instance SessionState CookieManager where
+  getHtmlST cm@(CookieManager cj mgr) link = do
+    req <- buildReq cj link
+    hRes <- liftIO $ httpHistLbs req mgr
+    let newCookies = responseCookieJar . hrFinalResponse $ hRes
+    return (extractDadBod . hrFinalResponse $ hRes, CookieManager (cj <> newCookies) mgr)
+
+  getHtmlAndUrl (CookieManager cj mgr) url = do
+    req <- buildReq cj url
+    (manager, response) <- persistGet mgr req
+    let
+      finalResponse = hrFinalResponse response
+
+      newCookies = responseCookieJar finalResponse
+      lastUrl = getURL $ hrFinalRequest response
+    html <- liftIO $ readMyBody finalResponse
+    return (html, Link lastUrl, CookieManager (cj <> newCookies) manager)
+
+    -- (html, ) getHtmlST cm url
+    -- req <- parseRequest url
+    -- catch (baseGetHtml manager req) (saveReq' url getHtmlAndUrl)
+
+  submitForm (CookieManager cj mgr) form@(FilledForm actionUrl reqM term tInput qStrVari) = do
+    req <- mkFormRequest actionUrl reqM (head tInput <> head qStrVari)
+    (manager, response) <- persistGet mgr req
+    let
+      finalResponse = hrFinalResponse response
+
+      newCookies = responseCookieJar finalResponse
+    -- undefined cuz it needs to be removed --> this is never used here
+    html <- liftIO $ readMyBody finalResponse
+    pure ((html, undefined, CookieManager (cj <> newCookies) manager), drop1qStrVar form)
+
+  -- in future we could use applyJS or something to make perfect
+  -- in future this could return a WebDocument
+  click _ cmanager (Clickable _ url) = getHtmlST cmanager url
+
+  clickWritePdf cmanager filepath x@(Clickable _ url) = do
+    (pdf, mgr) <- getHtmlST cmanager url
+    liftIO $ writeFile filepath pdf
+    return $ Right mgr
+ 
+  clickWriteFile = undefined 
+  clickWriteFile' = undefined 
+    -- pure ((html, cm), drop1qStrVar form)
+
+  -- -- Note: qStrVari has data on basic params factored in
+  -- submitForm manager (FilledForm actionUrl reqM term tInput qStrVari) = do
+  --   req <- parseRequest actionUrl
+  --   let
+  --     req2 = req { method = reqM
+  --                , queryString = (encodeUtf8 . showQString)
+  --                                $ head tInput <> head qStrVari }
+  --     formToDo = FilledForm actionUrl reqM term tInput (tail qStrVari)
+  --   fmap (, formToDo) $ catch (baseGetHtml manager req2) (saveReq req2 baseGetHtml)
+
+  -- clickWritePdf cmanager filepath x@(Clickable baseU _ url) = do
+  --   (pdf, mgr) <- getHtmlST cmanager url
+  --   -- path <- liftIO $ resultPath searchTerm (getHost baseU) (Paper x) >>= flip writeFile pdf
+  --   writeFile filepath pdf
+  --   return $ Right mgr
+      -- Invalidate HTML responses here------
+      -- AND if file did not download then this was not a PdfLink like expected
+
+
+
+
+
+
+-- data PersistentAction a = PersistentAction { action :: IO a
+--                                            , retryInterval :: SystemTime
+--                                            , test :: a -> Bool
+--                                            , cutoffTries :: Maybe Int
+--                                            , cutoffTime :: Maybe SystemTime
+--                                            -- ^ absolute time
+--                                            }
+
+
+--  clickWritePdf wdSesh (Clickable baseU (e, attrs) url) =
+  -- also need to check state of previous download folder
+  -- since we have to do this, might as well test old `cropFrom` new
+  -- and result should be a single file OR notReadyYet
+
+    -- if isSuffixOf ".pdf" url
+    -- then
+    --   do
+    --     (pdf, wdSesh') <- getHtmlST wdSesh url
+    --     liftIO $ writeFile (resultFolder baseU Pdf) pdf
+    --     return (Right wdSesh')
+
+    -- else
+    --   runWD wdSesh $ do
+    --   e <- findElem (ByXPath . pack $ xpath (e, attrs))
+    --   WD.click e
+    --   -- src <- waitUntil 10 (do
+        --  Should CHANGE TO checking if .pdf format
+                              -- thats a lot of work tho sooooo....
+                              -- src <- getSource
+                              -- expect (if ((length (unpack src)) < 10000) then False else True)
+                              -- return src
+                          -- )
+      -- pdf <- lift $ takeNewestFile baseU
+      -- let
+      --   host baseU = undefined
+      -- liftIO $ resultPath searchTerm baseU->host (Paper x) >>= flip writeFile pdf
+
+      -- fmap Right getSession
+      -- (unpack src,) <$> getSession
+
+
+addTenSeconds :: SystemTime -> SystemTime
+addTenSeconds (MkSystemTime s nanoS) =
+  MkSystemTime (s + 10) nanoS
+
+
+
+-- | This is only recommended if we can be absolutely confident that
+-- | the condition will be satisfied in a reasonable timescale
+-- | Do note that such a function could be very useful for an FRP system
+-- | that relies on external events
+persistUntilUnsafe :: IO a -> (a -> Bool) -> IO a
+persistUntilUnsafe actn test = do
+  x <- actn
+  if test x
+    then pure x
+    else persistUntilUnsafe actn test
+
+
+toMilli :: Int -> Int
+toMilli = (*) 1000000
+
+heatDeathOfTheUniverse :: Int64
+heatDeathOfTheUniverse = 100000000000000000
+
+
+
+persistUntilSafe :: PersistentAction a -> IO a
+persistUntilSafe (PersistentAction actn ri test cutR cutT) = do
+  x <- actn
+  currentT <- getSystemTime
+  if test x
+    then pure x
+    else if (fromMaybe 1 cutR == 0)
+            || (systemSeconds currentT > heatDeathOfTheUniverse)
+         then error "failed"
+         else
+           do
+             threadDelay $ toMilli ri
+             persistUntilSafe $ PersistentAction actn ri test cutR cutT
+
+
+data PersistentAction a = PersistentAction { action :: IO a
+                                           , retryInterval :: Int
+                                           , test :: a -> Bool
+                                           , cutoffTries :: Maybe Int
+                                           , cutoffTime :: Maybe SystemTime
+                                           -- ^ absolute time
+                                           }
+
+
+-- | There's actually no reason either of these couldnt be a Monad
+data PersistentActionM m a = PersistentActionM { actionM :: m a
+                                               , retryIntervalM :: SystemTime
+                                               , testM :: a -> Bool
+                                               , cutoffTriesM :: Maybe Int
+                                               , cutoffTimeM :: Maybe SystemTime
+                                               -- ^ absolute timex
+                                             }
+
+
+
+coerceE2M :: Either a b -> Maybe b
+coerceE2M (Left _) = Nothing
+coerceE2M (Right a) = Just a
+
+coerceM2E :: e -> Maybe a -> Either e a
+coerceM2E e Nothing = Left e
+coerceM2E _ (Just a) = Right a
+
+-- readPage >>= writeSuccesses
+--          >>/= tryNextPage (=<< ifSuccessfulFindLink) .. loop
+
+-- further complicated by the fact that we want Abstracts as well
+
+-- means for now that we need to preprocess the html
+
+-- should change to : click :: sv -> Clickable -> IO WebDocument
+
+
+
+
+
+  -- results <- successesM (someRecursiveFunc sv) $ fromMaybe [] $ scrape pdfLink html
+  -- return (local <> results)
+
+
+--grabResearchResults --> Nothing then this link in the SearchItem is Invalid
+
+-- couldn't I use TemplateHaskell to "teach" a domain in webscraping to a scraper?
+
+
+
+
+-- performResearchItem = do
+--   scrape abstract html
+--   pdf
+
+
+-- someRecursiveFunc :: sv -> Url -> MaybeT m [ResearchResult]
+
+
+firstSucc :: (a -> MaybeT IO b) -> [a] -> MaybeT IO b
+firstSucc _ [] = hoistMaybe Nothing
+firstSucc fm (a:as) = f $ fmap (runMaybeT . fm) as
+  where
+    f (actn:actns) = do
+      x <- liftIO actn
+      case x of
+        Just a -> pure a
+        Nothing -> f actns
+
+  -- let
+  --   save ::
+  -- catch (fm a) (\_ -> firstSucc fm as)
+
+
+
+-- Could eventually open this up to further extensions
+-- If something is a tree like string structure then we could extend to MessyTreeMatch which is
+-- configurable to Open and Close
+type FileExtension = FilePath
+
+data ScrapeException = --NoAdvSearchJustBasic
+  NoSearchOnSite
+  | CantDerivePagination
+  | InvalidPaginate
+  | ItemResultNF
+  | PDFRequestFailed
+  | NoSearchItems
+  | AuthError
+  | FormErr FormError
+  | OtherError String
+  | PromisedPdfDownloadNF String
+  deriving Show
+
+instance Exception ScrapeException
+
+
+-- instance Trajectory s => Trajectory SiteT s m a where
+
+-- | A trajectory is a self contained, possibly recursive scraping plan
+-- | Each state is simply a message to the runner, where we left off
+-- |
+-- | Note too that we could use this for ResearchGate
+-- |
+-- | data ResearchGate = PdfPage _x_ | RelatedToPage _y_ | GetPdf? | other
+-- | and the site has a recursive layout / papers do so this can just infinitely recurse between the opts
+-- | we could also institute some runner Function that runs the trajectory some given N times
+class Eq s => Trajectory s where
+  end :: s
+  -- could also call this stepTrajectory
+  performSiteState :: MonadIO m => s -> m s
+
+
+-- -- | As long as we have
+
+-- -- ...
+-- end :: MySiteState
+-- end = SiteEndState
+
+
+
+-- could also be called manageTrajectories
+performSiteStateMultiple :: (MonadIO m, Trajectory s) => [s] -> m ()
+performSiteStateMultiple trajs = do
+  let
+    tr' = dropWhile (==end) trajs
+  newState <- performSiteState (head tr')
+  when (not . null $ tr') $ performSiteStateMultiple $ (tail tr') <> (newState:[])
+
+  --when (s == end) $ performSiteStateMultiple ss
+
+
+performSiteStateSingle :: (Trajectory s, MonadIO m) => s -> m ()
+performSiteStateSingle s = do
+  if (s == end)
+    then return ()
+    else performSiteState s >>= performSiteStateSingle
+
+
+
+
+
+saveReq :: Request
+        -> (Manager -> Request -> IO (Html, Link, Manager))
+        -> HttpException
+        -> IO (Html, Link, Manager)
+saveReq req func _ = do
+  newManager <- mkProxdManager
+  func newManager req
+
+
+saveReq' :: Link
+         -> (Manager -> Link -> IO (Html, Link, Manager))
+         -> HttpException
+         -> IO (Html, Link, Manager)
+saveReq' link func _ = do
+  newManager <- mkProxdManager
+  func newManager link
+
+    -- hrFinalRequest res
+
+    -- mgr <- newManager tlsManagerSettings
+    -- res <- fmap (responseBody . hrFinalResponse) (responseOpenHistory req mgr) >>= brRead
+
+    -- let
+      -- finalDraftResponse = dadBod res
+
+    -- let
+    --   f :: Manager -> Request -> IO (Html, Url, Manager)
+    --   f mgr req = do
+    --     hResponse <- responseOpenHistory req mgr
+    --     -- res <- hrFinalResponse hRes
+    --     -- res <- (brConsume $ hrFinalResponse hRes)
+    --     let
+    --       finReq = hrFinalRequest hResponse
+    --       dadBodNew response = (unpack . decodeUtf8) response
+    --     finResBody <- (brRead (responseBody $ hrFinalResponse hResponse))
+    --     return (dadBodNew finResBody, (unpack . decodeUtf8) $ (host finReq) <> (path finReq) <> (queryString finReq), mgr)
+
+------------------------------------------------------------------------------------------------------------------
+    -- fmap (responseBody . hrFinalResponse) (responseOpenHistory req mgr) >>= brRead
+------------------------------------------------------------------------------------------------------------------
+
+
+
+type DownloadsFolder = FilePath
+
+-- | Pulls newest file in downloads folder into program/IO scope
+takeNewestFile :: DownloadsFolder -> Clickable -> BaseUrl -> ExceptT ScrapeException IO String
+takeNewestFile dwnlds clickable baseU = do
+  dirNames <- liftIO $ listDirectory dwnlds
+  when (length dirNames == 0) $ throwError (PromisedPdfDownloadNF
+                                        "either link was not a pdf or did not download properly or not yet")
+  times <- liftIO $ mapM getAccessTime dirNames
+  let
+    f :: [(FilePath, UTCTime)]
+    f = zip dirNames times
+    newFile = maximumBy (\x y -> if snd x > snd y then GT else LT) f
+  ---------------------------------------------
+  --Invalidate normal HTML responses here------
+  -- AND if file did not download then this was not a PdfLink like expected
+  ---------------------------------------------
+  -- liftIO $ copyFile (fst newFile) filepath
+  liftIO $ readFile (fst newFile) <* (removeFile $ fst newFile)
+  -- return pdf
+
+
+
+xpath :: ElemHead -> String
+xpath (e, attrs) = "//" <> e <> (attrsXpath attrs)
+
+attrsXpath :: Map String String -> String
+attrsXpath m =
+  let
+    lis = toList m
+    f :: (String, String) -> String
+    f (k,v) = "[@" <> k <> "='" <> v <> "']"
+  in
+    mconcat $ fmap f lis
+
+-- type ActionUrl = Url
+-- data Form' = Form' SearchTerm ActionUrl Method QueryString [QueryString]
+
+  -- submitForm wdSesh (FilledForm{..}) = do
+    -- liftIO $ print "inside submit form"
+    -- let
+      -- f2 = FilledForm baseUrl reqMethod searchTerm actnAttr textInputOpts (tail qStringVariants)
+    -- if (reqMethod == methodGet)
+      -- then fmap (,f2) $ runWD wdSesh (wdFuncF baseUrl actnAttr textInputOpts qStringVariants)
+      -- else fmap (,f2) $ postFormWD wdSesh (FilledForm baseUrl reqMethod searchTerm actnAttr textInputOpts qStringVariants)
+    -- where
+      -- wdFuncF baseU aAttr tio qStrVari = do
+        -- openPage $ baseU <> "/" <> (unpack $ aAttr <> (showQString $ (head tio) <> (head qStrVari)))
+        -- (,,) <$> (fmap unpack getSource) <*> getCurrentURL <*> getSession
+
+-- wdSubmitFormGET :: Url -> QueryString -> WD (String, Link, WDSession)
+-- wdSubmitFormGET actionUrl tioqStrVari = do
+--   openPage (actionUrl <> "?" <> (unpack (showQString $ tioqStrVari)))
+--   src <- waitUntil 10 (do
+--                           src <- getSource
+--                           expect (if ((length (unpack src)) < 50000) then False else True)
+--                           return $ unpack src
+--                       )
+--   (,,) <$> (fmap unpack getSource) <*> (Link <$> getCurrentURL) <*> getSession
+
+
+-- postFormWD :: WDSession -> FilledForm -> IO (Html, Url, WDSession)
+-- postFormWD sesh form =
+  -- (liftIO $ putStrLn "writing and submitting POST form")
+  -- >> runWD sesh (submitPostFormWD $ writeForm form)
+
+-- FilledForm baseUrl' reqMethod' searchTerm' actnAttr' textInputOpts' (qStr:qStrs)
+-- | actnAttr is part of Url
+writeForm :: Text -> QueryString -> Text
+writeForm url qString =
+  "<form id=\"myBullshitForm\""
+  <> " method=\"post\""
+  <> " action=\"" <> url <> "\""
+  <> ">"
+  -- <> ""
+  <> "hey"
+  <> writeFormParams qString
+  <> "</form>"
+
+
+-- | actnAttr is part of Url
+-- writeForm' :: Url -> Method -> QueryString -> Text
+-- writeForm' (FilledForm {..}) =
+  -- "<form id=\"myBullshitForm\""
+  -- <> " method=\"" <> (if reqMethod == methodGet then "get" else "post") <> "\""
+  -- <> " action=\"" <> (pack baseUrl <> "/" <> actnAttr) <> "\""
+  -- <> ">"
+  -- <> writeFormParams (head textInputOpts <> head qStringVariants)
+  -- <> "</form>"
+
+
+
+
+
+writeFormParams :: QueryString -> Text
+writeFormParams [] = ""
+writeFormParams (param:params) = writeParam param <> writeFormParams params
+
+writeParam :: (Namespace, Text) -> Text
+writeParam (n, v) =
+  "<input type=\"hidden\""
+  <> " name=\"" <> n <> "\""
+  <> " value=\"" <> v <> "\""
+  <> ">"
diff --git a/src/Scrappy/Requests/Types.hs b/src/Scrappy/Requests/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Scrappy/Requests/Types.hs
@@ -0,0 +1,12 @@
+module Scrappy.Requests.Types where
+
+
+import Network.HTTP.Client
+
+
+
+
+
+  
+
+data CookieManager = CookieManager CookieJar Manager   
