     [:h1 {:style (str section-style "margin: 16px; color: rgb(57,67,64);")} (:name pulse)]
     (apply vector :div (mapv render-pulse-section results))])
 
+; ported from https://github.com/radkovo/CSSBox/blob/cssbox-4.10/src/main/java/org/fit/cssbox/demo/ImageRenderer.java
+(defn render-to-png
+  [html, os]
+  (let [is (new java.io.ByteArrayInputStream (.getBytes html java.nio.charset.StandardCharsets/UTF_8))
+        docSource (new org.fit.cssbox.io.StreamDocumentSource is nil "text/html")
+        parser (new org.fit.cssbox.io.DefaultDOMSource docSource)
+        doc (-> parser .parse)
+        windowSize (new java.awt.Dimension card-width 1)
+        media (new cz.vutbr.web.css.MediaSpec "screen")]
+    (.setDimensions media (.width windowSize) (.height windowSize))
+    (.setDeviceDimensions media (.width windowSize) (.height windowSize))
+    (let [da (new org.fit.cssbox.css.DOMAnalyzer doc (.getURL docSource))]
+      (.setMediaSpec da media)
+      (.attributesToStyles da)
+      (.addStyleSheet da nil (org.fit.cssbox.css.CSSNorm/stdStyleSheet) org.fit.cssbox.css.DOMAnalyzer$Origin/AGENT)
+      (.addStyleSheet da nil (org.fit.cssbox.css.CSSNorm/userStyleSheet) org.fit.cssbox.css.DOMAnalyzer$Origin/AGENT)
+      (.addStyleSheet da nil (org.fit.cssbox.css.CSSNorm/formsStyleSheet) org.fit.cssbox.css.DOMAnalyzer$Origin/AGENT)
+      (.getStyleSheets da)
+      (let [contentCanvas (new org.fit.cssbox.layout.BrowserCanvas (.getRoot da) da (.getURL docSource))]
+        (-> contentCanvas (.setAutoMediaUpdate false))
+        (-> contentCanvas (.setAutoSizeUpdate true))
+        (-> contentCanvas .getConfig (.setClipViewport false))
+        (-> contentCanvas .getConfig (.setLoadImages true))
+        (-> contentCanvas .getConfig (.setLoadBackgroundImages true))
+        (-> contentCanvas (.createLayout windowSize))
+        (javax.imageio.ImageIO/write (.getImage contentCanvas) "png" os)))))
+
 (defn render-pulse-card-to-png
   [card data include-title]
   (let [html (html [:html [:body {:style "margin: 0; background-color: white;"} (render-pulse-card card data include-title)]])


(defsetting slack-token "Slack API bearer token obtained from https://api.slack.com/web#authentication")


(def ^:private card-width 400)

(defn parse-dom
  [stream]
  (let [dbf (javax.xml.parsers.DocumentBuilderFactory/newInstance)]
    (.setNamespaceAware dbf true)
    (.setFeature dbf "http://apache.org/xml/features/nonvalidating/load-external-dtd" false)
    (.parse (.newDocumentBuilder dbf) stream)))

; ported from https://github.com/radkovo/CSSBox/blob/cssbox-4.10/src/main/java/org/fit/cssbox/demo/ImageRenderer.java
(defn render-to-png
  [html, os]
  (let [is (new java.io.ByteArrayInputStream (.getBytes html java.nio.charset.StandardCharsets/UTF_8))
        docSource (new org.fit.cssbox.io.StreamDocumentSource is nil "text/html")
        parser (new org.fit.cssbox.io.DefaultDOMSource docSource)
        doc (-> parser .parse)
        windowSize (new java.awt.Dimension card-width 1)
        media (new cz.vutbr.web.css.MediaSpec "screen")]
    (.setDimensions media (.width windowSize) (.height windowSize))
    (.setDeviceDimensions media (.width windowSize) (.height windowSize))
    (let [da (new org.fit.cssbox.css.DOMAnalyzer doc (.getURL docSource))]
      (.setMediaSpec da media)
      (.attributesToStyles da)
      (.addStyleSheet da nil (org.fit.cssbox.css.CSSNorm/stdStyleSheet) org.fit.cssbox.css.DOMAnalyzer$Origin/AGENT)
      (.addStyleSheet da nil (org.fit.cssbox.css.CSSNorm/userStyleSheet) org.fit.cssbox.css.DOMAnalyzer$Origin/AGENT)
      (.addStyleSheet da nil (org.fit.cssbox.css.CSSNorm/formsStyleSheet) org.fit.cssbox.css.DOMAnalyzer$Origin/AGENT)
      (.getStyleSheets da)
      (let [contentCanvas (new org.fit.cssbox.layout.BrowserCanvas (.getRoot da) da (.getURL docSource))]
        (-> contentCanvas (.setAutoMediaUpdate false))
        (-> contentCanvas (.setAutoSizeUpdate true))
        (-> contentCanvas .getConfig (.setClipViewport false))
        (-> contentCanvas .getConfig (.setLoadImages true))
        (-> contentCanvas .getConfig (.setLoadBackgroundImages true))
        (-> contentCanvas (.createLayout windowSize))
        (javax.imageio.ImageIO/write (.getImage contentCanvas) "png" os)))))

; ported from https://stackoverflow.com/questions/17061682/java-html-rendering-engine
(defn render-to-png-swing
  [html os]
  (let [image (-> (java.awt.GraphicsEnvironment/getLocalGraphicsEnvironment)
              .getDefaultScreenDevice
              .getDefaultConfiguration
              (.createCompatibleImage card-width 600))
        graphics (.createGraphics image)
        jep (new javax.swing.JEditorPane "text/html" html)]
    (.setSize jep card-width 600)
    (.print jep graphics)
    (javax.imageio.ImageIO/write image "png" os)))

; ported from http://grepcode.com/file/repo1.maven.org/maven2/org.xhtmlrenderer/core-renderer/R8pre2/org/xhtmlrenderer/simple/Graphics2DRenderer.java
(defn render-to-png-flying-saucer
  [html os]
  (let [is (new java.io.ByteArrayInputStream (.getBytes html java.nio.charset.StandardCharsets/UTF_8))
        dom (parse-dom is)
        renderer (new org.xhtmlrenderer.simple.Graphics2DRenderer)
        rect (new java.awt.Dimension card-width 600)
        buff (new java.awt.image.BufferedImage (.getWidth rect) (.getHeight rect) java.awt.image.BufferedImage/TYPE_INT_ARGB)
        g (.getGraphics buff)]
    (.setDocument renderer dom nil)
    (.layout renderer g rect)
    (.dispose g)
    (let [rect (.getMinimumSize renderer)
          buff (new java.awt.image.BufferedImage (.getWidth rect) (.getHeight rect) java.awt.image.BufferedImage/TYPE_INT_ARGB)
          g (.getGraphics buff)]
      (.render renderer g)
      (.dispose g)
      (javax.imageio.ImageIO/write buff "png" os))))


(def ^:private font-style "font-family: Lato, \"Helvetica Neue\", Helvetica, Arial, sans-serif;")
(def ^:private section-style font-style)

(ns metabase.pulse
  (:require [hiccup.core :refer [html]]
            [clj-time.core :as t]
            [clj-time.coerce :as c]
            [clj-time.format :as f]
            [clojure.tools.logging :as log]
            [clojure.pprint :refer [cl-format]]
            [clojure.string :refer [upper-case]]
