from flufl.enum import Enum
import sys
import uuid
import random
import logging
from member_single import Member, sequence_generator

# Fix in final copy:
#  - include repeated classes
#  - merge ClusterMember and Member
#  - remove logging stuff

def log_acceptor_state(fn):
    def wrap(self, **kwargs):
        round = kwargs['round']
        rv = fn(self, **kwargs)
        self.logger.debug("ACCEPTOR STATE@%d - %r" % (round, dict(
            last_accept=self.last_accepts[round],
            promise=self.promises[round])))
        return rv
    return wrap

def log_proposer_state(fn):
    def wrap(self, **kwargs):
        rv = fn(self, **kwargs)
        for round in range(0, len(self.values)):
            self.logger.debug("PROPOSER STATE@%d - %r" % (round, dict(
                active_proposal=self.active_proposals[round])))
        return rv
    return wrap

def log_learner_state(fn):
    def wrap(self, **kwargs):
        round = kwargs['round']
        rv = fn(self, **kwargs)
        self.logger.debug("LEARNER STATE@%d - %r" % (round, dict(
            accept_reqs_by_n=self.accept_reqs_by_n[round],
            values=self.values[round])))
        return rv
    return wrap

class defaultlist(list):

    def __getitem__(self, i):
        if i >= len(self):
            return None
        return list.__getitem__(self, i)

    def __setitem__(self, i, v):
        if i >= len(self):
            self.extend([None] * (i - len(self) + 1))
        list.__setitem__(self, i, v)

Modes = Enum('Modes', ('Initialized', 'Joining', 'Active'))

def only_in_mode(*modes):
    modes = set(modes)
    def wrap(fn):
        def replacement(self, *args, **kwargs):
            if self.mode not in modes:
                return
            return fn(self, *args, **kwargs)
        return replacement
    return wrap

class ClusterMember(Member):

    namespace = uuid.UUID('7e0d7720-fa98-4270-94ff-650a2c25f3f0')
    def __init__(self, execute_fn):
        Member.__init__(self, execute_fn)
        self.unique_id = uuid.uuid3(self.namespace, self.address).int

        # member
        self.mode = Modes.Initialized
        self.peers = [self.address]

        # acceptor
        self.last_accepts = defaultlist()
        self.promises = defaultlist()

        # proposer
        self.biggest_n = (0, 0)
        self.active_proposals = defaultlist()

        # learner
        self.accept_reqs_by_n = defaultlist()
        self.last_invoked = -1
        self.waiting_clients = defaultlist()
        self.values = defaultlist()

    def start(self, initial_value=None, cluster_members=[]):
        assert self.mode is Modes.Initialized
        if initial_value is not None:
            self.state = initial_value
            self.mode = Modes.Active
        else:
            self.state = None
            self.mode = Modes.Joining
            self.send(cluster_members, 'ADD_MEMBER', new_member=self.address)
        self.run()

    @property
    def quorum(self):
        return len(self.peers) / 2 + 1

    def next_n(self):
        n = (self.biggest_n[0] + 1, self.unique_id)
        self.biggest_n = n
        return n[0] * 65536 + n[1]

    @only_in_mode(Modes.Active)
    def do_ADD_MEMBER(self, new_member):
        self.peers.append(new_member)
        self.send([new_member], 'JOIN_CLUSTER',
                state=self.state,
                last_invoked=self.last_invoked,
                peers=self.peers)
        self.send(self.peers, 'UPDATE_PEERS',
                peers=self.peers)

    @only_in_mode(Modes.Joining)
    def do_JOIN_CLUSTER(self, state, last_invoked, peers):
        self.mode = Modes.Active
        self.state = state
        self.last_invoked = last_invoked
        self.peers = list(set(peers) | set(self.peers))

    @only_in_mode(Modes.Active)
    def do_UPDATE_PEERS(self, peers):
        self.peers = list(set(peers) | set(self.peers))

    @only_in_mode(Modes.Active)
    @log_proposer_state
    def do_INVOKE(self, input, caller):
        round = len(self.values)
        self.waiting_clients[round] = caller
        self.values.append(None)
        n = self.next_n()
        quorum = random.sample(self.peers, self.quorum)
        self.logger.info("beginning round %d with value %r and quorum %r" %
                         (round, input, quorum))
        self.active_proposals[round] = dict(
            n=n, value=input, quorum=quorum, promises={}, have_accepted=False)
        self.send(quorum, 'PREPARE', proposer=self.address, n=n, round=round)
        # if this request fails, make_request will re-invoke us

    @log_acceptor_state
    def do_PREPARE(self, proposer, n, round):
        promise = self.promises[round]
        if promise is None or n > promise:
            self.promises[round] = n
            last_accept = self.last_accepts[round]
            prev_n = last_accept['n'] if last_accept else -1
            prev_value = last_accept['value'] if last_accept else None
            self.send(
                [proposer], 'PROMISE', round=round, responder=self.address,
                prev_n=prev_n, prev_value=prev_value)

    @log_proposer_state
    def do_PROMISE(self, round, responder, prev_n, prev_value):
        active_proposal = self.active_proposals[round]
        if not active_proposal or active_proposal['have_accepted']:
            return
        promises = active_proposal['promises']
        promises[responder] = dict(prev_n=prev_n, prev_value=prev_value)
        if len(promises) >= self.quorum:
            self.logger.info("received %d responses in round %d: %r" %
                             (len(promises), round, promises))
            # find the value of the largest-numbered proposal returned to us, defaulting
            # to our own value if none is given
            value = active_proposal['value']
            largest_n = -1
            for prom in promises.values():
                if prom['prev_n'] > largest_n:
                    value, largest_n = prom['prev_value'], prom['prev_n']
            quorum = random.sample(self.peers, self.quorum)
            self.send(quorum, 'PROPOSE', round=round,
                      n=active_proposal['n'], value=value, proposer=self.address)

    @log_acceptor_state
    def do_PROPOSE(self, round, n, value, proposer):
        promise = self.promises[round]
        if n < promise:
            return
        last_accept = self.last_accepts[round]
        if not last_accept or last_accept['n'] < n:
            self.last_accepts[round] = {'n': n, 'value': value}
        self.send(self.peers, 'ACCEPT', round=round, n=n, value=value)

    @log_learner_state
    def do_ACCEPT(self, round, n, value):
        accept_reqs_by_n = self.accept_reqs_by_n[round]
        if accept_reqs_by_n is None:
            accept_reqs_by_n = self.accept_reqs_by_n[round] = {}
        count = accept_reqs_by_n[n] = accept_reqs_by_n.get(n, 0) + 1
        if count < self.quorum:
            return
        self.logger.info(
            "received %d accepts in round %d for proposal n=%d/value=%r; learning" %
            (count, round, n, value))
        self.learn(round, value)

    def learn(self, round, value):
        if self.values[round] != value:
            assert self.values[round] is None, "values[%d] is already %r" % (
                round, self.values[round])
            self.values[round] = value
        # catch up on the log as far as we can go, sending INVOKED messages
        # where necessary
        for i in xrange(self.last_invoked + 1, len(self.values)):
            if self.values[i] is None:
                break
            output = self.invoke(self.values[i])
            self.last_invoked = i
            if self.waiting_clients[i]:
                self.send([self.waiting_clients[i]], 'INVOKED', output=output)

if __name__ == "__main__":
    logging.basicConfig(
        format="%(asctime)s %(name)s %(message)s", level=logging.DEBUG)
    member = ClusterMember(sequence_generator)
    print member.address
    cluster_members = sys.argv[1:]
    if cluster_members:
        member.start(cluster_members=cluster_members)
    else:
        print "starting new cluster"
        member.start(initial_value=0)


(lazy-seq (traverse next-pends  (conj explored item)  out-reffing ent-at))))))

(lazy-seq (traverse next-pends  (conj explored item)  out-reffing ent-at restruct-fn))))))

import sys, os, BaseHTTPServer

class ServerException(Exception):
    '''For internal error reporting.'''
    pass

class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    '''
    If the requested path maps to a file, that file is served.  If the
    path maps to a directory, a listing of the directory is
    constructed and served.  If anything goes wrong, an error page is
    constructed.

    This class's RootDirectory variable must be set to the root of the
    files being served before any instances of this class are created.
    '''

    # Root directory (must be set before requests are handled).
    Root_Directory = None

    # How to display a single item in a directory listing.
    Listing_Item = "
%s
"

    # How to display a whole page of listings.
    Listing_Page = """\

Listing for %(path)s

        %(filler)s

        """

    # How to display an error.
    Error_Page = """\

Error accessing %(path)s

%(msg)s

        """

    # Classify and handle request.
    def do_GET(self):

        # Handle any errors that aren't handled elsewhere.
        try:

            # Class not yet initialized.
            if self.Root_Directory is None:
                raise ServerException, "Root directory not set"

            # Figure out what exactly is being requested.
            full_path = self.Root_Directory + self.path

            # It doesn't exist...
            if not os.path.exists(full_path):
                raise ServerException, "'%s' not found" % self.path

            # ...it's a file...
            elif os.path.isfile(full_path):
                self.handle_file(full_path)

            # ...it's a directory...
            elif os.path.isdir(full_path):
                self.handle_dir(full_path)

            # ...we can't tell.
            else:
                raise ServerException, "Unknown object '%s'" % self.path

        # Handle errors.
        except Exception, msg:
            self.handle_error(msg)

    def handle_file(self, full_path):
        try:
            input = file(full_path, "r")
            content = input.read()
            input.close()
            self.send_content(content)
        except IOError, msg:
            msg = "'%s' cannot be read: %s" % (self.path, msg)
            self.handle_error(msg)

    def handle_dir(self, full_path):
        try:
            listing = os.listdir(full_path)
            filler = '\n'.join([(self.Listing_Item % item) for item in listing])
            content = self.Listing_Page % {'path'   : self.path,
                                           'filler' : filler}
            self.send_content(content)
        except IOError, msg:
            msg = "'%s' cannot be listed: %s" % (self.path, msg)
            self.handle_error(msg)

    # Handle unknown objects.
    def handle_error(self, msg):
        content = self.Error_Page % {'path' : self.path,
                                     'msg'  : msg}
        self.send_content(content)

    # Send actual content.
    def send_content(self, content):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.send_header("Content-Length", str(len(content)))
        self.end_headers()
        self.wfile.write(content)

#----------------------------------------------------------------------

if __name__ == '__main__':

    # Set the handler's root directory.
    if len(sys.argv) < 2:
        print >> sys.stderr, "Usage: server.py base_directory"
        sys.exit(1)
    root = os.path.abspath(sys.argv[1])
    if not os.path.isdir(root):
        print >> sys.stderr, "No such directory '%s'" % root
        sys.exit(1)
    RequestHandler.Root_Directory = root

    # Create and run server.
    serverAddress = ('', 8080)
    server = BaseHTTPServer.HTTPServer(serverAddress, RequestHandler)
    server.serve_forever()


require "catechism/it_block"

class Catechism::DescribeBlock < Struct.new(:description)
  def it(description, &block)
    Catechism::ItBlock.new(description, self).instance_eval(&block) if block_given?
  end
end


([start-ent-id db algo direction] (traverse-db start-ent-id db algo direction (:curr-time db)))

(let [pend-struct (if (= :bfs algo) vec list*)

explor-fn (if (= :outgoing direction) outgoing-refs incoming-refs)]

(traverse [start-ent-id] #{}  (partial explor-fn db ts) (partial entity-at db ts) pend-struct))))

(ns core.fdb
  [:use [core storage query constructs]]
  [:require [clojure.set :as CS :only (union difference intersection)]])

(defn collify [x] (if (coll? x) x [x]))

(defn next-ts [db] (inc (:curr-time db)))

(defn next-id
  "returns a pair composed of the id to use for the given entity and the next free running id in the database"
  [db ent]
  (let [top-id (:top-id db)
          ent-id (:id ent)
          inceased-id (inc top-id)
          [id-to-use next-top] (if (= ent-id :db/no-id-yet)
                                             [(keyword (str inceased-id)) inceased-id]
                                             [ent-id top-id])]
  [id-to-use next-top]))

(defn entity-at
  "the entity with the given ent-id at the given time (defualts to the latest time)"
  ([db ent-id] (entity-at db  (:curr-time db) ent-id))
  ([db ts ent-id] (stored-entity (get-in db [:timestamped ts :storage]) ent-id)))

(defn attr-at
  "The attribute of an entity at a given time (defaults to recent time)"
  ([db ent-id attr-name]
   (attr-at db ent-id attr-name (:curr-time db)))
  ([db ent-id attr-name ts]
  (get-in (entity-at db ts ent-id) [:attrs attr-name])))

(defn value-of-at
  "value of a datom at a given time, if no time is provided, we default to the most recent value"
  ([db ent-id attr-name]  (:value (attr-at db ent-id attr-name)))
  ([db ent-id attr-name ts] (:value (attr-at db ent-id attr-name ts))))

(defn update-attr-value
  "updating the attribute value based on the kind of the operation, the cardinality defined for this attribute and the given value"
  [attr value operation]
  (cond
      (single? attr)    (assoc attr :value #{value})
   ; now we're talking about an attribute of multiple values
      (= :db/reset-to operation)  (assoc attr :value value)
      (= :db/add operation)        (assoc attr :value (CS/union (:value attr)  value))
      (= :db/remove operation)  (assoc attr :value (CS/difference (:value attr) value))))

(defn add-attr
  "adds an attribute to an entity"
  [ent attr]
  (let [attr-id (keyword (:name attr))]
     (assoc-in ent [:attrs attr-id] attr)))

(defn update-creation-ts
  "updates the timestamp value of all the attributes of an entity to the given timestamp"
  [ent ts-val]
 (reduce #(assoc-in %1 [:attrs %2 :ts ] ts-val) ent (keys (:attrs ent))))

(defn add-entry-to-index [index path operation]
  (if (= operation :db/remove)
      index
    (let [update-path (butlast path)
            update-value (last path)
            to-be-updated-set (get-in index update-path #{})]
      (assoc-in index update-path (conj to-be-updated-set update-value) ))))

(defn update-attr-in-index [index ent-id attr-name target-val operation]
  (let [ colled-target-val (collify target-val)
         add-entry-fn (fn [indx vl] (add-entry-to-index indx ((from-eav index) ent-id attr-name vl) operation))]
    (reduce add-entry-fn index colled-target-val)))

(defn add-entity-to-index  [ent timestamped ind-name]
  (let [ent-id (:id ent)
        index (ind-name timestamped)
        all-attrs  (vals (:attrs ent))
        relevant-attrs (filter #((usage-pred index) %) all-attrs )
        add-in-index-fn (fn [ind attr] (update-attr-in-index ind ent-id (:name attr) (:value attr) :db/add))]
       (assoc timestamped ind-name  (reduce add-in-index-fn index relevant-attrs))))

(defn fix-new-entity [db ent]
      (let [[ent-id next-top-id] (next-id db ent)
              new-ts (next-ts db)]
      [(update-creation-ts (assoc ent :id ent-id) new-ts) next-top-id]))

(defn add-entity  [db ent]
  (let [[fixed-ent next-top-id](fix-new-entity db ent)
          new-timestamped (update-in  (last (:timestamped db)) [:storage] update-storage fixed-ent)
          add-fn (partial add-entity-to-index fixed-ent)
          new-timestamped (reduce add-fn new-timestamped  (indices))]
    (assoc db :timestamped  (conj (:timestamped db) new-timestamped) :top-id next-top-id)))

(defn add-entities  [db ents-seq] (reduce add-entity db ents-seq))

(defn update-attr-modification-time  [attr new-ts]  (assoc attr :ts new-ts :prev-ts ( :ts attr)))

(defn update-attr [attr new-val new-ts operation]
   {:pre  [(if (single? attr)
           (contains? #{:db/reset-to :db/remove} operation)
           (contains? #{:db/reset-to :db/add :db/remove} operation))]}
   (-> attr
      (update-attr-modification-time new-ts)
      (update-attr-value new-val operation)))

(defn remove-path-values [old-vals target-val operation]
  (case operation
    :db/add [] ; nothing to remove
    :db/reset-to old-vals ; removing all of the old values
    :db/remove (collify target-val))) ; removing the values defined by the caller

(defn remove-entry-from-index [index path]
  (let [path-head (first path)
          path-to-items (butlast path)
          val-to-remove (last path)
          old-entries-set (get-in index path-to-items)]
    (cond
     (not (contains?  old-entries-set val-to-remove)) index ; the set of items does not contain the item to remove, => nothing to do here
     (and (= 1 (count old-entries-set) ) (= 1 (count (index path-head)))) (dissoc index path-head) ; a path representing a single EAV - remove it entirely
     (= (count old-entries-set) 1)  (update-in index [path-head] dissoc (second path)) ; a path that splits at the second item - just remove the unneeded part of it
     :else (update-in index path-to-items disj val-to-remove))))

(defn remove-entries-from-index [ent-id operation index attr]
  (if (= operation :db/add)
       index
      (let  [attr-name (:name attr)
               datom-vals (collify (:value attr))
               paths (map #((from-eav index) ent-id attr-name %) datom-vals)]
       (reduce remove-entry-from-index index paths))))

(defn update-index [ent-id old-attr target-val operation timestamped ind-name]
  (if-not ((usage-pred (get-in timestamped [ind-name])) old-attr)
    timestamped
    (let [index (ind-name timestamped)
          old-vals (:value old-attr)
          attr-name (:name old-attr)
          remove-paths  (remove-path-values old-vals target-val operation)
          cleaned-index (remove-entries-from-index  ent-id operation index old-attr)
          updated-index  (update-attr-in-index cleaned-index ent-id attr-name target-val operation)]
      (assoc timestamped ind-name updated-index))))

(defn update-entity [storage e-id new-attr]
  (assoc-in (stored-entity storage e-id) [:attrs (:name new-attr)] new-attr))

(defn update-timestamped
  [timestamped ent-id old-attr updated-attr new-val operation]
  (let [storage (:storage timestamped)
         new-timestamped (reduce (partial update-index  ent-id old-attr new-val operation) timestamped (indices))]
    (assoc new-timestamped :storage (update-storage storage (update-entity storage ent-id updated-attr)))))

(defn update-datom
  ([db ent-id attr-name new-val]
   (update-datom db ent-id attr-name  new-val  :db/reset-to ))
  ([db ent-id attr-name  new-val operation ]
     (let [update-ts (next-ts db)
            timestamped (last (:timestamped db))
            attr (attr-at db ent-id attr-name)
            updated-attr (update-attr attr new-val update-ts operation)
            fully-updated-timestamped (update-timestamped timestamped ent-id attr updated-attr new-val operation)]
       (update-in db [:timestamped] conj fully-updated-timestamped))))

(defn remove-entity-from-index [ent timestamped ind-name]
  (let [ent-id (:id ent)
        index (ind-name timestamped)
        all-attrs  (vals (:attrs ent))
        relevant-attrs (filter #((usage-pred index) %) all-attrs )
        remove-from-index-fn (partial remove-entries-from-index  ent-id  :db/remove)]
    (assoc timestamped ind-name (reduce remove-from-index-fn index relevant-attrs))))

(defn reffing-datoms-to [e-id timestamped]
  (let [vaet (:VAET timestamped)]
        (for [[attr-name reffing-set] (e-id vaet)
                reffing reffing-set]
               [reffing attr-name e-id])))

(defn remove-back-refs [db e-id timestamped]
  (let [refing-datoms (reffing-datoms-to e-id timestamped)
          remove-fn (fn[d [e a v]] (update-datom db e a v :db/remove))
          clean-db (reduce remove-fn db refing-datoms)]
       (last (:timestamped db))))

(defn remove-entity  [db ent-id]
  (let [ent (entity-at db ent-id)
         timestamped (remove-back-refs db ent-id (last (:timestamped db)))
         retimed-timestamped (update-in timestamped [:VAET] dissoc ent-id)
         no-ent-timestamped (assoc retimed-timestamped :storage (remove-entity-from-storage (:storage retimed-timestamped) ent))
         new-timestamped (reduce (partial remove-entity-from-index ent) no-ent-timestamped (indices))]
    (assoc db :timestamped (conj  (:timestamped db) new-timestamped))))

(defn transact-on-db [initial-db  txs]
    (loop [[tx & rst-tx] txs transacted initial-db]
      (if tx
          (recur rst-tx (apply (first tx) transacted (rest tx)))
          (let [initial-timestamped  (:timestamped initial-db)
                  new-timestamped (last (:timestamped transacted))]
            (assoc initial-db :timestamped (conj  initial-timestamped new-timestamped)  :curr-time (next-ts initial-db) :top-id (:top-id transacted))))))

(defmacro  _transact [db op & txs]
  (when txs
    (loop [[frst-tx# & rst-tx#] txs  res#  [op db `transact-on-db]  accum-txs# []]
      (if frst-tx#
          (recur rst-tx# res#  (conj  accum-txs#  (vec  frst-tx#)))
          (list* (conj res#  accum-txs#))))))

(defn _what-if
  "Operates on the db with the given transactions, but without eventually updating it"
  [ db f  txs]
  (f db txs))

(defmacro what-if [db & txs]  `(_transact ~db   _what-if  ~@txs))

(defmacro transact [db & txs]  `(_transact ~db swap! ~@txs))

(defmacro q
  "querying the database using datalog queries built in a map structure ({:find [variables*] :where [ [e a v]* ]}).
  At the moment support only filtering queries, no joins is also assumed."
  [db query]
  `(let [query#  (q-clauses ~(:where query)) ; extracting the query clauses from the query
           ind# (choose-index ~db query#) ; selecting which index to use
           q-res# (query-index ind# query#) ; actually quering, from now on just preparing results
           binded-res# (bind-variables-to-query q-res# ind#) ; building a meta + real results structure
           needed-vars# (settify  ~(:find query))] ; extracting out the needed to be reported variables
     (map (partial locate-vars-in-query-res needed-vars# ) binded-res#))) ; picking the needed variables from the query result

(defn evolution-of
  "The sequence of the values of of an entity's attribute, as changed through time"
  [db ent-id attr-name]
  (loop [res [] ts (:curr-time db)]
    (if (= -1 ts) (reverse res)
        (let [attr (attr-at db ent-id attr-name ts)]
          (recur (conj res {(:ts attr) (:value attr)})  (:prev-ts attr))))))

(defn db-before
  "How the db was before a given timestamp"
  [db ts]
  (let [timestamped-before (subvec (:timestamped db) 0 ts )]
    (assoc db :timestamped timestamped-before :curr-time ts)))

(defn outgoing-refs [db ts ent-id]
  (if ent-id
    (->> (entity-at db ts ent-id)
          (:attrs)
          (vals)
          (filter ref?)
          (mapcat  (comp collify :value)))
    []))

(defn remove-explored [pendings explored]
  (if (contains? explored (first pendings))
    (recur (rest pendings) explored)
      pendings))

(defn traverse [pendings explored  out-reffing ent-at]
    (let [cleaned-pendings (remove-explored pendings explored)
           item (first cleaned-pendings)
           next-pends (reduce conj (rest cleaned-pendings) (out-reffing item))]
      (when item (cons (ent-at item)
                       (lazy-seq (traverse next-pends  (conj explored item)  out-reffing ent-at))))))

(defn traverse-db
  ([start-ent-id db bfs-or-dfs] (traverse-db start-ent-id db (:curr-time db) bfs-or-dfs))
  ([start-ent-id db ts bfs-or-dfs]
  (traverse (if (= :bfs bfs-or-dfs) [start-ent-id] '(start-ent-id))  #{}  (partial outgoing-refs db ts) (partial entity-at db ts))))


(ns core.manage
  "Management of db creation and db connections. This module allows acquire new db or reset an existing one, as well as get the db value from a connection"
  (:use core.constructs))

(def __ALL-DBS__ (atom {}))

(defn _get-db  [dbs db-name] (if (db-name dbs)  dbs  (assoc dbs db-name (make-db))))

(defn _reset-db [dbs db-name] (dissoc dbs db-name))

(defn _as-db-name [db-name] (keyword db-name))

(defn get-db-conn [db-name]
  (let [stored-db-name (_as-db-name db-name)]
  (stored-db-name (swap! __ALL-DBS__ _get-db stored-db-name))))

(defn reset-db-conn [db-name]
  (let [stored-db-name (_as-db-name db-name)]
  (swap! __ALL-DBS__ _reset-db stored-db-name)) nil)

(defn db-from-conn [conn] @conn)


import sys, os, BaseHTTPServer, mimetypes, gettext

class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

    # Root of files being served.
    Root_Directory = None

    # Is debugging output on?
    Debug = False

    # HTTP error codes.
    ERR_NO_PERM   = 403
    ERR_NOT_FOUND = 404
    ERR_INTERNAL  = 500

    # MIME types of files.
    File_Types = mimetypes.types_map

    # Filename extensions that identify executables.
    Exec_Extensions = {
        ".py" : None
    }

    # Classify and handle request.
    def do_GET(self):

        # Handle any errors that arise.
        try:

            # Class not yet initialized.
            if self.Root_Directory is None:
                self.err_internal("Root directory not set")
                return

            # Figure out what exactly is being requested.
            abs_path, query_params = self.parse_path()
            self.log("abs_path is '%s'" % abs_path)
            self.log("query_params is '%s'" % query_params)

            # It isn't below the root path.
            if not self.is_parent_dir(self.Root_Directory, abs_path):
                self.log("abs_path not below root directory")
                self.err_no_perm("Path '%s' not below root directory '%s'" % \
                                 (abs_path, self.Root_Directory))

            # It doesn't exist.
            elif not os.path.exists(abs_path):
                self.log("abs_path doesn't exist")
                self.err_not_found(abs_path)

            # It's a file. (Ignore query parameters if the file is
            # not being executed.)
            elif os.path.isfile(abs_path):
                if self.is_executable(abs_path):
                    self.log("abs_path is an executable")
                    self.handle_executable(abs_path, query_params)
                else:
                    self.log("abs_path is a file")
                    self.handle_static_file(abs_path)

            # It's a directory --- ignore query parameters.
            elif os.path.isdir(abs_path):
                self.log("abs_path is a directory")
                self.handle_dir(abs_path)

            # ...we can't tell.
            else:
                self.log("can't tell what abs_path is")
                self.err_not_found(abs_path)

        # Handle general errors.
        except Exception, msg:
            self.err_internal("Unexpected exception in main despatch: %s" % msg)

    def parse_path(self):
        '''Create the absolute path for a request, and extract the query
        parameter string (if any).'''
        parts = self.path.split("?")
        if len(parts) == 1:
            request_path, queryString = self.path, ""
        elif len(parts) == 2:
            request_path, queryString = parts
        else:
            pass
        head = os.path.abspath(self.Root_Directory)
        result = os.path.normpath(head + request_path)
        return result, queryString

    def is_parent_dir(self, left, right):
        return os.path.commonprefix([left, right]) == left

    def guess_file_type(self, path):
        base, ext = os.path.splitext(path)
        if ext in self.File_Types:
            return self.File_Types[ext]
        ext = ext.lower()
        if ext in self.File_Types:
            return self.File_Types[ext]
        return self.File_Types['']

    def is_executable(self, abs_path):
        '''Does this path map to an executable file?'''
        root, ext = os.path.splitext(abs_path)
        return ext in self.Exec_Extensions

    def handle_static_file(self, abs_path):
        '''Handle static files.  Must read in binary mode!'''
        try:
            input = file(abs_path, "rb")
            content = input.read()
            input.close()
            file_type = self.guess_file_type(abs_path)
            self.send_content(content, file_type)
        except IOError, msg:
            self.err_no_perm("'%s' cannot be read: %s" % (self.path, msg))

    # Handle directories.
    def handle_dir(self, abs_path):

        # How to display a single item in a directory listing.
        listing_item = "
%s
"

        # How to display a whole page of listings.
        listing_page = \
            "" + \
            "" + \
            "
Listing for " + "%(path)s" + "
" + \
            "
" + \
            "%(filler)s" + \
            "
" + \
            "" + \
            ""

        try:
            listing = os.listdir(abs_path)
            filler = '\n'.join([(listing_item % item) for item in listing])
            content = listing_page % {'path'   : self.path,
                                      'filler' : filler}
            self.send_content(content)
        except IOError, msg:
            self.err_no_perm("'%s' cannot be listed: %s" % msg)

    # Handle executable file.
    def handle_executable(self, abs_path, query_params):
        # Passing query parameters?
        if query_params:
            os.environ["REQUEST_METHOD"] = "GET"
            os.environ["QUERY_STRING"] = query_params
        cmd = "python " + abs_path
        childInput, childOutput = os.popen2(cmd)
        childInput.close()
        response = childOutput.read()
        childOutput.close()
        self.log("handle_executable: response length is %d" % len(response))
        self.send_response(200)
        self.wfile.write(response)

    # Send actual content.
    def send_content(self, content, fileType="text/html"):
        length = str(len(content))
        self.log("sending content, fileType '%s', length %s" % (fileType, length))
        self.send_response(200)
        self.send_header("Content-type", fileType)
        self.send_header("Content-Length", length)
        self.end_headers()
        self.wfile.write(content)

    # Report internal errors.
    def err_internal(self, msg):
        self.send_error(self.ERR_INTERNAL, msg)

    # Handle missing object errors.
    def err_not_found(self, abs_path):
        self.send_error(self.ERR_NOT_FOUND, "'%s' not found" % self.path)

    # Handle no permission errors.
    def err_no_perm(self, msg):
        self.send_error(self.ERR_NO_PERM, msg)

    # Handle execution errors.
    def errExec(self, msg):
        self.send_error(self.ERR_NO_PERM, msg)

    # Write a log message if in debugging mode
    def log(self, msg):
        if self.Debug:
            print "nitinat:", msg

#----------------------------------------------------------------------

if __name__ == '__main__':

    # Main libraries
    import getopt

    # How to handle fatal startup errors
    def fatal(msg):
        print >> sys.stderr, "nitinat:", msg
        sys.exit(1)

    # Defaults
    host = ''
    port = 8080
    root = None

    # How to use
    Usage = "server.py [-h host] [-p port] [-v] -r|Root_Directory"

    # Handle command-line arguments
    options, rest = getopt.getopt(sys.argv[1:], "h:p:rv")

    for (flag, arg) in options:
        if flag == "-h":
            host = arg
            if not arg:
                msg = "No host given with -h"
                fatal(msg)
        elif flag == "-p":
            try:
                port = int(arg)
            except ValueError, msg:
                fatal("Unable to convert '%s' to integer: %s" % (arg, msg))
        elif flag == "-r":
            root = os.getcwd()
        elif flag == "-v":
            RequestHandler.Debug = True
        else:
            fatal(Usage)

    # Make sure root directory is set, and is a directory.
    if (root and rest) or (not root and not rest):
        fatal(Usage)
    if not root:
        root = os.path.abspath(rest[0])
    if not os.path.isdir(root):
        fatal("No such directory '%s'" % root)
    RequestHandler.Root_Directory = root

    # Create and run server.
    server_address = (host, port)
    server = BaseHTTPServer.HTTPServer(server_address, RequestHandler)
    server.serve_forever()


(transact hospital-db (add-entity (-> (make-entity id)

(add-attr (make-attr :machine/name nm :string))))))

(ns scenarios.hospital
  (:use [core fdb constructs ] )
  [:require [core.manage :as M]
                [clojure.set     :as CS :only (union difference )]])

(def db-name "hos12")
(M/reset-db-conn db-name)

(def hospital-db (M/get-db-conn db-name))

(def basic-kinds [:test/bp-systolic :test/bp-diastolic :test/temperature :person/patient :person/doctor ] )

(defn make-patient[id address symptoms]
  (-> (make-entity id)
        (add-attr (make-attr :patient/kind :person/patient :db/ref))
        (add-attr (make-attr :patient/city address :string ))
        (add-attr (make-attr :patient/tests #{} :db/ref :indexed true :cardinality :db/multiple))
        (add-attr (make-attr :patient/symptoms (set symptoms) :string :cardinality :db/multiple))))

(defn make-test [t-id tests-map types ]
  (let [ent (make-entity t-id)]
           (reduce #(add-attr %1 (make-attr (first %2) ;attr-name
                                                               (second %2) ; attr value
                                                               (get types (first %2) :number) ; attr type
                                                                :indexed true ));indexed
                  ent tests-map)))

(defn add-patient [id address symptoms]
  (transact hospital-db (add-entity (make-patient id address symptoms))))

(defn add-test-results-to-patient [pat-id test-result]
  (let [test-id (:id test-result)
        a (transact hospital-db  (add-entity test-result))]
   (transact hospital-db  (update-datom pat-id  :patient/tests #{test-id} :db/add))))

;; world setup
(transact hospital-db  (add-entities (map #(make-entity %) basic-kinds )))

(add-patient :pat1 "London" ["fever" "cough"] )
(add-patient :pat2 "London" ["fever" "cough"] )

(add-test-results-to-patient :pat1  (make-test :t2-pat1  {:test/bp-systolic 170 :test/bp-diastolic 80 :test/machine "XXX"} {:test/machine "string"} ))
(add-test-results-to-patient :pat2  (make-test :t4-pat1  {:test/bp-systolic 170 :test/bp-diastolic 90 :test/machine "XYY"} {:test/machine "string"} ))

(transact hospital-db (update-datom :pat1 :patient/symptoms #{"cold sweat" "sneeze"} :db/reset-to))
(transact hospital-db (update-datom :pat1 :patient/tests #{:t2-pat1} :db/remove))
 ;  (transact hospital-db (remove-entity :t2-pat1))

 (defn keep-on-equals [a b](if (= a b) a nil ))

(q @hospital-db {:find [?e ?k] :where [[ ?e :test/bp-systolic (> 200 ?b)] [ ?e :test/bp-diastolic ?k]]} )

 (q @hospital-db {:find [?a ?b] :where [[ _  ?a (> 200 ?b)] ]})

 (q @hospital-db {:find [?e ?k ] :where [[ ?e :test/bp-systolic (> 180 ?b)][ ?e :test/bp-diastolic ?k] ]})

(evolution-of (M/db-from-conn hospital-db) :pat1 :patient/symptoms)
(evolution-of (M/db-from-conn hospital-db) :pat1 :patient/tests)

   (take 4 (traverse-db  :pat2 @hospital-db (:curr-time @hospital-db) :bfs))

   (outgoing-refs  @hospital-db 9 :pat2)
;(entity-at @hospital-db :pat1 9)


class Object
  def describe(description, &block)
    Catechism::DescribeBlock.new(description).instance_eval(&block) if block_given?
  end
end


<?xml version="1.0" encoding="UTF-8"?>
<classpath>
	<classpathentry kind="src" path="functionalDB/src"/>
	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
	<classpathentry kind="output" path="functionalDB/bin"/>
</classpath>


import sys
import logging
from network import Node

# Remove from final copy:
#  - logging

class Member(Node):

    def __init__(self, execute_fn):
        Node.__init__(self)
        self.execute_fn = execute_fn

    def start(self, initial_value=None):
        self.state = initial_value
        self.run()

    def invoke(self, input):
        self.state, output = self.execute_fn(self.state, input)
        return output

    def do_INVOKE(self, input, caller):
        self.send([caller], 'INVOKED', output=self.invoke(input))

def sequence_generator(state, input):
    return state + input, range(state, state + input)

if __name__ == "__main__":
    logging.basicConfig(
        format="%(asctime)s %(name)s %(message)s", level=logging.DEBUG)
    member = Member(sequence_generator)
    print member.address
    member.start(initial_value=0)

# tests

import unittest
import threading

class FakeClient(Node):

    def do_INVOKED(self, output):
        self.output = output
        self.stop()

class MemberTests(unittest.TestCase):

    def test_invoke(self):
        member = Member(sequence_generator)
        client = FakeClient()
        client.member = member
        memberthd = threading.Thread(target=member.start, args=(0,))
        memberthd.daemon = 1
        memberthd.start()
        client.send([member.address], 'INVOKE', input=5, caller=client.address)
        client.run()
        self.assertEqual(client.output, [0, 1, 2, 3, 4])


(add-patient :pat1 "London" ["fever" "cough"] )

(add-patient :pat2 "London" ["fever" "cough"] )

(add-test-results-to-patient :pat1  (make-test :t2-pat1  {:test/bp-systolic 170 :test/bp-diastolic 80 :test/machine "XXX"} {:test/machine "string"} ))

(add-test-results-to-patient :pat2  (make-test :t4-pat1  {:test/bp-systolic 170 :test/bp-diastolic 90 :test/machine "XYY"} {:test/machine "string"} ))

(transact hospital-db (update-datom :pat1 :patient/symptoms #{"cold sweat" "sneeze"} :db/reset-to))

(transact hospital-db (update-datom :pat1 :patient/tests #{:t2-pat1} :db/remove))

keep keep keep replace replace keep keep keep

(add-test-results-to-patient :pat1  (make-test :t2-pat1  {:test/bp-systolic 170 :test/bp-diastolic 80 :test/machine :2machine2 } {:test/machine :db/ref} ))

(add-test-results-to-patient :pat2  (make-test :t4-pat2  {:test/bp-systolic 170 :test/bp-diastolic 90 :test/machine :1machine1} {:test/machine :db/ref} ))

(add-test-results-to-patient :pat2  (make-test :t3-pat2  {:test/bp-systolic 140 :test/bp-diastolic 80 :test/machine :2machine2} {:test/machine :db/ref} ))


import sys, os, BaseHTTPServer

class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

    # Root of files being served.
    Root_Directory = None

    # Is debugging output on?
    Debug = False

    # HTTP error codes.
    ERR_NO_PERM   = 403
    ERR_NOT_FOUND = 404
    ERR_INTERNAL  = 500

    # How to display a single item in a directory listing.
    Listing_Item = "
%s
"

    # How to display a whole page of listings.
    Listing_Page = """\

Listing for %(path)s

        %(filler)s

        """

    # Classify and handle request.
    def do_GET(self):

        self.log("path is '%s'" % self.path)

        # Handle any errors that arise.
        try:

            # Class not yet initialized.
            if self.Root_Directory is None:
                self.err_internal("Root directory not set")
                return

            # Figure out what exactly is being requested.
            abs_path = self.create_abs_path()
            self.log("abs_path is '%s'" % abs_path)

            # It isn't below the root path.
            if not self.is_parent_dir(self.Root_Directory, abs_path):
                self.log("abs_path not below root directory")
                msg = "Path '%s' not below root directory '%s'" % \
                      (abs_path, self.Root_Directory)
                self.err_no_perm(msg)

            # It doesn't exist.
            elif not os.path.exists(abs_path):
                self.log("abs_path doesn't exist")
                self.err_not_found(abs_path)

            # It's a file.
            elif os.path.isfile(abs_path):
                self.log("abs_path is a file")
                self.handle_file(abs_path)

            # It's a directory.
            elif os.path.isdir(abs_path):
                self.log("abs_path is a directory")
                self.handle_dir(abs_path)

            # ...we can't tell.
            else:
                self.log("can't tell what abs_path is")
                self.err_not_found(abs_path)

        # Handle general errors.
        except Exception, msg:
            self.err_internal("Unexpected exception: %s" % msg)

    def create_abs_path(self):
        head = os.path.abspath(self.Root_Directory)
        result = os.path.normpath(head + self.path)
        return result

    def is_parent_dir(self, left, right):
        return os.path.commonprefix([left, right]) == left

    def handle_file(self, abs_path):
        try:
            input = file(abs_path, "r")
            content = input.read()
            input.close()
            self.send_content(content)
        except IOError, msg:
            msg = "'%s' cannot be read: %s" % (self.path, msg)
            self.err_no_perm(msg)

    def handle_dir(self, abs_path):
        try:
            listing = os.listdir(abs_path)
            filler = '\n'.join([(self.Listing_Item % item) for item in listing])
            content = self.Listing_Page % {'path'   : self.path,
                                           'filler' : filler}
            self.send_content(content)
        except IOError, msg:
            msg = "'%s' cannot be listed: %s" % (self.path, msg)
            self.send_error(ERR_NO_PERM, msg)

    # Send actual content.
    def send_content(self, content):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.send_header("Content-Length", str(len(content)))
        self.end_headers()
        self.wfile.write(content)

    # Report internal errors.
    def err_internal(self, msg):
        self.send_error(self.ERR_INTERNAL, msg)

    # Handle missing object errors.
    def err_not_found(self, abs_path):
        self.send_error(self.ERR_NOT_FOUND, "'%s' not found" % self.path)

    # Handle no permission errors.
    def err_no_perm(self, msg):
        self.send_error(self.ERR_NO_PERM, msg)

    # Write a log message if in debugging mode
    def log(self, msg):
        if self.Debug:
            print msg

#----------------------------------------------------------------------

if __name__ == '__main__':

    # Main libraries
    import getopt

    # How to use
    Usage = "server.py [-v] root_directory"

    # Handle command-line arguments
    options, rest = getopt.getopt(sys.argv[1:], "v")

    for (flag, arg) in options:
        if flag == "-v":
            RequestHandler.Debug = True
        else:
            print >> sys.stderr, Usage
            sys.exit(1)

    if not rest:
        print >> sys.stderr, Usage
        sys.exit(1)
    root = os.path.abspath(rest[0])
    if not os.path.isdir(root):
        print >> sys.stderr, "No such directory '%s'" % root
        sys.exit(1)
    RequestHandler.Root_Directory = root

    # Create and run server.
    server_address = ('', 8080)
    server = BaseHTTPServer.HTTPServer(server_address, RequestHandler)
    server.serve_forever()


class Catechism::ItBlock < Struct.new(:description, :current_context)
  def expect(subject = nil, &block)
    subject = block if block_given?
    Catechism::SubjectWrapper.new(subject)
  end
end


all : commands

## commands : show all commands
commands :
	@grep -E '^##' Makefile | sed -e 's/## //g'

## check    : build locally into _site directory for checking
check :
	jekyll -t build -d _site

## clean    : clean up
clean :
	rm -rf _site $$(find . -name '*~' -print)


(evolution-of (M/db-from-conn hospital-db) :pat1 :patient/tests)

(take 4 (traverse-db  :pat2 @hospital-db (:curr-time @hospital-db) :bfs))

(traverse-db  :pat2 @hospital-db :bfs :outgoing))


require 'thor'

class Catechism::Cli < Thor
  desc 'run_trial TRIAL', 'Run the given trial'
  def run_trial(trial_path)
    Kernel.system("bundle exec ruby #{trial_path}") && puts("#{trial_path} was successful.")
  end

  desc 'run_all_trials', 'Run all trials in the current path'
  def run_all_trials
    Dir.glob('trials/**/*_trial.rb') { |trial_path| run_trial(trial_path) }
  end

  default_task :run_all_trials
end


---
---
<!DOCTYPE html>

    {% include header.html %}

{{page.title}}

          {{content}}

      {% include footer.html %}


Catechism
=========

Catechism is a very small test framework for Ruby.

Prerequisites
-------------

* Ruby 2.0.0
* A Unix environment

Installation
------------

Add this line to your application's Gemfile:

    gem 'catechism'

And then execute:

    $ bundle

Or install it yourself as:

    $ gem install catechism

Usage
-----

Create a `trials` directory in the root of your project.

Create files in any path underneath it ending in `_trial.rb`.  Examples can be found in `trials/lib/catechism`.

Then, run your test suite:

    $ catechism

Contributing
------------

1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request


{application, torrent_client,
 [
  {description, ""},
  {vsn, "1"},
  {registered, []},
  {applications, [
                  kernel,
                  stdlib
                 ]},
  {mod, { torrent_client, []}},
  {env, []}
 ]}.


require 'catechism'

describe Catechism::Cli do
end


this.shouldComponentUpdate = _props => {

import { setupRerender } from 'preact/test-utils';
import { createElement as h, render, Component, createContext } from '../../src/index';
import { setupScratch, teardown } from '../_util/helpers';
import { Fragment } from '../../src';
import { i as ctxId } from '../../src/create-context';

/** @jsx h */

describe('createContext', () => {
	let scratch;
	let rerender;

	beforeEach(() => {
		scratch = setupScratch();
		rerender = setupRerender();
	});

	afterEach(() => {
		teardown(scratch);
	});

	it('should pass context to a consumer', () => {
		const { Provider, Consumer } = createContext();
		const CONTEXT = { a: 'a' };

		class Inner extends Component {
			render(props) {
				return
{props.a}
;
			}
		}

		sinon.spy(Inner.prototype, 'render');

		render(<Provider value={CONTEXT}>

				<Consumer>
					{data => <Inner {...data} />}
				</Consumer>

		</Provider>, scratch);

		// initial render does not invoke anything but render():
		expect(Inner.prototype.render).to.have.been.calledWithMatch(CONTEXT, {},  { ['__cC' + (ctxId - 1)]: {} });
		expect(scratch.innerHTML).to.equal('

a

');
	});

	it('should preserve provider context through nesting providers', (done) => {
		const { Provider, Consumer } = createContext();
		const CONTEXT = { a: 'a' };
		const CHILD_CONTEXT = { b: 'b' };

		class Inner extends Component {
			render(props) {
				return
{props.a} - {props.b}
;
			}
		}

		sinon.spy(Inner.prototype, 'render');

		render(<Provider value={CONTEXT}>
			<Consumer>
				{data =>
					(<Provider value={CHILD_CONTEXT}>
						<Consumer>
							{childData => <Inner {...data} {...childData} />}
						</Consumer>
					</Provider>)
				}
			</Consumer>
		</Provider>, scratch);

		// initial render does not invoke anything but render():
		expect(Inner.prototype.render).to.have.been.calledWithMatch({ ...CONTEXT, ...CHILD_CONTEXT }, {}, { ['__cC' + (ctxId - 1)]: {} });
		expect(Inner.prototype.render).to.be.calledOnce;
		expect(scratch.innerHTML).to.equal('
a - b
');
		setTimeout(() => {
			expect(Inner.prototype.render).to.be.calledOnce;
			done();
		}, 0);
	});

	it('should preserve provider context between different providers', () => {
		const { Provider: ThemeProvider, Consumer: ThemeConsumer } = createContext();
		const { Provider: DataProvider, Consumer: DataConsumer } = createContext();
		const THEME_CONTEXT = { theme: 'black' };
		const DATA_CONTEXT = { global: 'a' };

		class Inner extends Component {
			render(props) {
				return
{props.theme} - {props.global}
;
			}
		}

		sinon.spy(Inner.prototype, 'render');

		render(<ThemeProvider value={THEME_CONTEXT.theme}>
			<DataProvider value={DATA_CONTEXT}>
				<ThemeConsumer>
					{theme => (<DataConsumer>
						{data => <Inner theme={theme} {...data} />}
					</DataConsumer>)}
				</ThemeConsumer>
			</DataProvider>
		</ThemeProvider>, scratch);

		// initial render does not invoke anything but render():
		expect(Inner.prototype.render).to.have.been.calledWithMatch({ ...THEME_CONTEXT, ...DATA_CONTEXT }, {}, { ['__cC' + (ctxId - 1)]: {} });
		expect(scratch.innerHTML).to.equal('
black - a
');
	});

	it('should preserve provider context through nesting consumers', () => {
		const { Provider, Consumer } = createContext();
		const CONTEXT = { a: 'a' };

		class Inner extends Component {
			render(props) {
				return
{props.a}
;
			}
		}

		sinon.spy(Inner.prototype, 'render');

		render(<Provider value={CONTEXT}>
			<Consumer>
				{data =>
					(<Consumer>
						{childData => <Inner {...data} {...childData} />}
					</Consumer>)
				}
			</Consumer>
		</Provider>, scratch);

		// initial render does not invoke anything but render():
		expect(Inner.prototype.render).to.have.been.calledWithMatch({ ...CONTEXT }, {}, { ['__cC' + (ctxId - 1)]: {} });
		expect(scratch.innerHTML).to.equal('
a
');
	});

	it('should not emit when value does not update', () => {
		const { Provider, Consumer } = createContext();
		const CONTEXT = { a: 'a' };

		class NoUpdate extends Component {
			shouldComponentUpdate() {
				return false;
			}

			render() {
				return this.props.children;
			}
		}

		class Inner extends Component {
			render(props) {
				return
{props.a}
;
			}
		}

		sinon.spy(Inner.prototype, 'render');

		render(

				<Provider value={CONTEXT}>
					<NoUpdate>
						<Consumer>
							{data => <Inner {...data} />}
						</Consumer>
					</NoUpdate>
				</Provider>

, scratch);

		expect(Inner.prototype.render).to.have.been.calledOnce;

		render(

				<Provider value={CONTEXT}>
					<NoUpdate>
						<Consumer>
							{data => <Inner {...data} />}
						</Consumer>
					</NoUpdate>
				</Provider>

, scratch);

		expect(Inner.prototype.render).to.have.been.calledOnce;
	});

	it('should preserve provider context through nested components', () => {
		const { Provider, Consumer } = createContext();
		const CONTEXT = { a: 'a' };

		class Consumed extends Component {
			render(props) {
				return {props.a};
			}
		}

		sinon.spy(Consumed.prototype, 'render');

		class Outer extends Component {
			render() {
				return
<Inner />
;
			}
		}

		class Inner extends Component {
			render() {
				return (
					<Fragment>
						<InnerMost />
					</Fragment>
				);
			}
		}

		class InnerMost extends Component {
			render() {
				return (

						<Consumer>
							{data => <Consumed {...data} />}
						</Consumer>

				);
			}
		}

		render((
			<Provider value={CONTEXT}>
				<Outer />
			</Provider>
		), scratch);

		// initial render does not invoke anything but render():
		expect(Consumed.prototype.render).to.have.been.calledWithMatch({ ...CONTEXT }, {}, { ['__cC' + (ctxId - 1)]: {} });
		expect(scratch.innerHTML).to.equal('

a

');
	});

	it('should propagates through shouldComponentUpdate false', done => {
		const { Provider, Consumer } = createContext();
		const CONTEXT = { a: 'a' };
		const UPDATED_CONTEXT = { a: 'b' };

		class Consumed extends Component {
			render(props) {
				return {props.a};
			}
		}

		sinon.spy(Consumed.prototype, 'render');

		class Outer extends Component {
			render() {
				return
<Inner />
;
			}
		}

		class Inner extends Component {
			shouldComponentUpdate() {
				return false;
			}

			render() {
				return (
					<Fragment>
						<InnerMost />
					</Fragment>
				);
			}
		}

		class InnerMost extends Component {
			render() {
				return (

						<Consumer>
							{data => <Consumed {...data} />}
						</Consumer>

				);
			}
		}

		class App extends Component {
			render() {
				return (
					<Provider value={this.props.value}>
						<Outer />
					</Provider>
				);
			}
		}

		render((
			<App value={CONTEXT} />
		), scratch);
		expect(scratch.innerHTML).to.equal('

a

');
		expect(Consumed.prototype.render).to.have.been.calledOnce;

		render((
			<App value={UPDATED_CONTEXT} />
		), scratch);

		rerender();

		// initial render does not invoke anything but render():
		expect(Consumed.prototype.render).to.have.been.calledTwice;
		// expect(Consumed.prototype.render).to.have.been.calledWithMatch({ ...UPDATED_CONTEXT }, {}, { ['__cC' + (ctxId - 1)]: {} });
		expect(scratch.innerHTML).to.equal('

b

');
		setTimeout(() => {
			expect(Consumed.prototype.render).to.have.been.calledTwice;
			done();
		});
	});

	it('should keep the right context at the right "depth"', () => {
		const { Provider, Consumer } = createContext();
		const CONTEXT = { theme: 'a', global: 1 };
		const NESTED_CONTEXT = { theme: 'b', global: 1 };

		class Inner extends Component {
			render(props) {
				return
{props.theme} - {props.global}
;
			}
		}
		class Nested extends Component {
			render(props) {
				return
{props.theme} - {props.global}
;
			}
		}

		sinon.spy(Inner.prototype, 'render');
		sinon.spy(Nested.prototype, 'render');

		render((
			<Provider value={CONTEXT}>
				<Provider value={NESTED_CONTEXT}>
					<Consumer>
						{data => <Nested {...data} />}
					</Consumer>
				</Provider>
				<Consumer>
					{data => <Inner {...data} />}
				</Consumer>
			</Provider>
		), scratch);

		// initial render does not invoke anything but render():
		expect(Nested.prototype.render).to.have.been.calledWithMatch({ ...NESTED_CONTEXT }, {}, { ['__cC' + (ctxId - 1)]: {} });
		expect(Inner.prototype.render).to.have.been.calledWithMatch({ ...CONTEXT }, {}, { ['__cC' + (ctxId - 1)]: {} });

		expect(scratch.innerHTML).to.equal('
b - 1

a - 1
');
	});

	it('should not re-render the consumer if the context doesn\'t change', () => {
		const { Provider, Consumer } = createContext();
		const CONTEXT = { i: 1 };

		class NoUpdate extends Component {
			shouldComponentUpdate() {
				return false;
			}

			render() {
				return this.props.children;
			}
		}

		class Inner extends Component {
			render(props) {
				console.log('rendering', props.i);
				return
{props.i}
;
			}
		}

		sinon.spy(Inner.prototype, 'render');

		render(
			<Provider value={CONTEXT}>
				<NoUpdate>
					<Consumer>
						{data => <Inner {...data} />}
					</Consumer>
				</NoUpdate>
			</Provider>,
			scratch
		);

		render(
			<Provider value={CONTEXT}>
				<NoUpdate>
					<Consumer>{data => <Inner {...data} />}</Consumer>
				</NoUpdate>
			</Provider>,
			scratch
		);

		// Rendered twice, should called just one 'Consumer' render
		expect(Inner.prototype.render).to.have.been.calledOnce.and.calledWithMatch(CONTEXT, {},  { ['__cC' + (ctxId - 1)]: {} });
		expect(scratch.innerHTML).to.equal('
1
');

		render(
			<Provider value={{ i: 2 }}>
				<NoUpdate>
					<Consumer>{data => <Inner {...data} />}</Consumer>
				</NoUpdate>
			</Provider>,
			scratch
		);

		// Rendered three times, should call 'Consumer' render two times
		// Logged these things I think we're dealing with another stale dom issue due to NoUpdate... :/
		expect(Inner.prototype.render).to.have.been.calledTwice.and.calledWithMatch({ i: 2 }, {},  { ['__cC' + (ctxId - 1)]: {} });
		expect(scratch.innerHTML).to.equal('
2
');
	});

	it('should allow for updates of props', () => {
		let set;
		const MyContext = createContext();
		class App extends Component {
			constructor(props) {
				super(props);
				this.state = {
					x: 'y'
				};
				set = this.setState.bind(this);
				this.renderInner = this.renderInner.bind(this);
			}

			renderInner() {
				return
{this.state.x}
;
			}

			render() {
				return (
					<MyContext.Provider value="irrelevant">
						<MyContext.Consumer>
							{this.renderInner}
						</MyContext.Consumer>
					</MyContext.Provider>
				);
			}
		}

		render(<App />, scratch);
		expect(scratch.innerHTML).to.equal('
y
');

		set({ x: 'x' });
		rerender();
		expect(scratch.innerHTML).to.equal('
x
');
	});

	it('should re-render the consumer if the children change', () => {
		const { Provider, Consumer } = createContext();
		const CONTEXT = { i: 1 };

		class Inner extends Component {
			render(props) {
				return
{props.i}
;
			}
		}

		sinon.spy(Inner.prototype, 'render');

		render(
			<Provider value={CONTEXT}>
				<Consumer>
					{data => <Inner {...data} />}
				</Consumer>
			</Provider>,
			scratch
		);

		render(
			<Provider value={CONTEXT}>
				<Consumer>
					{data => <Inner {...data} />}
				</Consumer>
			</Provider>,
			scratch
		);

		// Rendered twice, with two different children for consumer, should render twice
		expect(Inner.prototype.render).to.have.been.calledTwice;
		expect(scratch.innerHTML).to.equal('
1
');
	});

	describe('class.contextType', () => {
		it('should use default value', () => {
			const ctx = createContext('foo');

			let actual;
			class App extends Component {
				render() {
					actual = this.context;
					return
bar
;
				}
			}

			App.contextType = ctx;

			render(<App />, scratch);
			expect(actual).to.deep.equal('foo');
		});

		it('should use the value of the nearest Provider', () => {
			const ctx = createContext('foo');

			let actual;
			class App extends Component {
				render() {
					actual = this.context;
					return
bar
;
				}
			}

			App.contextType = ctx;
			const Provider = ctx.Provider;

			render((
				<Provider value="bar">
					<Provider value="bob">
						<App />
					</Provider>
				</Provider>
			), scratch);
			expect(actual).to.deep.equal('bob');
		});

		it('should restore legacy context for children', () => {
			const Foo = createContext('foo');
			const spy = sinon.spy();

			class NewContext extends Component {
				render() {
					return
{this.props.children}
;
				}
			}

			class OldContext extends Component {
				getChildContext() {
					return { foo: 'foo' };
				}

				render() {
					return
{this.props.children}
;
				}
			}

			class Inner extends Component {
				render() {
					spy(this.context);
					return
Inner
;
				}
			}

			NewContext.contextType = Foo;

			render((
				<Foo.Provider value="bar">
					<OldContext>
						<NewContext>
							<Inner />
						</NewContext>
					</OldContext>
				</Foo.Provider>
			), scratch);

			expect(spy).to.be.calledWithMatch({ foo: 'foo' });
		});

		it('should call componentWillUnmount', () => {
			let Foo = createContext('foo');
			let spy = sinon.spy();

			let instance;
			class App extends Component {
				constructor(props) {
					super(props);
					instance = this;
				}

				componentWillUnmount() {
					spy(this);
				}

				render() {
					return
;
				}
			}

			App.contextType = Foo;

			render((
				<Foo.Provider value="foo">
					<App />
				</Foo.Provider>
			), scratch);

			render(null, scratch);

			expect(spy).to.be.calledOnce;
			expect(spy.getCall(0).args[0]).to.equal(instance);
		});
	});
});


import { setupRerender } from 'preact/test-utils';
import { setupScratch, teardown } from '../../../test/_util/helpers';
import { Component, render, createElement as h, memo } from '../../src';

/** @jsx h */

describe('memo()', () => {
	let scratch, rerender;

	beforeEach(() => {
		scratch = setupScratch();
		rerender = setupRerender();
	});

	afterEach(() => {
		teardown(scratch);
	});

	it('should have isReactComponent flag', () => {
		let App = memo(() =>
foo
);
		expect(App.prototype.isReactComponent).to.equal(true);
	});

	it('should work with function components', () => {
		let spy = sinon.spy();

		function Foo() {
			spy();
			return
Hello World
;
		}

		let Memoized = memo(Foo);

		let update;
		class App extends Component {
			constructor() {
				super();
				update = () => this.setState({});
			}
			render() {
				return <Memoized />;
			}
		}
		render(<App />, scratch);

		expect(spy).to.be.calledOnce;

		update();
		rerender();

		expect(spy).to.be.calledOnce;
	});

	it('should support adding refs', () => {
		let spy = sinon.spy();

		let ref = null;

		function Foo() {
			spy();
			return
Hello World
;
		}

		let Memoized = memo(Foo);

		let update;
		class App extends Component {
			constructor() {
				super();
				update = () => this.setState({});
			}
			render() {
				return <Memoized ref={ref} />;
			}
		}
		render(<App />, scratch);

		expect(spy).to.be.calledOnce;

		ref = {};

		update();
		rerender();

		expect(ref.current).not.to.be.undefined;

		// TODO: not sure whether this is in-line with react...
		expect(spy).to.be.calledTwice;
	});

	it('should support custom comparer functions', () => {
		function Foo() {
			return
Hello World
;
		}

		let spy = sinon.spy(() => true);
		let Memoized = memo(Foo, spy);

		let update;
		class App extends Component {
			constructor() {
				super();
				update = () => this.setState({});
			}
			render() {
				return <Memoized />;
			}
		}
		render(<App />, scratch);

		update();
		rerender();

		expect(spy).to.be.calledOnce;
		expect(spy).to.be.calledWith({}, {});
	});

	it('should rerender when custom comparer returns false', () => {
		const spy = sinon.spy();
		function Foo() {
			spy();
			return
Hello World
;
		}

		const App = memo(Foo, () => false);
		render(<App />, scratch);
		expect(spy).to.be.calledOnce;

		render(<App foo="bar" />, scratch);
		expect(spy).to.be.calledTwice;
	});

	it('should pass props and nextProps to comparer fn', () => {
		const spy = sinon.spy(() => false);
		function Foo() {
			return
foo
;
		}

		const props = { foo: true };
		const nextProps = { foo: false };
		const App = memo(Foo, spy);
		render(h(App, props), scratch);
		render(h(App, nextProps), scratch);

		expect(spy).to.be.calledWith(props, nextProps);
	});

	it('should nest without errors', () => {
		const Foo = () =>
foo
;
		const App = memo(memo(Foo));

		// eslint-disable-next-line prefer-arrow-callback
		expect(function() {
			render(<App />, scratch);
		}).to.not.throw();
	});
});


/* eslint-disable */
var renderToString
try {
	renderToString = dep(require('preact-render-to-string'));
} catch (e) {
	throw new Error(
		'You seem to be missing the "preact-render-to-string" dependency.\n' +
		'You can add this by using "npm install --save preact-render-to-string@next".'
	)
}

function dep(obj) { return obj['default'] || obj; }

module.exports = {
	renderToString: renderToString,
	renderToStaticMarkup: renderToString
};


import { enqueueRender } from './component';

export let i = 0;

/**
 *
 * @param {any} defaultValue
 */
export function createContext(defaultValue) {
	const ctx = {};

	const context = {
		_id: '__cC' + i++,
		_defaultValue: defaultValue,
		Consumer(props, context) {
			return props.children(context);
		},
		Provider(props) {
			if (!this.getChildContext) {
				const subs = [];
				this.getChildContext = () => {
					ctx[context._id] = this;
					return ctx;
				};
				this.shouldComponentUpdate = _props => {
					if (props.value !== _props.value) {
						subs.some(c => {
							// Check if still mounted
							if (c._parentDom) {
								c.context = props.value;
								enqueueRender(c);
							}
						});
					}
				};
				this.sub = (c) => {
					subs.push(c);
					let old = c.componentWillUnmount;
					c.componentWillUnmount = () => {
						subs.splice(subs.indexOf(c), 1);
						old && old.call(c);
					};
				};
			}
			return props.children;
		}
	};

	context.Consumer.contextType = context;

	return context;
}


import React, {
	render,
	createElement,
	cloneElement,
	findDOMNode,
	Component,
	unmountComponentAtNode,
	createFactory,
	unstable_batchedUpdates
} from '../../src';
import { createElement as preactH } from 'preact';
import { setupScratch, teardown, createEvent } from '../../../test/_util/helpers';

let ce = type => document.createElement(type);
let text = text => document.createTextNode(text);

describe('preact-compat', () => {

	/** @type {HTMLDivElement} */
	let scratch, proto;

	beforeEach(() => {
		scratch = setupScratch();
		proto = document.createElement('div').constructor.prototype;
		sinon.spy(proto, 'addEventListener');
		sinon.spy(proto, 'removeEventListener');
	});

	afterEach(() => {
		proto.addEventListener.restore();
		proto.removeEventListener.restore();
		teardown(scratch);
	});

	describe('render()', () => {
		it('should be exported', () => {
			expect(React)
				.to.have.property('render')
				.that.is.a('function')
				.that.equals(render);
		});

		it('should replace isomorphic content', () => {
			let root = ce('div');
			let initialChild = ce('div');
			initialChild.appendChild(text('initial content'));
			root.appendChild(initialChild);

			render(
dynamic content
, root);
			expect(root)
				.to.have.property('textContent')
				.that.is.a('string')
				.that.equals('dynamic content');
		});

		it('should remove extra elements', () => {
			let root = ce('div');
			let inner = ce('div');

			root.appendChild(inner);

			let c1 = ce('div');
			c1.appendChild(text('isomorphic content'));
			inner.appendChild(c1);

			let c2 = ce('div');
			c2.appendChild(text('extra content'));
			inner.appendChild(c2);

			render(
dynamic content
, root);
			expect(root)
				.to.have.property('textContent')
				.that.is.a('string')
				.that.equals('dynamic content');
		});

		// Note: Replacing text nodes inside the root itself is currently unsupported.
		// We do replace them everywhere else, though.
		it('should remove text nodes', () => {
			let root = ce('div');

			let div = ce('div');
			root.appendChild(div);
			div.appendChild(text('Text Content'));
			div.appendChild(text('More Text Content'));

			render(
dynamic content
, root);
			expect(root)
				.to.have.property('textContent')
				.that.is.a('string')
				.that.equals('dynamic content');
		});

		it('should support onAnimationEnd', () => {
			const func = () => { };
			render(
, scratch);

			expect(proto.addEventListener).to.have.been.calledOnce
				.and.to.have.been.calledWithExactly('animationend', sinon.match.func, false);

			expect(scratch.firstChild._listeners).to.deep.equal({
				animationend: func
			});

			render(
, scratch);
			expect(proto.removeEventListener).to.have.been.calledOnce
				.and.to.have.been.calledWithExactly('animationend', sinon.match.func, false);
		});

		it('should support onTransitionEnd', () => {
			const func = () => { };
			render(
, scratch);

			expect(proto.addEventListener).to.have.been.calledOnce
				.and.to.have.been.calledWithExactly('transitionend', sinon.match.func, false);

			expect(scratch.firstChild._listeners).to.deep.equal({
				transitionend: func
			});

			render(
, scratch);
			expect(proto.removeEventListener).to.have.been.calledOnce
				.and.to.have.been.calledWithExactly('transitionend', sinon.match.func, false);
		});

		it('should support defaultValue', () => {
			render(<input defaultValue="foo" />, scratch);
			expect(scratch.firstElementChild).to.have.property('value', 'foo');
		});

		it('should ignore defaultValue when value is 0', () => {
			render(<input defaultValue={2} value={0} />, scratch);
			expect(scratch.firstElementChild.value).to.equal('0');
		});

		it('should call the callback', () => {
			let spy = sinon.spy();
			render(
, scratch, spy);
			expect(spy).to.be.calledOnce;
			expect(spy).to.be.calledWithExactly();
		});

		// Issue #1727
		it('should destroy the any existing DOM nodes inside the container', () => {
			scratch.appendChild(document.createElement('div'));
			scratch.appendChild(document.createElement('div'));

			render(foo, scratch);
			expect(scratch.innerHTML).to.equal('foo');
		});

		it('should only destroy existing DOM nodes on first render', () => {
			scratch.appendChild(document.createElement('div'));
			scratch.appendChild(document.createElement('div'));

			render(<input />, scratch);

			let child = scratch.firstChild;
			child.focus();
			render(<input />, scratch);
			expect(document.activeElement.nodeName).to.equal('INPUT');
		});
	});

	describe('createFactory', () => {
		it('should create a DOM element', () => {
			render(createFactory('span')({ class: 'foo' }, '1'), scratch);
			expect(scratch.innerHTML).to.equal('1');
		});

		it('should create a component', () => {
			const Foo = ({ id, children }) =>
foo {children}
;
			render(createFactory(Foo)({ id: 'value' }, 'bar'), scratch);
			expect(scratch.innerHTML).to.equal('
foo bar
');
		});
	});

	describe('createElement()', () => {
		it('should be exported', () => {
			expect(React)
				.to.have.property('createElement')
				.that.is.a('function')
				.that.equals(createElement);
		});

		it('should normalize vnodes', () => {
			let vnode =
t
;
			let $$typeof = 0xeac7;
			try {
				// eslint-disable-next-line
				if (Function.prototype.toString.call(eval('Sym' + 'bol.for')).match(/\[native code\]/)) {
					// eslint-disable-next-line
					$$typeof = eval('Sym' + 'bol.for("react.element")');
				}
			}
			catch (e) { }
			expect(vnode).to.have.property('$$typeof', $$typeof);
			expect(vnode).to.have.property('type', 'div');
			expect(vnode).to.have.property('props').that.is.an('object');
			expect(vnode.props).to.have.property('children');
			expect(vnode.props.children).to.have.property('$$typeof', $$typeof);
			expect(vnode.props.children).to.have.property('type', 'a');
			expect(vnode.props.children).to.have.property('props').that.is.an('object');
			expect(vnode.props.children.props).to.eql({ children: 't' });
		});

		it('should normalize onChange', () => {
			let props = { onChange() { } };

			function expectToBeNormalized(vnode, desc) {
				expect(vnode, desc)
					.to.have.property('props')
					.with.all.keys(['oninput'].concat(vnode.props.type ? 'type' : []))
					.and.property('oninput').that.is.a('function');
			}

			function expectToBeUnmodified(vnode, desc) {
				expect(vnode, desc).to.have.property('props').eql({
					...props,
					...(vnode.props.type ? { type: vnode.props.type } : {})
				});
			}

			expectToBeUnmodified(
, '
');
			expectToBeUnmodified(<input {...props} type="radio" />, '<input type="radio">');
			expectToBeUnmodified(<input {...props} type="checkbox" />, '<input type="checkbox">');
			expectToBeUnmodified(<input {...props} type="file" />, '<input type="file">');

			expectToBeNormalized(<textarea {...props} />, '<textarea>');
			expectToBeNormalized(<input {...props} />, '<input>');
			expectToBeNormalized(<input {...props} type="text" />, '<input type="text">');

		});

		it('should normalize beforeinput event listener', () => {
			let spy = sinon.spy();
			render(<input onBeforeInput={spy} />, scratch);
			scratch.firstChild.dispatchEvent(createEvent('beforeinput'));
			expect(spy).to.be.calledOnce;
		});
	});

	describe('Component', () => {
		it('should be exported', () => {
			expect(React)
				.to.have.property('Component')
				.that.is.a('function')
				.that.equals(Component);
		});
	});

	describe('cloneElement', () => {
		it('should clone elements', () => {
			let element = <foo a="b" c="d">ab</foo>;
			expect(cloneElement(element)).to.eql(element);
		});

		it('should support props.children', () => {
			let element = <foo children={b} />;
			let clone = cloneElement(element);
			expect(clone).to.eql(element);
			expect(cloneElement(clone).props.children).to.eql(element.props.children);
		});

		it('children take precedence over props.children', () => {
			let element = <foo children={c}>
b
</foo>;
			let clone = cloneElement(element);
			expect(clone).to.eql(element);
			expect(clone.props.children.type).to.eql('div');
		});

		it('should support children in prop argument', () => {
			let element = <foo />;
			let children = [b];
			let clone = cloneElement(element, { children });
			expect(clone.props.children).to.eql(children);
		});

		it('children argument takes precedence over props.children', () => {
			let element = <foo />;
			let childrenA = [b];
			let childrenB = [
c
];
			let clone = cloneElement(element, { children: childrenA }, ...childrenB);
			expect(clone.props.children).to.eql(childrenB);
		});

		it('children argument takes precedence over props.children even if falsey', () => {
			let element = <foo />;
			let childrenA = [b];
			let clone = cloneElement(element, { children: childrenA }, undefined);
			expect(clone.children).to.eql(undefined);
		});

		it('should skip cloning on invalid element', () => {
			let element = { foo: 42 };
			let clone = cloneElement(element);
			expect(clone).to.eql(element);
		});

		it('should work with jsx constructor from core', () => {
			function Foo(props) {
				return
{props.value}
;
			}

			let clone = cloneElement(preactH(Foo), { value: 'foo' });
			render(clone, scratch);
			expect(scratch.textContent).to.equal('foo');
		});
	});

	describe('findDOMNode()', () => {
		class Helper extends React.Component {
			render({ something }) {
				if (something == null) return null;
				if (something === false) return null;
				return
;
			}
		}

		it.skip('should return DOM Node if render is not false nor null', () => {
			const helper = React.render(<Helper />, scratch);
			expect(findDOMNode(helper)).to.be.instanceof(Node);
		});

		it('should return null if given null', () => {
			expect(findDOMNode(null)).to.be.null;
		}),

		it('should return a regular DOM Element if given a regular DOM Element', () => {
			let scratch = document.createElement('div');
			expect(findDOMNode(scratch)).to.equalNode(scratch);
		}),

		// NOTE: React.render() returning false or null has the component pointing
		// 			to no DOM Node, in contrast, Preact always render an empty Text DOM Node.
		it('should return null if render returns false', () => {
			const helper = React.render(<Helper something={false} />, scratch);
			expect(findDOMNode(helper)).to.be.null;
		});

		// NOTE: React.render() returning false or null has the component pointing
		// 			to no DOM Node, in contrast, Preact always render an empty Text DOM Node.
		it('should return null if render returns null', () => {
			const helper = React.render(<Helper something={null} />, scratch);
			expect(findDOMNode(helper)).to.be.null;
		});
	});

	describe('unmountComponentAtNode', () => {
		it('should unmount a root node', () => {
			const App = () =>
foo
;
			render(<App />, scratch);

			expect(unmountComponentAtNode(scratch)).to.equal(true);
			expect(scratch.innerHTML).to.equal('');
		});

		it('should do nothing if root is not mounted', () => {
			expect(unmountComponentAtNode(scratch)).to.equal(false);
			expect(scratch.innerHTML).to.equal('');
		});
	});

	describe('unstable_batchedUpdates', () => {
		it('should call the callback', () => {
			const spy = sinon.spy();
			unstable_batchedUpdates(spy);
			expect(spy).to.be.calledOnce;
		});

		it('should call callback with only one arg', () => {
			const spy = sinon.spy();
			unstable_batchedUpdates(spy, 'foo', 'bar');
			expect(spy).to.be.calledWithExactly('foo');
		});
	});

	it('should patch events', () => {
		let spy = sinon.spy();
		render(
, scratch);
		scratch.firstChild.click();

		expect(spy).to.be.calledOnce;
		expect(spy.args[0][0]).to.haveOwnProperty('persist');
		expect(spy.args[0][0]).to.haveOwnProperty('nativeEvent');
	});

	it('should normalize ondoubleclick event', () => {
		let vnode =
 null} />;
		expect(vnode.props).to.haveOwnProperty('ondblclick');
	});

	it('should normalize onChange for textarea', () => {
		let vnode = <textarea onChange={() => null} />;
		expect(vnode.props).to.haveOwnProperty('oninput');
		expect(vnode.props).to.not.haveOwnProperty('onchange');

		vnode = <textarea oninput={() => null} onChange={() => null} />;
		expect(vnode.props).to.haveOwnProperty('oninput');
		expect(vnode.props).to.not.haveOwnProperty('onchange');
	});

	it('should not normalize onChange for range', () => {
		render(<input type="range" onChange={() => null} />, scratch);
		expect(scratch.firstChild._listeners).to.haveOwnProperty('change');
		expect(scratch.firstChild._listeners).to.not.haveOwnProperty('input');
	});

	it('should normalize class+className even on components', () => {
		function Foo(props) {
			return
foo
;
		}
		render(<Foo class="foo" />, scratch);
		expect(scratch.firstChild.className).to.equal('foo');
		render(null, scratch);

		render(<Foo className="foo" />, scratch);
		expect(scratch.firstChild.className).to.equal('foo');
	});
});


module.exports = {
	repo: 'preactjs/preact',
	path: ['./{compat,debug,hooks,}/dist/**/!(*.map)'],
	branch: 'master'
};


/**
 * A helper to generate innerHTML validation strings containing spans
 * @param {string | number} contents The contents of the span, as a string
 */
export const span = contents => `<span>${contents}</span>`;

/**
 * A helper to generate innerHTML validation strings containing divs
 * @param {string | number} contents The contents of the div, as a string
 */
export const div = contents => `<div>${contents}</div>`;

/**
 * A helper to generate innerHTML validation strings containing p
 * @param {string | number} contents The contents of the p, as a string
 */
export const p = contents => `<p>${contents}</p>`;

/**
 * A helper to generate innerHTML validation strings containing sections
 * @param {string | number} contents The contents of the section, as a string
 */
export const section = contents => `<section>${contents}</section>`;

/**
 * A helper to generate innerHTML validation strings containing uls
 * @param {string | number} contents The contents of the ul, as a string
 */
export const ul = contents => `<ul>${contents}</ul>`;

/**
 * A helper to generate innerHTML validation strings containing ols
 * @param {string | number} contents The contents of the ol, as a string
 */
export const ol = contents => `<ol>${contents}</ol>`;

/**
 * A helper to generate innerHTML validation strings containing lis
 * @param {string | number} contents The contents of the li, as a string
 */
export const li = contents => `<li>${contents}</li>`;

/**
 * A helper to generate innerHTML validation strings containing inputs
 */
export const input = () => `<input type="text">`;

/**
 * A helper to generate innerHTML validation strings containing inputs
 * @param {string | number} contents The contents of the h1
 */
export const h1 = contents => `<h1>${contents}</h1>`;

/**
 * A helper to generate innerHTML validation strings containing inputs
 * @param {string | number} contents The contents of the h2
 */
export const h2 = contents => `<h2>${contents}</h2>`;


import { setupScratch, teardown } from '../_util/helpers';

import { i as ctxId } from '../../src/create-context';

import options from '../../src/options';


import { createElement, Component } from "preact";
import { connect, Provider } from "react-redux";
import { createStore } from "redux";
import { HashRouter, Route, Link } from "react-router-dom";

const store = createStore(
	(state, action) => ({ ...state, display: action.display }),
	{ display: false }
);

function _Redux({ showMe, counter }) {
	if (!showMe) return null;
	return
showMe {counter}
;
}
const Redux = connect(
	state => console.log("injecting", state.display) || { showMe: state.display }
)(_Redux);

let display = false;
class Test extends Component {
	componentDidUpdate(prevProps) {
		if (this.props.start != prevProps.start) {
			this.setState({ f: (this.props.start || 0) + 1 });
			setTimeout(() => this.setState({ i: (this.state.i || 0) + 1 }));
		}
	}

	render() {
		const { f } = this.state;
		return (

				<button
					onClick={() => {
						display = !display;
						store.dispatch({ type: 1, display });
					}}
				>
					Toggle visibilty
				</button>
				<Link to={`/${(parseInt(this.props.start) || 0) + 1}`}>Click me</Link>

				<Redux counter={f} />

		);
	}
}

function App() {
	return (
		<Provider store={store}>
			<HashRouter>
				<Route
					path="/:start?"
					render={({ match }) => <Test start={match.params.start || 0} />}
				/>
			</HashRouter>
		</Provider>
	);
}

export default App;


// eslint-disable-next-line no-unused-vars
import { createElement, Component, createContext, Fragment } from "preact";
const { Provider, Consumer } = createContext();

class ThemeProvider extends Component {
	state = {
		value: this.props.value
	};

	onClick = () => {
		this.setState(prev => ({
			value: prev.value===this.props.value ? this.props.next : this.props.value
		}));
	}

	render() {
		return (

				<button onClick={this.onClick}>Toggle</button>
				<Provider value={this.state.value}>{this.props.children}</Provider>

		);
	}
}

class Child extends Component {
	shouldComponentUpdate() {
		return false;
	}

	render() {
		return (
			<>

(blocked update)

				{this.props.children}
			</>
		);
	}
}

export default class ContextDemo extends Component {
	render() {
		return (
			<ThemeProvider value="blue" next="red">
				<Child>
					<Consumer>
						{data => (

current theme: {data}

								<ThemeProvider value="black" next="white">
									<Consumer>
										{data =>
current sub theme: {data}
}
									</Consumer>
								</ThemeProvider>

						)}
					</Consumer>
				</Child>
			</ThemeProvider>
		);
	}
}


import { diff, unmount, applyRef } from './index';
import { coerceToVNode } from '../create-element';
import { EMPTY_OBJ, EMPTY_ARR } from '../constants';
import { removeNode } from '../util';
import { getDomSibling } from '../component';

/**
 * Diff the children of a virtual node
 * @param {import('../internal').PreactElement} parentDom The DOM element whose
 * children are being diffed
 * @param {import('../internal').VNode} newParentVNode The new virtual
 * node whose children should be diff'ed against oldParentVNode
 * @param {import('../internal').VNode} oldParentVNode The old virtual
 * node whose children should be diff'ed against newParentVNode
 * @param {object} context The current context object
 * @param {boolean} isSvg Whether or not this DOM node is an SVG node
 * @param {Array<import('../internal').PreactElement>} excessDomChildren
 * @param {Array<import('../internal').Component>} mounts The list of components
 * which have mounted
 * @param {Node | Text} oldDom The current attached DOM
 * element any new dom elements should be placed around. Likely `null` on first
 * render (except when hydrating). Can be a sibling DOM element when diffing
 * Fragments that have siblings. In most cases, it starts out as `oldChildren[0]._dom`.
 * @param {boolean} isHydrating Whether or not we are in hydration
 */
export function diffChildren(parentDom, newParentVNode, oldParentVNode, context, isSvg, excessDomChildren, mounts, oldDom, isHydrating) {
	let i, j, oldVNode, newDom, sibDom, firstChildDom, refs;

	// This is a compression of oldParentVNode!=null && oldParentVNode != EMPTY_OBJ && oldParentVNode._children || EMPTY_ARR
	// as EMPTY_OBJ._children should be `undefined`.
	let oldChildren = (oldParentVNode && oldParentVNode._children) || EMPTY_ARR;

	let oldChildrenLength = oldChildren.length;

	// Only in very specific places should this logic be invoked (top level `render` and `diffElementNodes`).
	// I'm using `EMPTY_OBJ` to signal when `diffChildren` is invoked in these situations. I can't use `null`
	// for this purpose, because `null` is a valid value for `oldDom` which can mean to skip to this logic
	// (e.g. if mounting a new tree in which the old DOM should be ignored (usually for Fragments).
	if (oldDom == EMPTY_OBJ) {
		if (excessDomChildren != null) {
			oldDom = excessDomChildren[0];
		}
		else if (oldChildrenLength) {
			oldDom = getDomSibling(oldParentVNode, 0);
		}
		else {
			oldDom = null;
		}
	}

	i=0;
	newParentVNode._children = toChildArray(newParentVNode._children, childVNode => {

		if (childVNode!=null) {
			childVNode._parent = newParentVNode;
			childVNode._depth = newParentVNode._depth + 1;

			// Check if we find a corresponding element in oldChildren.
			// If found, delete the array item by setting to `undefined`.
			// We use `undefined`, as `null` is reserved for empty placeholders
			// (holes).
			oldVNode = oldChildren[i];

			if (oldVNode===null || (oldVNode && childVNode.key == oldVNode.key && childVNode.type === oldVNode.type)) {
				oldChildren[i] = undefined;
			}
			else {
				// Either oldVNode === undefined or oldChildrenLength > 0,
				// so after this loop oldVNode == null or oldVNode is a valid value.
				for (j=0; j<oldChildrenLength; j++) {
					oldVNode = oldChildren[j];
					// If childVNode is unkeyed, we only match similarly unkeyed nodes, otherwise we match by key.
					// We always match by type (in either case).
					if (oldVNode && childVNode.key == oldVNode.key && childVNode.type === oldVNode.type) {
						oldChildren[j] = undefined;
						break;
					}
					oldVNode = null;
				}
			}

			oldVNode = oldVNode || EMPTY_OBJ;

			// Morph the old element into the new one, but don't append it to the dom yet
			newDom = diff(parentDom, childVNode, oldVNode, context, isSvg, excessDomChildren, mounts, null, oldDom, isHydrating);

			if ((j = childVNode.ref) && oldVNode.ref != j) {
				(refs || (refs=[])).push(j, childVNode._component || newDom, childVNode);
			}

			// Only proceed if the vnode has not been unmounted by `diff()` above.
			if (newDom!=null) {
				if (firstChildDom == null) {
					firstChildDom = newDom;
				}

				if (childVNode._lastDomChild != null) {
					// Only Fragments or components that return Fragment like VNodes will
					// have a non-null _lastDomChild. Continue the diff from the end of
					// this Fragment's DOM tree.
					newDom = childVNode._lastDomChild;

					// Eagerly cleanup _lastDomChild. We don't need to persist the value because
					// it is only used by `diffChildren` to determine where to resume the diff after
					// diffing Components and Fragments.
					childVNode._lastDomChild = null;
				}
				else if (excessDomChildren==oldVNode || newDom!=oldDom || newDom.parentNode==null) {
					// NOTE: excessDomChildren==oldVNode above:
					// This is a compression of excessDomChildren==null && oldVNode==null!
					// The values only have the same type when `null`.

					outer: if (oldDom==null || oldDom.parentNode!==parentDom) {
						parentDom.appendChild(newDom);
					}
					else {
						// `j<oldChildrenLength; j+=2` is an alternative to `j++<oldChildrenLength/2`
						for (sibDom=oldDom, j=0; (sibDom=sibDom.nextSibling) && j<oldChildrenLength; j+=2) {
							if (sibDom==newDom) {
								break outer;
							}
						}
						parentDom.insertBefore(newDom, oldDom);
					}

					// Browsers will infer an option's `value` from `textContent` when
					// no value is present. This essentially bypasses our code to set it
					// later in `diff()`. It works fine in all browsers except for IE11
					// where it breaks setting `select.value`. There it will be always set
					// to an empty string. Re-applying an options value will fix that, so
					// there are probably some internal data structures that aren't
					// updated properly.
					//
					// To fix it we make sure to reset the inferred value, so that our own
					// value check in `diff()` won't be skipped.
					if (newParentVNode.type == 'option') {
						parentDom.value = '';
					}
				}

				oldDom = newDom.nextSibling;

				if (typeof newParentVNode.type == 'function') {
					// At this point, if childVNode._lastDomChild existed, then
					// newDom = childVNode._lastDomChild per line 101. Else it is
					// the same as childVNode._dom, meaning this component returned
					// only a single DOM node
					newParentVNode._lastDomChild = newDom;
				}
			}
		}

		i++;
		return childVNode;
	});

	newParentVNode._dom = firstChildDom;

	// Remove children that are not part of any vnode.
	if (excessDomChildren!=null && typeof newParentVNode.type !== 'function') for (i=excessDomChildren.length; i--; ) if (excessDomChildren[i]!=null) removeNode(excessDomChildren[i]);

	// Remove remaining oldChildren if there are any.
	for (i=oldChildrenLength; i--; ) if (oldChildren[i]!=null) unmount(oldChildren[i], oldChildren[i]);

	// Set refs only after unmount
	if (refs) {
		for (i = 0; i < refs.length; i++) {
			applyRef(refs[i], refs[++i], refs[++i]);
		}
	}
}

/**
 * Flatten and loop through the children of a virtual node
 * @param {import('../index').ComponentChildren} children The unflattened
 * children of a virtual node
 * @param {(vnode: import('../internal').VNode) => import('../internal').VNode} [callback]
 * A function to invoke for each child before it is added to the flattened list.
 * @param {import('../internal').VNode[]} [flattened] An flat array of children to modify
 * @returns {import('../internal').VNode[]}
 */
export function toChildArray(children, callback, flattened) {
	if (flattened == null) flattened = [];

	if (children==null || typeof children === 'boolean') {
		if (callback) flattened.push(callback(null));
	}
	else if (Array.isArray(children)) {
		for (let i=0; i < children.length; i++) {
			toChildArray(children[i], callback, flattened);
		}
	}
	else {
		flattened.push(callback ? callback(coerceToVNode(children)) : children);
	}

	return flattened;
}


expect(scratch.innerHTML).to.equal('
b - 1

a - 1
');

it('should not re-render the consumer if the context doesn\'t change', () => {

const { Provider, Consumer } = createContext();


import { assign } from './util';
import { EMPTY_ARR } from './constants';
import { createVNode } from './create-element';

/**
 * Clones the given VNode, optionally adding attributes/props and replacing its children.
 * @param {import('./internal').VNode} vnode The virtual DOM element to clone
 * @param {object} props Attributes/props to add when cloning
 * @param {Array<import('./index').ComponentChildren>} rest Any additional arguments will be used as replacement children.
 */
export function cloneElement(vnode, props) {
	props = assign(assign({}, vnode.props), props);
	if (arguments.length>2) props.children = EMPTY_ARR.slice.call(arguments, 2);
	return createVNode(vnode.type, props, props.key || vnode.key, props.ref || vnode.ref);
}