\defactiveparameter page {%
  \settovalue\pdfpagewidth  #1 : width
  \settovalue\pdfpageheight #1 : height
  \settovalue\baselineskip  #1 : baselineskip
  \settovalueor\topskip     #1 : topskip {\topskip=\baselineskip}%
  \settovalue\pdfhorigin    #1 : left
  \ifattribute #1 : right
              {\hsize = \dimexpr(\pdfpagewidth-\pdfhorigin-\usevalue #1 : right )\relax}
              {\settovalue\hsize #1 : hsize }%
  \settovalue\pdfvorigin    #1 : top
  \settovalue\parindent     #1 : parindent
  \settovalue\parskip       #1 : parskip
  \ifattribute #1 : lines {\vsize=\usevalue #1 : lines \baselineskip}{}%
  }

\restrictparameter page : 
  width
  height
  hsize
  baselineskip
  topskip
  left
  right
  top
  lines
  parindent
  parskip
\par

% Defaults... they don't produce anything beautiful.
% I redefine them on every job.
\setparameter page:
  height       = 28cm
  width        = 21cm
  hsize        = 15cm
  baselineskip = 12pt
  lines        = 42
  left         = 1in
  top          = 1in
  parskip      = 0pt

\widowpenalty151
\clubpenalty0
\holdinginserts1
\newdimen\outputsize
\newif\ifheader

\gates new \OutputRoutine {OutputRoutine}%

\OutputRoutine list {output}
  [precheck]
    {%
    \global\holdinginserts0
    \OutputRoutine skip {precheck, shipout}{output}%
    \ifnum\outputpenalty<\widowpenalty
      \global\outputsize=\vsize
    \else
      \ifnum\outputpenalty=10000
        \global\outputsize=\vsize
      \else
        \ifdim\pagegoal<\vsize
          \global\advance\vsize-\baselineskip
          \global\outputsize=\dimexpr\vsize+\baselineskip\relax
        \else
          \global\advance\vsize\baselineskip
          \global\outputsize=\dimexpr\vsize-\baselineskip\relax
        \fi
      \fi
    \fi
    \unvbox\outputbox
    \ifnum\outputpenalty=10000
      \penalty0
    \else
      \penalty\outputpenalty
    \fi}
%
  (shipout)
  . (inserts)
  . . [inserts_figures]   ?{conditional = \unless\ifvoid\ptx@insert_figures} {%
        \setbox\outputbox=\vbox to \outputsize{%
        \box\ptx@insert_figures
        \unvbox\outputbox}}
  . . [inserts_footnotes] ?{conditional = \unless\ifvoid\ptx@insert_footnotes} {%
        \setbox\outputbox=\vbox to \outputsize{%
          \unvbox\outputbox
          \vfil
          \vskip.5\skip\ptx@insert_footnotes
          \vbox to0pt{\vss\hrule width .3\hsize}%
          \vskip.5\skip\ptx@insert_footnotes
          \unvbox\ptx@insert_footnotes}}
  %
  . [headers] {%
      \setbox\outputbox=\vbox{%
      \kern-3\baselineskip
      \vbox to3\baselineskip{%
        \hbox to\hsize{\strut\baselineskip {0pt}%
          \normalsize\rm\sc
          \ifodd\pageno
            \hfill\usevalue chapter : inner_title \rlap{\kern1em \the\pageno}\kern-3em
          \else
            \kern-3em\llap{\the\pageno\kern1em }\usevalue chapter : inner_title \hfill
          \fi}
          \vfill}
      \nointerlineskip
      \box\outputbox}}
    %
  . [ship] {%
      \settovalue\pdfhorigin page : left
      \shipout\box\outputbox}
    %
  . [postship] {%
      \global\holdinginserts1
      \global\vsize\outputsize
      \global\advance\count0 1
      \ifnum\insertpenalties>0
        \ifnum\outputpenalty=\clearpagepenalty
          \hbox{}\vfil\penalty\outputpenalty
        \fi
      \fi}


\output{%
  \OutputRoutine execute {output}%
  }



% MARGIN NOTES
\setparameter marginnote :
  hsize     = 3cm
  hpos      = fr
  font      = \it
  parindent = 0pt
  side      = right
  gap       = 1em

\newcount\notecount
\newattribute\ptx@marginnote_attribute
\def\marginnote{%
  \ifnext[
    {\ptx@marginnote}
    {\ptx@marginnote[]}%
  }

\long\def\ptx@marginnote[#1]#2{%
  \setparameterlist{marginnote@temp}{meta = marginnote, #1}%
  \global\advance\notecount 1
  \global\expandafter\newbox\csname marginnote_\the\notecount\endcsname
  \global\expandafter\setbox\csname marginnote_\the\notecount\endcsname=
    \vtop{%
      \settovalue\hsize marginnote@temp : hsize
      \settovalue{\advance\hsize} marginnote@temp : gap
      \leftskip=0pt \rightskip=0pt plus 1 fil \parfillskip=0pt\relax
      \ifcasevalue marginnote@temp : hpos
        \val ff \rightskip=0pt \parfillskip=0pt plus 1 fil
        \val rf \leftskip=0pt plus 1 fil \rightskip=1pt
        \val rr \leftskip=0pt plus 1 fil
      \endval
      \ifvalue marginnote@temp : side = left
        {\settovalue{\advance\rightskip} marginnote@temp : gap }
        {\settovalue{\advance\leftskip} marginnote@temp : gap }%
      \settovalue\baselineskip marginnote@temp : baselineskip
      \settovalue\parindent marginnote@temp : parindent
      \usevalue marginnote@temp : font
      #2}%
  \quitvmode % Must be outside the attribute's scope, otherwise the
             %  paragraphs DIR whatsit might get in the way.
  \bgroup
  \ifvalue marginnote@temp : side = left
    {\ptx@marginnote_attribute=-\expandafter\the\csname marginnote_\the\notecount\endcsname}
    {\ptx@marginnote_attribute=\expandafter\the\csname marginnote_\the\notecount\endcsname}\relax
  \pdfliteral{}%
  \egroup
  \deleteparameter marginnote@temp:%
  }

\luacode
local WHAT, HLIST, KERN = node.id("whatsit"), node.id("hlist"), node.id("kern")
local GLUE, SPEC = node.id("glue"), node.id("glue_spec")
local marginnote_table = {}
function pitex.misc.mark_lines (head)
  for line in node.traverse_id(HLIST, head) do
    local t = {left = {}, right = {}}
    local item = line.head
    while item do
      local next = item.next
      if item.id == WHAT then
        local attr = node.has_attribute(item, \attributenumber\ptx@marginnote_attribute)
        if attr then
          if attr < 0 then
            table.insert(t.left, -attr)
          else
            table.insert(t.right, attr)
          end
          line.head = node.remove(line.head, item)
        end
      end
      item = next
    end
    if #t.left > 0 or #t.right > 0 then
      table.insert(marginnote_table, t)
      node.set_attribute(line, \attributenumber\ptx@marginnote_attribute, #marginnote_table)
    end
  end
  return head
end

pitex.callback.register("post_linebreak_filter", "pitex.misc:mark_lines")

local lheight, rheight = 0, 0
local function update_height (h)
  lheight = lheight + h
  rheight = rheight + h
end

local function first_dim (n, t)
  while n do
    if node.has_field(n, "kern") then
      return n.kern
    elseif node.has_field(n, "spec") then
      return n.spec.width
    elseif node.has_field(n, "height") then
      return t == "height" and n.height or n.depth
    else
      n = t == "height" and n.next or n.prev
    end
  end
  return 0
end

function process_marginalia (head)
  lheight, rheight = 0, 0
  local item, first = node.slide(head), true
  while item do
    if node.has_field(item, "kern") then
      if not first then
        update_height(item.kern)
      end
    elseif node.has_field(item, "spec") then
      if not first then
        update_height(item.spec.width)
      end
    elseif node.has_field(item, "height") then
      if first then
        first = false
      else
        update_height(item.depth)
      end
      local attr = node.has_attribute(item, \attributenumber\ptx@marginnote_attribute)
      if attr then
        for side, notes in pairs (marginnote_table[attr]) do
          if #notes > 0 then
            local note
            for _, n in ipairs(notes) do
              if note then
                local n, g, s = tex.box[n], node.new(GLUE), node.new(SPEC)
                local d = first_dim(node.tail(note.head), "depth")
                local h = first_dim(n.head, "height")
                s.width = tex.baselineskip.width - (d + h)
                g.spec = s
                note.depth = note.depth + s.width + n.height + n.depth
                node.insert_after(note.head, node.tail(note.head), g)
                g.next, n.head.prev = n.head, g
              else
                note = tex.box[n]
              end
            end
            first = true
            local upward = note.depth - first_dim(node.tail(note.head), "depth")
            local remainingheight = side == "left" and lheight or rheight
            if upward > remainingheight then
              upward = remainingheight - upward
            else
              upward = 0
            end
            local kern = node.new(KERN, 1)
            kern.kern = upward - note.height - item.depth
            node.insert_before(note.list, note.list, kern)
            note.list = kern
            if side == "left" then
              note.shift = -note.width
              lheight = upward
            else
              note.shift = item.width
              rheight = upward
            end
            note.height, note.depth = 0, 0
            node.insert_after(head, item, note)
          else
            if side == "left" then
              lheight = lheight + item.height
            else
              rheight = rheight + item.height
            end
          end
        end
      else
        update_height(item.height)
      end
    end
    item = item.prev
  end
end
\luacode/

\OutputRoutine def {processmarginalia}{%
  \ptx@lua{process_marginalia(tex.box[255].list)}%
  }

\OutputRoutine add {processmarginalia}[first]{shipout}

