<!DOCTYPE html>
<html>
<head>
    <title><%= exception.type %> at <%= request_path %></title>
</head>
<body>
    <%# Stylesheets are placed in the <body> for Turbolinks compatibility. %>
    <style>
    /* Basic reset */
    * {
        margin: 0;
        padding: 0;
    }

    table {
        width: 100%;
        border-collapse: collapse;
    }

    th, td {
        vertical-align: top;
        text-align: left;
    }

    textarea {
        resize: none;
    }

    body {
        font-size: 10pt;
    }

    body, td, input, textarea {
        font-family: helvetica neue, lucida grande, sans-serif;
        line-height: 1.5;
        color: #333;
        text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6);
    }

    html {
        background: #f0f0f5;
    }

    .clearfix::after{
        clear: both;
        content: ".";
        display: block;
        height: 0;
        visibility: hidden;
    }

    /* ---------------------------------------------------------------------
     * Basic layout
     * --------------------------------------------------------------------- */

    /* Small */
    @media screen and (max-width: 1100px) {
        html {
            overflow-y: scroll;
        }

        body {
            margin: 0 20px;
        }

        header.exception {
            margin: 0 -20px;
        }

        nav.sidebar {
            padding: 0;
            margin: 20px 0;
        }

        ul.frames {
            max-height: 200px;
            overflow: auto;
        }
    }

    /* Wide */
    @media screen and (min-width: 1100px) {
        header.exception {
           position: fixed;
           top: 0;
           left: 0;
           right: 0;
        }

        nav.sidebar,
        .frame_info {
            position: fixed;
            top: 95px;
            bottom: 0;

            box-sizing: border-box;

            overflow-y: auto;
            overflow-x: hidden;
        }

        nav.sidebar {
            width: 40%;
            left: 20px;
            top: 115px;
            bottom: 20px;
        }

        .frame_info {
            right: 0;
            left: 40%;

            padding: 20px;
            padding-left: 10px;
            margin-left: 30px;
        }
    }

    nav.sidebar {
        background: #d3d3da;
        border-top: solid 3px #a33;
        border-bottom: solid 3px #a33;
        border-radius: 4px;
        box-shadow: 0 0 6px rgba(0, 0, 0, 0.2), inset 0 0 0 1px rgba(0, 0, 0, 0.1);
    }

    /* ---------------------------------------------------------------------
     * Header
     * --------------------------------------------------------------------- */

    header.exception {
        padding: 18px 20px;

        height: 59px;
        min-height: 59px;

        overflow: hidden;

        background-color: #20202a;
        color: #aaa;
        text-shadow: 0 1px 0 rgba(0, 0, 0, 0.3);
        font-weight: 200;
        box-shadow: inset 0 -5px 3px -3px rgba(0, 0, 0, 0.05), inset 0 -1px 0 rgba(0, 0, 0, 0.05);

        -webkit-text-smoothing: antialiased;
    }

    /* Heading */
    header.exception h2 {
        font-weight: 200;
        font-size: 11pt;
    }

    header.exception h2,
    header.exception p {
        line-height: 1.4em;
        overflow: hidden;
        white-space: pre;
        text-overflow: ellipsis;
    }

    header.exception h2 strong {
        font-weight: 700;
        color: #d55;
    }

    header.exception p {
        font-weight: 200;
        font-size: 20pt;
        color: white;
    }

    header.exception:hover {
        height: auto;
        z-index: 2;
    }

    header.exception:hover h2,
    header.exception:hover p {
        padding-right: 20px;
        overflow-y: auto;
        word-wrap: break-word;
        white-space: pre-wrap;
        height: auto;
        max-height: 7em;
    }

    @media screen and (max-width: 1100px) {
        header.exception {
            height: auto;
        }

        header.exception h2,
        header.exception p {
            padding-right: 20px;
            overflow-y: auto;
            word-wrap: break-word;
            height: auto;
            max-height: 7em;
        }
    }

    <%#
    /* Light theme */
    header.exception {
        text-shadow: 0 1px 0 rgba(250, 250, 250, 0.6);
        background: rgba(200,100,50,0.10);
        color: #977;
    }
    header.exception h2 strong {
        color: #533;
    }
    header.exception p {
        color: #744;
    }
    %>

    /* ---------------------------------------------------------------------
     * Navigation
     * --------------------------------------------------------------------- */

    nav.tabs {
        border-bottom: solid 1px #ddd;

        background-color: #eee;
        text-align: center;

        padding: 6px;

        box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
    }

    nav.tabs a {
        display: inline-block;

        height: 22px;
        line-height: 22px;
        padding: 0 10px;

        text-decoration: none;
        font-size: 8pt;
        font-weight: bold;

        color: #999;
        text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6);
    }

    nav.tabs a.selected {
        color: white;
        background: rgba(0, 0, 0, 0.5);
        border-radius: 16px;
        box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.1);
        text-shadow: 0 0 4px rgba(0, 0, 0, 0.4), 0 1px 0 rgba(0, 0, 0, 0.4);
    }

    nav.tabs a.disabled {
        text-decoration: line-through;
        text-shadow: none;
        cursor: default;
    }

    /* ---------------------------------------------------------------------
     * Sidebar
     * --------------------------------------------------------------------- */

    ul.frames {
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    }

    /* Each item */
    ul.frames li {
        background-color: #f8f8f8;
        background: -webkit-linear-gradient(top, #f8f8f8 80%, #f0f0f0);
        background: -moz-linear-gradient(top, #f8f8f8 80%, #f0f0f0);
        background: linear-gradient(top, #f8f8f8 80%, #f0f0f0);
        box-shadow: inset 0 -1px 0 #e2e2e2;
        padding: 7px 20px;

        cursor: pointer;
        overflow: hidden;
    }

    ul.frames .name,
    ul.frames .location {
        overflow: hidden;
        height: 1.5em;

        white-space: nowrap;
        word-wrap: none;
        text-overflow: ellipsis;
    }

    ul.frames .method {
        color: #966;
    }

    ul.frames .location {
        font-size: 0.85em;
        font-weight: 400;
        color: #999;
    }

    ul.frames .line {
        font-weight: bold;
    }

    /* Selected frame */
    ul.frames li.selected {
        background: #38a;
        box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), inset 0 2px 0 rgba(255, 255, 255, 0.01), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
    }

    ul.frames li.selected .name,
    ul.frames li.selected .method,
    ul.frames li.selected .location {
        color: white;
        text-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
    }

    ul.frames li.selected .location {
        opacity: 0.6;
    }

    /* Iconography */
    ul.frames li {
        padding-left: 60px;
        position: relative;
    }

    ul.frames li .icon {
        display: block;
        width: 20px;
        height: 20px;
        line-height: 20px;
        border-radius: 15px;

        text-align: center;

        background: white;
        border: solid 2px #ccc;

        font-size: 9pt;
        font-weight: 200;
        font-style: normal;

        position: absolute;
        top: 14px;
        left: 20px;
    }

    ul.frames .icon.application {
        background: #808090;
        border-color: #555;
    }

    ul.frames .icon.application:before {
        content: 'A';
        color: white;
        text-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
    }

    /* Responsiveness -- flow to single-line mode */
    @media screen and (max-width: 1100px) {
        ul.frames li {
            padding-top: 6px;
            padding-bottom: 6px;
            padding-left: 36px;
            line-height: 1.3;
        }

        ul.frames li .icon {
            width: 11px;
            height: 11px;
            line-height: 11px;

            top: 7px;
            left: 10px;
            font-size: 5pt;
        }

        ul.frames .name,
        ul.frames .location {
            display: inline-block;
            line-height: 1.3;
            height: 1.3em;
        }

        ul.frames .name {
            margin-right: 10px;
        }
    }

    /* ---------------------------------------------------------------------
     * Monospace
     * --------------------------------------------------------------------- */

    pre, code, .repl input, .repl .prompt span, textarea, .code_linenums {
        font-family: menlo, lucida console, monospace;
        font-size: 8pt;
    }

    /* ---------------------------------------------------------------------
     * Display area
     * --------------------------------------------------------------------- */

    .trace_info {
        background: #fff;
        padding: 6px;
        border-radius: 3px;
        margin-bottom: 2px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.03), 1px 1px 0 rgba(0, 0, 0, 0.05), -1px 1px 0 rgba(0, 0, 0, 0.05), 0 0 0 4px rgba(0, 0, 0, 0.04);
    }

    .code_block{
        background: #f1f1f1;
        border-left: 1px solid #ccc;
    }

    /* Titlebar */
    .trace_info .title {
        background: #f1f1f1;

        box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3);
        overflow: hidden;
        padding: 6px 10px;

        border: solid 1px #ccc;
        border-bottom: 0;

        border-top-left-radius: 2px;
        border-top-right-radius: 2px;
    }

    .trace_info .title .name,
    .trace_info .title .location {
        font-size: 9pt;
        line-height: 26px;
        height: 26px;
        overflow: hidden;
    }

    .trace_info .title .location {
        float: left;
        font-weight: bold;
        font-size: 10pt;
    }

    .trace_info .title .location a {
        color:inherit;
        text-decoration:none;
        border-bottom:1px solid #aaaaaa;
    }

    .trace_info .title .location a:hover {
        border-color:#666666;
    }

    .trace_info .title .name {
        float: right;
        font-weight: 200;
    }

    .code, .console, .unavailable {
        background: #fff;
        padding: 5px;

        box-shadow: inset 3px 3px 3px rgba(0, 0, 0, 0.1), inset 0 0 0 1px rgba(0, 0, 0, 0.1);
    }

    .code_linenums{
        background:#f1f1f1;
        padding-top:10px;
        padding-bottom:9px;
        float:left;
    }

    .code_linenums span{
        display:block;
        padding:0 12px;
    }

    .code {
        margin-bottom: -1px;
        border-top-left-radius:2px;
        padding: 10px 0;
        overflow: auto;
    }

    .code pre{
        padding-left:12px;
        min-height:16px;
    }

    /* Source unavailable */
    p.unavailable {
        padding: 20px 0 40px 0;
        text-align: center;
        color: #b99;
        font-weight: bold;
    }

    p.unavailable:before {
        content: '\00d7';
        display: block;

        color: #daa;

        text-align: center;
        font-size: 40pt;
        font-weight: normal;
        margin-bottom: -10px;
    }

    @-webkit-keyframes highlight {
        0%   { background: rgba(220, 30, 30, 0.3); }
        100% { background: rgba(220, 30, 30, 0.1); }
    }
    @-moz-keyframes highlight {
        0%   { background: rgba(220, 30, 30, 0.3); }
        100% { background: rgba(220, 30, 30, 0.1); }
    }
    @keyframes highlight {
        0%   { background: rgba(220, 30, 30, 0.3); }
        100% { background: rgba(220, 30, 30, 0.1); }
    }

    .code .highlight, .code_linenums .highlight {
        background: rgba(220, 30, 30, 0.1);
        -webkit-animation: highlight 400ms linear 1;
        -moz-animation: highlight 400ms linear 1;
        animation: highlight 400ms linear 1;
    }

    /* REPL shell */
    .console {
        padding: 0 1px 10px 1px;
        border-bottom-left-radius: 2px;
        border-bottom-right-radius: 2px;
    }

    .console pre {
        padding: 10px 10px 0 10px;
        max-height: 400px;
        overflow-x: none;
        overflow-y: auto;
        margin-bottom: -3px;
        word-wrap: break-word;
        white-space: pre-wrap;
    }

    /* .prompt > span + input */
    .console .prompt {
        display: table;
        width: 100%;
    }

    .console .prompt span,
    .console .prompt input {
        display: table-cell;
    }

    .console .prompt span {
        width: 1%;
        padding-right: 5px;
        padding-left: 10px;
    }

    .console .prompt input {
        width: 99%;
    }

    /* Input box */
    .console input,
    .console input:focus {
        outline: 0;
        border: 0;
        padding: 0;
        background: transparent;
        margin: 0;
    }

    /* Hint text */
    .hint {
        margin: 15px 0 20px 0;
        font-size: 8pt;
        color: #8080a0;
        padding-left: 20px;
    }

    .hint:before {
        content: '\25b2';
        margin-right: 5px;
        opacity: 0.5;
    }

    /* ---------------------------------------------------------------------
     * Variable infos
     * --------------------------------------------------------------------- */

    .sub {
        padding: 10px 0;
        margin: 10px 0;
    }

    .sub:before {
        content: '';
        display: block;
        width: 100%;
        height: 4px;

        border-radius: 2px;
        background: rgba(0, 150, 200, 0.05);
        box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.7), inset 0 0 0 1px rgba(0, 0, 0, 0.04), inset 2px 2px 2px rgba(0, 0, 0, 0.07);
    }

    .sub h3 {
        color: #39a;
        font-size: 1.1em;
        margin: 10px 0;
        text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6);

        -webkit-font-smoothing: antialiased;
    }

    .sub .inset {
        overflow-y: auto;
    }

    .sub table {
        table-layout: fixed;
    }

    .sub table td {
        border-top: dotted 1px #ddd;
        padding: 7px 1px;
    }

    .sub table td.name {
        width: 150px;

        font-weight: bold;
        font-size: 0.8em;
        padding-right: 20px;

        word-wrap: break-word;
    }

    .sub table td pre {
        max-height: 15em;
        overflow-y: auto;
    }

    .sub table td pre {
        width: 100%;

        word-wrap: break-word;
        white-space: normal;
    }

    /* "(object doesn't support inspect)" */
    .sub .unsupported {
      font-family: sans-serif;
      color: #777;
    }

    /* ---------------------------------------------------------------------
     * Scrollbar
     * --------------------------------------------------------------------- */

    nav.sidebar::-webkit-scrollbar,
    .inset pre::-webkit-scrollbar,
    .console pre::-webkit-scrollbar,
    .code::-webkit-scrollbar {
        width: 10px;
        height: 10px;
    }

    .inset pre::-webkit-scrollbar-thumb,
    .console pre::-webkit-scrollbar-thumb,
    .code::-webkit-scrollbar-thumb {
        background: #ccc;
        border-radius: 5px;
    }

    nav.sidebar::-webkit-scrollbar-thumb {
        background: rgba(0, 0, 0, 0.0);
        border-radius: 5px;
    }

    nav.sidebar:hover::-webkit-scrollbar-thumb {
        background-color: #999;
        background: -webkit-linear-gradient(left, #aaa, #999);
    }

    .console pre:hover::-webkit-scrollbar-thumb,
    .inset pre:hover::-webkit-scrollbar-thumb,
    .code:hover::-webkit-scrollbar-thumb {
        background: #888;
    }
    </style>

    <%# IE8 compatibility crap %>
    <script>
    (function() {
        var elements = ["section", "nav", "header", "footer", "audio"];
        for (var i = 0; i < elements.length; i++) {
            document.createElement(elements[i]);
        }
    })();
    </script>

    <%#
      If Rails's Turbolinks is used, the Better Errors page is probably
      rendered in the host app's layout. Let's empty out the styles of the
      host app.
    %>
    <script>
      if (window.Turbolinks) {
          for(var i=0; i < document.styleSheets.length; i++) {
              if(document.styleSheets[i].href)
                  document.styleSheets[i].disabled = true;
          }
          document.addEventListener("page:restore", function restoreCSS(e) {
              for(var i=0; i < document.styleSheets.length; i++) {
                  document.styleSheets[i].disabled = false;
              }
              document.removeEventListener("page:restore", restoreCSS, false);
          });
      }
    </script>

    <div class='top'>
        <header class="exception">
            <h2><strong><%= exception.type %></strong> <span>at <%= request_path %></span></h2>
            <p><%= exception.message %></p>
        </header>
    </div>

    <section class="backtrace">
        <nav class="sidebar">
            <nav class="tabs">
                <a href="#" id="application_frames">Application Frames</a>
                <a href="#" id="all_frames">All Frames</a>
            </nav>
            <ul class="frames">
                <% backtrace_frames.each_with_index do |frame, index| %>
                    <li class="<%= frame.context %>" data-context="<%= frame.context %>" data-index="<%= index %>">
                        <span class='stroke'></span>
                        <i class="icon <%= frame.context %>"></i>
                        <div class="info">
                            <div class="name">
                                <strong><%= frame.class_name %></strong><span class='method'><%= frame.method_name %></span>
                            </div>
                            <div class="location">
                                <span class="filename"><%= frame.pretty_path %></span>, line <span class="line"><%= frame.line %></span>
                            </div>
                        </div>
                    </li>
                <% end %>
            </ul>
        </nav>

        <% backtrace_frames.each_with_index do |frame, index| %>
            <div class="frame_info" id="frame_info_<%= index %>" style="display:none;"></div>
        <% end %>
    </section>
</body>
<script>
(function() {

    var OID = "<%= id %>";

    var previousFrame = null;
    var previousFrameInfo = null;
    var allFrames = document.querySelectorAll("ul.frames li");
    var allFrameInfos = document.querySelectorAll(".frame_info");

    function apiCall(method, opts, cb) {
        var req = new XMLHttpRequest();
        req.open("POST", <%== uri_prefix.gsub("<", "&lt;").inspect %> + "/__better_errors/" + OID + "/" + method, true);
        req.setRequestHeader("Content-Type", "application/json");
        req.send(JSON.stringify(opts));
        req.onreadystatechange = function() {
            if(req.readyState == 4) {
                var res = JSON.parse(req.responseText);
                cb(res);
            }
        };
    }

    function escapeHTML(html) {
        return html.replace(/&/, "&amp;").replace(/</g, "&lt;");
    }

    function REPL(index) {
        this.index = index;

        var previousCommands = JSON.parse(localStorage.getItem("better_errors_previous_commands"));
        if(previousCommands === null) {
          localStorage.setItem("better_errors_previous_commands", JSON.stringify([]));
          previousCommands = [];
        }

        this.previousCommandOffset = previousCommands.length;
    }

    REPL.all = [];

    REPL.prototype.install = function(containerElement) {
        this.container = containerElement;

        this.promptElement  = this.container.querySelector(".prompt span");
        this.inputElement   = this.container.querySelector("input");
        this.outputElement  = this.container.querySelector("pre");

        var self = this;
        this.inputElement.onkeydown = function(ev) {
            self.onKeyDown(ev);
        };

        this.setPrompt(">>");

        REPL.all[this.index] = this;
    }

    REPL.prototype.focus = function() {
        this.inputElement.focus();
    };

    REPL.prototype.setPrompt = function(prompt) {
        this._prompt = prompt;
        this.promptElement.innerHTML = escapeHTML(prompt);
    };

    REPL.prototype.getInput = function() {
        return this.inputElement.value;
    };

    REPL.prototype.setInput = function(text) {
        this.inputElement.value = text;

        if(this.inputElement.setSelectionRange) {
            // set cursor to end of input
            this.inputElement.setSelectionRange(text.length, text.length);
        }
    };

    REPL.prototype.writeRawOutput = function(output) {
        this.outputElement.innerHTML += output;
        this.outputElement.scrollTop = this.outputElement.scrollHeight;
    };

    REPL.prototype.writeOutput = function(output) {
        this.writeRawOutput(escapeHTML(output));
    };

    REPL.prototype.sendInput = function(line) {
        var self = this;
        apiCall("eval", { "index": this.index, source: line }, function(response) {
            if(response.error) {
                self.writeOutput(response.error + "\n");
            }
            self.writeOutput(self._prompt + " ");
            self.writeRawOutput(response.highlighted_input + "\n");
            self.writeOutput(response.result);
            self.setPrompt(response.prompt);
            self.setInput(response.prefilled_input);
        });
    };

    REPL.prototype.onEnterKey = function() {
        var text = this.getInput();
        if(text != "" && text !== undefined) {
            var previousCommands = JSON.parse(localStorage.getItem("better_errors_previous_commands"));
            this.previousCommandOffset = previousCommands.push(text);
            if(previousCommands.length > 100) {
              previousCommands.splice(0, 1);
            }
            localStorage.setItem("better_errors_previous_commands", JSON.stringify(previousCommands));
        }
        this.setInput("");
        this.sendInput(text);
    };

    REPL.prototype.onNavigateHistory = function(direction) {
        this.previousCommandOffset += direction;
        var previousCommands = JSON.parse(localStorage.getItem("better_errors_previous_commands"));

        if(this.previousCommandOffset < 0) {
            this.previousCommandOffset = -1;
            this.setInput("");
            return;
        }

        if(this.previousCommandOffset >= previousCommands.length) {
            this.previousCommandOffset = previousCommands.length;
            this.setInput("");
            return;
        }

        this.setInput(previousCommands[this.previousCommandOffset]);
    };

    REPL.prototype.onKeyDown = function(ev) {
        if(ev.keyCode == 13) {
            this.onEnterKey();
        } else if(ev.keyCode == 38 || (ev.ctrlKey && ev.keyCode == 80)) {
            // the user pressed the up arrow or Ctrl-P
            this.onNavigateHistory(-1);
            ev.preventDefault();
            return false;
        } else if(ev.keyCode == 40 || (ev.ctrlKey && ev.keyCode == 78)) {
            // the user pressed the down arrow or Ctrl-N
            this.onNavigateHistory(1);
            ev.preventDefault();
            return false;
        }
    };

    function switchTo(el) {
        if(previousFrameInfo) previousFrameInfo.style.display = "none";
        previousFrameInfo = el;

        el.style.display = "block";

        var replInput = el.querySelector('.console input');
        if (replInput) replInput.focus();
    }

    function selectFrameInfo(index) {
        var el = allFrameInfos[index];
        if(el) {
            if (el.loaded) {
                return switchTo(el);
            }

            apiCall("variables", { "index": index }, function(response) {
                el.loaded = true;
                if(response.error) {
                    el.innerHTML = "<span class='error'>" + escapeHTML(response.error) + "</span>";
                } else {
                    el.innerHTML = response.html;

                    var repl = el.querySelector(".repl .console");
                    if(repl) {
                        new REPL(index).install(repl);
                    }

                    switchTo(el);
                }
            });
        }
    }

    for(var i = 0; i < allFrames.length; i++) {
        (function(i, el) {
            var el = allFrames[i];
            el.onclick = function() {
                if(previousFrame) {
                    previousFrame.className = "";
                }
                el.className = "selected";
                previousFrame = el;

                selectFrameInfo(el.attributes["data-index"].value);
            };
        })(i);
    }

    // Click the first application frame
    (
      document.querySelector(".frames li.application") ||
      document.querySelector(".frames li")
    ).onclick();

    // This is the second query performed for frames; maybe the 'allFrames' list
    // currently used and this list can be better used to avoid the repetition:
    var applicationFramesCount = document.querySelectorAll(
        "ul.frames li[data-context=application]"
    ).length;

    var applicationFramesButtonIsInstalled = false;
    var applicationFramesButton = document.getElementById("application_frames");
    var allFramesButton = document.getElementById("all_frames");

    // The application frames button only needs to be bound if
    // there are actually any application frames to look at.
    var installApplicationFramesButton = function() {
        applicationFramesButton.onclick = function() {
            allFramesButton.className = "";
            applicationFramesButton.className = "selected";
            for(var i = 0; i < allFrames.length; i++) {
                if(allFrames[i].attributes["data-context"].value == "application") {
                    allFrames[i].style.display = "block";
                } else {
                    allFrames[i].style.display = "none";
                }
            }
            return false;
        };

        applicationFramesButtonIsInstalled = true;
    }

    allFramesButton.onclick = function() {
        if(applicationFramesButtonIsInstalled) {
            applicationFramesButton.className = "";
        }

        allFramesButton.className = "selected";
        for(var i = 0; i < allFrames.length; i++) {
            allFrames[i].style.display = "block";
        }
        return false;
    };

    // If there are no application frames, select the 'All Frames'
    // tab by default.
    if(applicationFramesCount > 0) {
        installApplicationFramesButton();
        applicationFramesButton.onclick();
    } else {
        applicationFramesButton.className = "disabled";
        applicationFramesButton.title = "No application frames available";
        allFramesButton.onclick();
    }
})();
</script>
</html>

<!-- generated by Better Errors in <%= Time.now.to_f - @start_time %> seconds -->
