// Path: spark-common/src/main/java/com/k15t/spark/base/Keys.java
// public class Keys {
// 
//     /**
//      * The param key used in the atlassian-plugin.xml servlet or xwork configuration.
//      */
//     public static final String RESOURCE_PATH = "resource-path";
// 
//     /**
//      * The system property key to be used for the SPARK development directory. Must contain a comma-separated list of absolute paths
//      * representing the base directories to which the app resource paths are relative to. Rule of thumb: one directory for each plugin.
//      *
//      * @see AppServlet#loadFromDevelopmentDirectory(java.lang.String)
//      */
//     public static final String SPARK_DEV_RESOURCE_DIRECTORIES = "spark.dev.dir";
// 
//     /**
//      * Param key to configure to use a specific message bundle provider for using ng-translate.
//      */
//     public static final String NG_TRANS_MSG_BUNDLE = "ng-translate-message-bundle";
// 
//     /**
//      * The param key used in the atlassian-plugin.xml action or servlet configuration for specifying the item to select
//      * in the admin side menu
//      */
//     public static final String SPARK_SELECTED_WEB_ITEM_KEY = "spark-selected-web-item-key";
// 
//     /**
//      * The param key used in the atlassian-plugin.xml action or servlet configuration for specifying the SPA base url.
//      */
//     public static final String SPARK_SPA_BASE_URL = "spark-spa-base-url";
// 
//     /**
//      * <p>
//      * The param key used in the atlassian-plugin.xml for specifying a list of resources that should be required
//      * when loading certain SPARK action.
//      * </p><p>
//      * The parameter value should be a comma-separated list of complete web-resource module keys
//      * </p>
//      */
//     public static final String SPARK_REQUIRED_WEB_RESOURCE_KEYS = "spark-required-web-resource-keys";
// 
// }


import com.atlassian.jira.config.properties.JiraSystemProperties;
import com.atlassian.jira.web.action.JiraWebActionSupport;
import com.k15t.spark.base.Keys;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import webwork.action.ServletActionContext;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
                Document document = Jsoup.parse(indexHtml, "UTF-8", "");

                this.title = document.title();
                this.body = prepareBody(document);
            }

        } catch (IOException e) {
            logger.error("Error parsing HTML of template '" + indexHtmlPath + "'.", e);
            this.title = "Error loading index.html";
            this.body = "<p>Error parsing HTML of template '" + indexHtmlPath + "':<br/>"
                    + e.getMessage()
                    + "</p><pre>" + ExceptionUtils.getStackTrace(e) + "</pre>";
        }
    }


    private InputStream loadIndexHtml(String indexHtmlPath) throws IOException {
        if (JiraSystemProperties.isDevMode()) {
            InputStream dev = loadFromDevelopmentDirectory(indexHtmlPath);
            if (dev != null) {
                return dev;
            }
        }

        return getClass().getClassLoader().getResourceAsStream(indexHtmlPath);
    }


    protected InputStream loadFromDevelopmentDirectory(String localPath) throws IOException {
        InputStream fileIn = null;
// Path: spark-common/src/main/java/com/k15t/spark/base/Keys.java
// public class Keys {
// 
//     /**
//      * The param key used in the atlassian-plugin.xml servlet or xwork configuration.
//      */
//     public static final String RESOURCE_PATH = "resource-path";
// 
//     /**
//      * The system property key to be used for the SPARK development directory. Must contain a comma-separated list of absolute paths
//      * representing the base directories to which the app resource paths are relative to. Rule of thumb: one directory for each plugin.
//      *
//      * @see AppServlet#loadFromDevelopmentDirectory(java.lang.String)
//      */
//     public static final String SPARK_DEV_RESOURCE_DIRECTORIES = "spark.dev.dir";
// 
//     /**
//      * Param key to configure to use a specific message bundle provider for using ng-translate.
//      */
//     public static final String NG_TRANS_MSG_BUNDLE = "ng-translate-message-bundle";
// 
//     /**
//      * The param key used in the atlassian-plugin.xml action or servlet configuration for specifying the item to select
//      * in the admin side menu
//      */
//     public static final String SPARK_SELECTED_WEB_ITEM_KEY = "spark-selected-web-item-key";
// 
//     /**
//      * The param key used in the atlassian-plugin.xml action or servlet configuration for specifying the SPA base url.
//      */
//     public static final String SPARK_SPA_BASE_URL = "spark-spa-base-url";
// 
//     /**
//      * <p>
//      * The param key used in the atlassian-plugin.xml for specifying a list of resources that should be required
//      * when loading certain SPARK action.
//      * </p><p>
//      * The parameter value should be a comma-separated list of complete web-resource module keys
//      * </p>
//      */
//     public static final String SPARK_REQUIRED_WEB_RESOURCE_KEYS = "spark-required-web-resource-keys";
// 
// }


// Path: spark-jira/src/main/java/com/k15t/spark/jira/JiraAppAction.java
import com.atlassian.jira.config.properties.JiraSystemProperties;
import com.atlassian.jira.web.action.JiraWebActionSupport;
import com.k15t.spark.base.Keys;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import webwork.action.ServletActionContext;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

                Document document = Jsoup.parse(indexHtml, "UTF-8", "");

                this.title = document.title();
                this.body = prepareBody(document);
            }

        } catch (IOException e) {
            logger.error("Error parsing HTML of template '" + indexHtmlPath + "'.", e);
            this.title = "Error loading index.html";
            this.body = "<p>Error parsing HTML of template '" + indexHtmlPath + "':<br/>"
                    + e.getMessage()
                    + "</p><pre>" + ExceptionUtils.getStackTrace(e) + "</pre>";
        }
    }


    private InputStream loadIndexHtml(String indexHtmlPath) throws IOException {
        if (JiraSystemProperties.isDevMode()) {
            InputStream dev = loadFromDevelopmentDirectory(indexHtmlPath);
            if (dev != null) {
                return dev;
            }
        }

        return getClass().getClassLoader().getResourceAsStream(indexHtmlPath);
    }


    protected InputStream loadFromDevelopmentDirectory(String localPath) throws IOException {
        InputStream fileIn = null;
        String resourceDirectoryPaths = System.getProperty(Keys.SPARK_DEV_RESOURCE_DIRECTORIES);