{"action":"created","issue":{"url":"https://api.github.com/repos/SKCraft/Launcher/issues/163","repository_url":"https://api.github.com/repos/SKCraft/Launcher","labels_url":"https://api.github.com/repos/SKCraft/Launcher/issues/163/labels{/name}","comments_url":"https://api.github.com/repos/SKCraft/Launcher/issues/163/comments","events_url":"https://api.github.com/repos/SKCraft/Launcher/issues/163/events","html_url":"https://github.com/SKCraft/Launcher/issues/163","id":181785960,"number":163,"title":"Custom ModPack pages","user":{"login":"jtrent238","id":10227394,"avatar_url":"https://avatars.githubusercontent.com/u/10227394?v=3","gravatar_id":"","url":"https://api.github.com/users/jtrent238","html_url":"https://github.com/jtrent238","followers_url":"https://api.github.com/users/jtrent238/followers","following_url":"https://api.github.com/users/jtrent238/following{/other_user}","gists_url":"https://api.github.com/users/jtrent238/gists{/gist_id}","starred_url":"https://api.github.com/users/jtrent238/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jtrent238/subscriptions","organizations_url":"https://api.github.com/users/jtrent238/orgs","repos_url":"https://api.github.com/users/jtrent238/repos","events_url":"https://api.github.com/users/jtrent238/events{/privacy}","received_events_url":"https://api.github.com/users/jtrent238/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":1,"created_at":"2016-10-07T23:14:40Z","updated_at":"2016-10-08T22:32:37Z","closed_at":"2016-10-08T01:35:55Z","body":"```\r\n\r\n*******************************************\r\n You are building SKCraft Launcher!\r\n\r\n Output files will be in [subproject]/build/libs\r\n*******************************************\r\n\r\n:creator-tools:clean UP-TO-DATE\r\n:launcher:clean\r\n:launcher-bootstrap:clean UP-TO-DATE\r\n:launcher-builder:clean UP-TO-DATE\r\n:launcher-fancy:clean UP-TO-DATE\r\n:launcher:compileJava\r\nwarning: [options] bootstrap class path not set in conjunction with -source 1.6\r\nC:\\Users\\trent\\GitHub\\JTMinecraftLauncher.test\\launcher\\src\\main\\java\\com\\skcraf\r\nt\\launcher\\Launcher.java:335: error: method url in class HttpRequest cannot be a\r\npplied to given types;\r\n            return HttpRequest.url(\r\n                              ^\r\n  required: String\r\n  found: String,String\r\n  reason: actual and formal argument lists differ in length\r\n1 error\r\n:launcher:compileJava FAILED\r\n\r\nFAILURE: Build failed with an exception.\r\n\r\n* What went wrong:\r\nExecution failed for task ':launcher:compileJava'.\r\n> Compilation failed; see the compiler error output for details.\r\n\r\n* Try:\r\nRun with --stacktrace option to get the stack trace. Run with --info or --debug\r\noption to get more log output.\r\n\r\nBUILD FAILED\r\n\r\nTotal time: 18.081 secs\r\nPress any key to continue . . .\r\n\r\n```\r\n\r\n```\r\n/*\r\n * SK's Minecraft Launcher\r\n * Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors\r\n * Please see LICENSE.txt for license information.\r\n */\r\n\r\npackage com.skcraft.launcher;\r\n\r\nimport com.beust.jcommander.JCommander;\r\nimport com.beust.jcommander.ParameterException;\r\nimport com.google.common.base.Strings;\r\nimport com.google.common.base.Supplier;\r\nimport com.google.common.util.concurrent.ListeningExecutorService;\r\nimport com.google.common.util.concurrent.MoreExecutors;\r\nimport com.skcraft.launcher.auth.AccountList;\r\nimport com.skcraft.launcher.auth.LoginService;\r\nimport com.skcraft.launcher.auth.YggdrasilLoginService;\r\nimport com.skcraft.launcher.launch.LaunchSupervisor;\r\nimport com.skcraft.launcher.model.minecraft.VersionManifest;\r\nimport com.skcraft.launcher.persistence.Persistence;\r\nimport com.skcraft.launcher.swing.SwingHelper;\r\nimport com.skcraft.launcher.update.UpdateManager;\r\nimport com.skcraft.launcher.util.HttpRequest;\r\nimport com.skcraft.launcher.util.SharedLocale;\r\nimport com.skcraft.launcher.util.SimpleLogFormatter;\r\nimport com.sun.management.OperatingSystemMXBean;\r\nimport lombok.Getter;\r\nimport lombok.NonNull;\r\nimport lombok.Setter;\r\nimport lombok.extern.java.Log;\r\nimport org.apache.commons.io.FileUtils;\r\n\r\nimport javax.swing.*;\r\nimport java.awt.*;\r\nimport java.io.File;\r\nimport java.io.FileFilter;\r\nimport java.io.IOException;\r\nimport java.io.UnsupportedEncodingException;\r\nimport java.lang.management.ManagementFactory;\r\nimport java.net.URL;\r\nimport java.net.URLEncoder;\r\nimport java.util.Locale;\r\nimport java.util.Properties;\r\nimport java.util.concurrent.Executors;\r\nimport java.util.logging.Level;\r\n\r\nimport static com.skcraft.launcher.util.SharedLocale.tr;\r\n\r\n/**\r\n * The main entry point for the launcher.\r\n */\r\n@Log\r\npublic final class Launcher {\r\n\r\n    public static final int PROTOCOL_VERSION = 2;\r\n\r\n    @Getter\r\n    private final ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());\r\n    @Getter @Setter private Supplier<Window> mainWindowSupplier = new DefaultLauncherSupplier(this);\r\n    @Getter private final File baseDir;\r\n    @Getter private final Properties properties;\r\n    @Getter private final InstanceList instances;\r\n    @Getter private final Configuration config;\r\n    @Getter private final AccountList accounts;\r\n    @Getter private final AssetsRoot assets;\r\n    @Getter private final LaunchSupervisor launchSupervisor = new LaunchSupervisor(this);\r\n    @Getter private final UpdateManager updateManager = new UpdateManager(this);\r\n    @Getter private final InstanceTasks instanceTasks = new InstanceTasks(this);\r\n\r\n    /**\r\n     * Create a new launcher instance with the given base directory.\r\n     *\r\n     * @param baseDir the base directory\r\n     * @throws java.io.IOException on load error\r\n     */\r\n    public Launcher(@NonNull File baseDir) throws IOException {\r\n        this(baseDir, baseDir);\r\n    }\r\n\r\n    /**\r\n     * Create a new launcher instance with the given base and configuration\r\n     * directories.\r\n     *\r\n     * @param baseDir the base directory\r\n     * @param configDir the config directory\r\n     * @throws java.io.IOException on load error\r\n     */\r\n    public Launcher(@NonNull File baseDir, @NonNull File configDir) throws IOException {\r\n        SharedLocale.loadBundle(\"com.skcraft.launcher.lang.Launcher\", Locale.getDefault());\r\n\r\n        this.baseDir = baseDir;\r\n        this.properties = LauncherUtils.loadProperties(Launcher.class, \"launcher.properties\", \"com.skcraft.launcher.propertiesFile\");\r\n        this.instances = new InstanceList(this);\r\n        this.assets = new AssetsRoot(new File(baseDir, \"assets\"));\r\n        this.config = Persistence.load(new File(configDir, \"config.json\"), Configuration.class);\r\n        this.accounts = Persistence.load(new File(configDir, \"accounts.dat\"), AccountList.class);\r\n\r\n        setDefaultConfig();\r\n\r\n        if (accounts.getSize() > 0) {\r\n            accounts.setSelectedItem(accounts.getElementAt(0));\r\n        }\r\n\r\n        executor.submit(new Runnable() {\r\n            @Override\r\n            public void run() {\r\n                cleanupExtractDir();\r\n            }\r\n        });\r\n\r\n        updateManager.checkForUpdate();\r\n    }\r\n\r\n    /**\r\n     * Updates any incorrect / unset configuration settings with defaults.\r\n     */\r\n    public void setDefaultConfig() {\r\n        double configMax = config.getMaxMemory() / 1024.0;\r\n        double suggestedMax = 2;\r\n        double available = Double.MAX_VALUE;\r\n\r\n        try {\r\n            OperatingSystemMXBean bean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();\r\n            available = bean.getTotalPhysicalMemorySize() / 1024.0 / 1024.0 / 1024.0;\r\n            if (available <= 6) {\r\n                suggestedMax = available * 0.48;\r\n            } else {\r\n                suggestedMax = 4;\r\n            }\r\n        } catch (Exception ignored) {\r\n        }\r\n\r\n        if (config.getMaxMemory() <= 0 || configMax >= available - 1) {\r\n            config.setMaxMemory((int) (suggestedMax * 1024));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Get the launcher version.\r\n     *\r\n     * @return the launcher version\r\n     */\r\n    public String getVersion() {\r\n        String version = getProperties().getProperty(\"version\");\r\n        if (version.equals(\"${project.version}\")) {\r\n            return \"1.0.0-SNAPSHOT\";\r\n        }\r\n        return version;\r\n    }\r\n\r\n    /**\r\n     * Get a login service.\r\n     *\r\n     * @return a login service\r\n     */\r\n    public LoginService getLoginService() {\r\n        return new YggdrasilLoginService(HttpRequest.url(getProperties().getProperty(\"yggdrasilAuthUrl\")));\r\n    }\r\n\r\n    /**\r\n     * Get the directory containing the instances.\r\n     *\r\n     * @return the instances dir\r\n     */\r\n    public File getInstancesDir() {\r\n        return new File(getBaseDir(), \"instances\");\r\n    }\r\n\r\n    /**\r\n     * Get the directory to store temporary files.\r\n     *\r\n     * @return the temporary directory\r\n     */\r\n    public File getTemporaryDir() {\r\n        return new File(getBaseDir(), \"temp\");\r\n    }\r\n\r\n    /**\r\n     * Get the directory to store temporary install files.\r\n     *\r\n     * @return the temporary install directory\r\n     */\r\n    public File getInstallerDir() {\r\n        return new File(getTemporaryDir(), \"install\");\r\n    }\r\n\r\n    /**\r\n     * Get the directory to store temporarily extracted files.\r\n     *\r\n     * @return the directory\r\n     */\r\n    private File getExtractDir() {\r\n        return new File(getTemporaryDir(), \"extract\");\r\n    }\r\n\r\n    /**\r\n     * Delete old extracted files.\r\n     */\r\n    public void cleanupExtractDir() {\r\n        log.info(\"Cleaning up temporary extracted files directory...\");\r\n\r\n        final long now = System.currentTimeMillis();\r\n\r\n        File[] dirs = getExtractDir().listFiles(new FileFilter() {\r\n            @Override\r\n            public boolean accept(File pathname) {\r\n                try {\r\n                    long time = Long.parseLong(pathname.getName());\r\n                    return (now - time) > (1000 * 60 * 60);\r\n                } catch (NumberFormatException e) {\r\n                    return false;\r\n                }\r\n            }\r\n        });\r\n\r\n        if (dirs != null) {\r\n            for (File dir : dirs) {\r\n                log.info(\"Removing \" + dir.getAbsolutePath() + \"...\");\r\n                try {\r\n                    FileUtils.deleteDirectory(dir);\r\n                } catch (IOException e) {\r\n                    log.log(Level.WARNING, \"Failed to delete \" + dir.getAbsolutePath(), e);\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Create a new temporary directory to extract files to.\r\n     *\r\n     * @return the directory path\r\n     */\r\n    public File createExtractDir() {\r\n        File dir = new File(getExtractDir(), String.valueOf(System.currentTimeMillis()));\r\n        dir.mkdirs();\r\n        log.info(\"Created temporary directory \" + dir.getAbsolutePath());\r\n        return dir;\r\n    }\r\n\r\n    /**\r\n     * Get the directory to store the launcher binaries.\r\n     *\r\n     * @return the libraries directory\r\n     */\r\n    public File getLauncherBinariesDir() {\r\n        return new File(getBaseDir(), \"launcher\");\r\n    }\r\n\r\n    /**\r\n     * Get the directory to store common data files.\r\n     *\r\n     * @return the common data directory\r\n     */\r\n    public File getCommonDataDir() {\r\n        return getBaseDir();\r\n    }\r\n\r\n    /**\r\n     * Get the directory to store libraries.\r\n     *\r\n     * @return the libraries directory\r\n     */\r\n    public File getLibrariesDir() {\r\n        return new File(getCommonDataDir(), \"libraries\");\r\n    }\r\n\r\n    /**\r\n     * Get the directory to store versions.\r\n     *\r\n     * @return the versions directory\r\n     */\r\n    public File getVersionsDir() {\r\n        return new File(getCommonDataDir(), \"versions\");\r\n    }\r\n\r\n    /**\r\n     * Get the directory to store a version.\r\n     *\r\n     * @param version the version\r\n     * @return the directory\r\n     */\r\n    public File getVersionDir(String version) {\r\n        return new File(getVersionsDir(), version);\r\n    }\r\n\r\n    /**\r\n     * Get the path to the JAR for the given version manifest.\r\n     *\r\n     * @param versionManifest the version manifest\r\n     * @return the path\r\n     */\r\n    public File getJarPath(VersionManifest versionManifest) {\r\n        return new File(getVersionDir(versionManifest.getId()), versionManifest.getId() + \".jar\");\r\n    }\r\n\r\n    /**\r\n     * Get the news URL.\r\n     *\r\n     * @return the news URL\r\n     */\r\n    public URL getNewsURL() {\r\n        try {\r\n            return HttpRequest.url(\r\n                    String.format(getProperties().getProperty(\"newsUrl\"),\r\n                            URLEncoder.encode(getVersion(), \"UTF-8\")));\r\n        } catch (UnsupportedEncodingException e) {\r\n            throw new RuntimeException(e);\r\n        }\r\n    }\r\n\t\r\n\t/**\r\n     * Get the Pack URL.\r\n     *\r\n     * @return the Pack URL\r\n     */\r\n    public URL getPackURL() {\r\n        try {\r\n            return HttpRequest.url(\r\n                    String.format(getProperties().getProperty(\"packUrl\"),\r\n                            URLEncoder.encode(getVersion(), \"UTF-8\")));\r\n        } catch (UnsupportedEncodingException e) {\r\n            throw new RuntimeException(e);\r\n        }\r\n    }\r\n\r\n\t\r\n\t/**\r\n     * Get the packages URL.\r\n     *\r\n     * @return the packages URL\r\n     */\r\n    public URL getPackagesURL() {\r\n        try {\r\n            String key = Strings.nullToEmpty(getConfig().getGameKey());\r\n            return HttpRequest.url(\r\n                    String.format(getProperties().getProperty(\"packageListUrl\")),\r\n                            URLEncoder.encode(key, \"UTF-8\"));\r\n        } catch (UnsupportedEncodingException e) {\r\n            throw new RuntimeException(e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Convenient method to fetch a property.\r\n     *\r\n     * @param key the key\r\n     * @return the property\r\n     */\r\n    public String prop(String key) {\r\n        return getProperties().getProperty(key);\r\n    }\r\n\r\n    /**\r\n     * Convenient method to fetch a property.\r\n     *\r\n     * @param key the key\r\n     * @param args formatting arguments\r\n     * @return the property\r\n     */\r\n    public String prop(String key, String... args) {\r\n        return String.format(getProperties().getProperty(key), (Object[]) args);\r\n    }\r\n\r\n    /**\r\n     * Convenient method to fetch a property.\r\n     *\r\n     * @param key the key\r\n     * @return the property\r\n     */\r\n    public URL propUrl(String key) {\r\n        return HttpRequest.url(prop(key));\r\n    }\r\n\r\n    /**\r\n     * Convenient method to fetch a property.\r\n     *\r\n     * @param key the key\r\n     * @param args formatting arguments\r\n     * @return the property\r\n     */\r\n    public URL propUrl(String key, String... args) {\r\n        return HttpRequest.url(prop(key, args));\r\n    }\r\n\r\n    /**\r\n     * Show the launcher.\r\n     */\r\n    public void showLauncherWindow() {\r\n        mainWindowSupplier.get().setVisible(true);\r\n    }\r\n\r\n    /**\r\n     * Create a new launcher from arguments.\r\n     *\r\n     * @param args the arguments\r\n     * @return the launcher\r\n     * @throws ParameterException thrown on a bad parameter\r\n     * @throws IOException throw on an I/O error\r\n     */\r\n    public static Launcher createFromArguments(String[] args) throws ParameterException, IOException {\r\n        LauncherArguments options = new LauncherArguments();\r\n        new JCommander(options, args);\r\n\r\n        Integer bsVersion = options.getBootstrapVersion();\r\n        log.info(bsVersion != null ? \"Bootstrap version \" + bsVersion + \" detected\" : \"Not bootstrapped\");\r\n\r\n        File dir = options.getDir();\r\n        if (dir != null) {\r\n            log.info(\"Using given base directory \" + dir.getAbsolutePath());\r\n        } else {\r\n            dir = new File(\".\");\r\n            log.info(\"Using current directory \" + dir.getAbsolutePath());\r\n        }\r\n\r\n        return new Launcher(dir);\r\n    }\r\n\r\n    /**\r\n     * Setup loggers and perform initialization.\r\n     */\r\n    public static void setupLogger() {\r\n        SimpleLogFormatter.configureGlobalLogger();\r\n    }\r\n\r\n    /**\r\n     * Bootstrap.\r\n     *\r\n     * @param args args\r\n     */\r\n    public static void main(final String[] args) {\r\n        setupLogger();\r\n\r\n        SwingUtilities.invokeLater(new Runnable() {\r\n            @Override\r\n            public void run() {\r\n                try {\r\n                    Launcher launcher = createFromArguments(args);\r\n                    SwingHelper.setSwingProperties(tr(\"launcher.appTitle\", launcher.getVersion()));\r\n                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());\r\n                    launcher.showLauncherWindow();\r\n                } catch (Throwable t) {\r\n                    log.log(Level.WARNING, \"Load failure\", t);\r\n                    SwingHelper.showErrorDialog(null, \"Uh oh! The updater couldn't be opened because a \" +\r\n                            \"problem was encountered.\", \"Launcher error\", t);\r\n                }\r\n            }\r\n        });\r\n\r\n    }\r\n\r\n}\r\n```\r\n\r\n```\r\n/*\r\n * SK's Minecraft Launcher\r\n * Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors\r\n * Please see LICENSE.txt for license information.\r\n */\r\n\r\npackage com.skcraft.launcher.dialog;\r\n\r\nimport com.skcraft.concurrency.ObservableFuture;\r\nimport com.skcraft.launcher.Instance;\r\nimport com.skcraft.launcher.InstanceList;\r\nimport com.skcraft.launcher.Launcher;\r\nimport com.skcraft.launcher.launch.LaunchListener;\r\nimport com.skcraft.launcher.launch.LaunchOptions;\r\nimport com.skcraft.launcher.launch.LaunchOptions.UpdatePolicy;\r\nimport com.skcraft.launcher.swing.*;\r\nimport com.skcraft.launcher.util.SharedLocale;\r\nimport com.skcraft.launcher.util.SwingExecutor;\r\nimport lombok.Getter;\r\nimport lombok.NonNull;\r\nimport lombok.extern.java.Log;\r\nimport net.miginfocom.swing.MigLayout;\r\n\r\nimport javax.swing.*;\r\nimport javax.swing.event.TableModelEvent;\r\nimport javax.swing.event.TableModelListener;\r\nimport java.awt.*;\r\nimport java.awt.event.ActionEvent;\r\nimport java.awt.event.ActionListener;\r\nimport java.awt.event.MouseEvent;\r\nimport java.beans.PropertyChangeEvent;\r\nimport java.beans.PropertyChangeListener;\r\nimport java.io.File;\r\nimport java.lang.ref.WeakReference;\r\n\r\nimport static com.skcraft.launcher.util.SharedLocale.tr;\r\n\r\n/**\r\n * The main launcher frame.\r\n */\r\n@Log\r\npublic class LauncherFrame extends JFrame {\r\n\r\n    private final Launcher launcher;\r\n\r\n    @Getter\r\n    private final InstanceTable instancesTable = new InstanceTable();\r\n    private final InstanceTableModel instancesModel;\r\n    @Getter\r\n    private final JScrollPane instanceScroll = new JScrollPane(instancesTable);\r\n    private WebpagePanel webView;\r\n    private JSplitPane splitPane;\r\n    private final JButton launchButton = new JButton(SharedLocale.tr(\"launcher.launch\"));\r\n    private final JButton refreshButton = new JButton(SharedLocale.tr(\"launcher.checkForUpdates\"));\r\n    private final JButton optionsButton = new JButton(SharedLocale.tr(\"launcher.options\"));\r\n    private final JButton selfUpdateButton = new JButton(SharedLocale.tr(\"launcher.updateLauncher\"));\r\n    private final JCheckBox updateCheck = new JCheckBox(SharedLocale.tr(\"launcher.downloadUpdates\"));\r\n\r\n    /**\r\n     * Create a new frame.\r\n     *\r\n     * @param launcher the launcher\r\n     */\r\n    public LauncherFrame(@NonNull Launcher launcher) {\r\n        super(tr(\"launcher.title\", launcher.getVersion()));\r\n\r\n        this.launcher = launcher;\r\n        instancesModel = new InstanceTableModel(launcher.getInstances());\r\n\r\n        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);\r\n        setMinimumSize(new Dimension(400, 300));\r\n        initComponents();\r\n        pack();\r\n        setLocationRelativeTo(null);\r\n\r\n        SwingHelper.setIconImage(this, Launcher.class, \"icon.png\");\r\n\r\n        SwingUtilities.invokeLater(new Runnable() {\r\n            @Override\r\n            public void run() {\r\n                loadInstances();\r\n            }\r\n        });\r\n    }\r\n\r\n    private void initComponents() {\r\n        JPanel container = createContainerPanel();\r\n        container.setLayout(new MigLayout(\"fill, insets dialog\", \"[][]push[][]\", \"[grow][]\"));\r\n\r\n        webView = createNewsPanel();\r\n        splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, instanceScroll, webView);\r\n        selfUpdateButton.setVisible(launcher.getUpdateManager().getPendingUpdate());\r\n\r\n        launcher.getUpdateManager().addPropertyChangeListener(new PropertyChangeListener() {\r\n            @Override\r\n            public void propertyChange(PropertyChangeEvent evt) {\r\n                if (evt.getPropertyName().equals(\"pendingUpdate\")) {\r\n                    selfUpdateButton.setVisible((Boolean) evt.getNewValue());\r\n\r\n                }\r\n            }\r\n        });\r\n\r\n        updateCheck.setSelected(true);\r\n        instancesTable.setModel(instancesModel);\r\n        launchButton.setFont(launchButton.getFont().deriveFont(Font.BOLD));\r\n        splitPane.setDividerLocation(200);\r\n        splitPane.setDividerSize(4);\r\n        splitPane.setOpaque(false);\r\n        container.add(splitPane, \"grow, wrap, span 5, gapbottom unrel, w null:680, h null:350\");\r\n        SwingHelper.flattenJSplitPane(splitPane);\r\n        container.add(refreshButton);\r\n        container.add(updateCheck);\r\n        container.add(selfUpdateButton);\r\n        container.add(optionsButton);\r\n        container.add(launchButton);\r\n\r\n        add(container, BorderLayout.CENTER);\r\n\r\n        instancesModel.addTableModelListener(new TableModelListener() {\r\n            @Override\r\n            public void tableChanged(TableModelEvent e) {\r\n                if (instancesTable.getRowCount() > 0) {\r\n                    instancesTable.setRowSelectionInterval(0, 0);\r\n                }\r\n            }\r\n        });\r\n\r\n        instancesTable.addMouseListener(new DoubleClickToButtonAdapter(launchButton));\r\n\r\n        refreshButton.addActionListener(new ActionListener() {\r\n            @Override\r\n            public void actionPerformed(ActionEvent e) {\r\n                loadInstances();\r\n                launcher.getUpdateManager().checkForUpdate();\r\n            }\r\n        });\r\n\r\n        selfUpdateButton.addActionListener(new ActionListener() {\r\n            @Override\r\n            public void actionPerformed(ActionEvent e) {\r\n                launcher.getUpdateManager().performUpdate(LauncherFrame.this);\r\n            }\r\n        });\r\n\r\n        optionsButton.addActionListener(new ActionListener() {\r\n            @Override\r\n            public void actionPerformed(ActionEvent e) {\r\n                showOptions();\r\n            }\r\n        });\r\n\r\n        launchButton.addActionListener(new ActionListener() {\r\n            @Override\r\n            public void actionPerformed(ActionEvent e) {\r\n                launch();\r\n            }\r\n        });\r\n\r\n        instancesTable.addMouseListener(new PopupMouseAdapter() {\r\n            @Override\r\n            protected void showPopup(MouseEvent e) {\r\n                int index = instancesTable.rowAtPoint(e.getPoint());\r\n                Instance selected = null;\r\n                if (index >= 0) {\r\n                    instancesTable.setRowSelectionInterval(index, index);\r\n                    selected = launcher.getInstances().get(index);\r\n                }\r\n                popupInstanceMenu(e.getComponent(), e.getX(), e.getY(), selected);\r\n            }\r\n        });\r\n    }\r\n\r\n    protected JPanel createContainerPanel() {\r\n        return new JPanel();\r\n    }\r\n\r\n    /**\r\n     * Return the news panel.\r\n     *\r\n     * @return the news panel\r\n     */\r\n    protected WebpagePanel createNewsPanel() {\r\n        return WebpagePanel.forURL(launcher.getNewsURL(), false);\r\n    }\r\n\r\n\t/**\r\n     * Return the Pack panel.\r\n     *\r\n     * @return the Pack panel\r\n     */\r\n    protected WebpagePanel createPackPanel() {\r\n        return WebpagePanel.forURL(launcher.getPackURL(), false);\r\n    }\r\n    /**\r\n     * Popup the menu for the instances.\r\n     *\r\n     * @param component the component\r\n     * @param x mouse X\r\n     * @param y mouse Y\r\n     * @param selected the selected instance, possibly null\r\n     */\r\n    private void popupInstanceMenu(Component component, int x, int y, final Instance selected) {\r\n        JPopupMenu popup = new JPopupMenu();\r\n        JMenuItem menuItem;\r\n\r\n        if (selected != null) {\r\n            menuItem = new JMenuItem(!selected.isLocal() ? tr(\"instance.install\") : tr(\"instance.launch\"));\r\n            menuItem.addActionListener(new ActionListener() {\r\n                @Override\r\n                public void actionPerformed(ActionEvent e) {\r\n                    launch();\r\n                }\r\n            });\r\n            popup.add(menuItem);\r\n\r\n            if (selected.isLocal()) {\r\n                popup.addSeparator();\r\n\r\n                menuItem = new JMenuItem(SharedLocale.tr(\"instance.openFolder\"));\r\n                menuItem.addActionListener(ActionListeners.browseDir(\r\n                        LauncherFrame.this, selected.getContentDir(), true));\r\n                popup.add(menuItem);\r\n\r\n                menuItem = new JMenuItem(SharedLocale.tr(\"instance.openSaves\"));\r\n                menuItem.addActionListener(ActionListeners.browseDir(\r\n                        LauncherFrame.this, new File(selected.getContentDir(), \"saves\"), true));\r\n                popup.add(menuItem);\r\n\r\n                menuItem = new JMenuItem(SharedLocale.tr(\"instance.openResourcePacks\"));\r\n                menuItem.addActionListener(ActionListeners.browseDir(\r\n                        LauncherFrame.this, new File(selected.getContentDir(), \"resourcepacks\"), true));\r\n                popup.add(menuItem);\r\n\r\n                menuItem = new JMenuItem(SharedLocale.tr(\"instance.openScreenshots\"));\r\n                menuItem.addActionListener(ActionListeners.browseDir(\r\n                        LauncherFrame.this, new File(selected.getContentDir(), \"screenshots\"), true));\r\n                popup.add(menuItem);\r\n\r\n                menuItem = new JMenuItem(SharedLocale.tr(\"instance.copyAsPath\"));\r\n                menuItem.addActionListener(new ActionListener() {\r\n                    @Override\r\n                    public void actionPerformed(ActionEvent e) {\r\n                        File dir = selected.getContentDir();\r\n                        dir.mkdirs();\r\n                        SwingHelper.setClipboard(dir.getAbsolutePath());\r\n                    }\r\n                });\r\n                popup.add(menuItem);\r\n\r\n                popup.addSeparator();\r\n\r\n                if (!selected.isUpdatePending()) {\r\n                    menuItem = new JMenuItem(SharedLocale.tr(\"instance.forceUpdate\"));\r\n                    menuItem.addActionListener(new ActionListener() {\r\n                        @Override\r\n                        public void actionPerformed(ActionEvent e) {\r\n                            selected.setUpdatePending(true);\r\n                            launch();\r\n                            instancesModel.update();\r\n                        }\r\n                    });\r\n                    popup.add(menuItem);\r\n                }\r\n\r\n                menuItem = new JMenuItem(SharedLocale.tr(\"instance.hardForceUpdate\"));\r\n                menuItem.addActionListener(new ActionListener() {\r\n                    @Override\r\n                    public void actionPerformed(ActionEvent e) {\r\n                        confirmHardUpdate(selected);\r\n                    }\r\n                });\r\n                popup.add(menuItem);\r\n\r\n                menuItem = new JMenuItem(SharedLocale.tr(\"instance.deleteFiles\"));\r\n                menuItem.addActionListener(new ActionListener() {\r\n                    @Override\r\n                    public void actionPerformed(ActionEvent e) {\r\n                        confirmDelete(selected);\r\n                    }\r\n                });\r\n                popup.add(menuItem);\r\n            }\r\n\r\n            popup.addSeparator();\r\n        }\r\n\r\n        menuItem = new JMenuItem(SharedLocale.tr(\"launcher.refreshList\"));\r\n        menuItem.addActionListener(new ActionListener() {\r\n            @Override\r\n            public void actionPerformed(ActionEvent e) {\r\n                loadInstances();\r\n            }\r\n        });\r\n        popup.add(menuItem);\r\n\r\n        popup.show(component, x, y);\r\n\r\n    }\r\n\r\n    private void confirmDelete(Instance instance) {\r\n        if (!SwingHelper.confirmDialog(this,\r\n                tr(\"instance.confirmDelete\", instance.getTitle()), SharedLocale.tr(\"confirmTitle\"))) {\r\n            return;\r\n        }\r\n\r\n        ObservableFuture<Instance> future = launcher.getInstanceTasks().delete(this, instance);\r\n\r\n        // Update the list of instances after updating\r\n        future.addListener(new Runnable() {\r\n            @Override\r\n            public void run() {\r\n                loadInstances();\r\n            }\r\n        }, SwingExecutor.INSTANCE);\r\n    }\r\n\r\n    private void confirmHardUpdate(Instance instance) {\r\n        if (!SwingHelper.confirmDialog(this, SharedLocale.tr(\"instance.confirmHardUpdate\"), SharedLocale.tr(\"confirmTitle\"))) {\r\n            return;\r\n        }\r\n\r\n        ObservableFuture<Instance> future = launcher.getInstanceTasks().hardUpdate(this, instance);\r\n\r\n        // Update the list of instances after updating\r\n        future.addListener(new Runnable() {\r\n            @Override\r\n            public void run() {\r\n                launch();\r\n                instancesModel.update();\r\n            }\r\n        }, SwingExecutor.INSTANCE);\r\n    }\r\n\r\n    private void loadInstances() {\r\n        ObservableFuture<InstanceList> future = launcher.getInstanceTasks().reloadInstances(this);\r\n\r\n        future.addListener(new Runnable() {\r\n            @Override\r\n            public void run() {\r\n                instancesModel.update();\r\n                if (instancesTable.getRowCount() > 0) {\r\n                    instancesTable.setRowSelectionInterval(0, 0);\r\n                }\r\n                requestFocus();\r\n            }\r\n        }, SwingExecutor.INSTANCE);\r\n\r\n        ProgressDialog.showProgress(this, future, SharedLocale.tr(\"launcher.checkingTitle\"), SharedLocale.tr(\"launcher.checkingStatus\"));\r\n        SwingHelper.addErrorDialogCallback(this, future);\r\n    }\r\n\r\n    private void showOptions() {\r\n        ConfigurationDialog configDialog = new ConfigurationDialog(this, launcher);\r\n        configDialog.setVisible(true);\r\n    }\r\n\r\n    private void launch() {\r\n        boolean permitUpdate = updateCheck.isSelected();\r\n        Instance instance = launcher.getInstances().get(instancesTable.getSelectedRow());\r\n\r\n        LaunchOptions options = new LaunchOptions.Builder()\r\n                .setInstance(instance)\r\n                .setListener(new LaunchListenerImpl(this))\r\n                .setUpdatePolicy(permitUpdate ? UpdatePolicy.UPDATE_IF_SESSION_ONLINE : UpdatePolicy.NO_UPDATE)\r\n                .setWindow(this)\r\n                .build();\r\n        launcher.getLaunchSupervisor().launch(options);\r\n    }\r\n\r\n    private static class LaunchListenerImpl implements LaunchListener {\r\n        private final WeakReference<LauncherFrame> frameRef;\r\n        private final Launcher launcher;\r\n\r\n        private LaunchListenerImpl(LauncherFrame frame) {\r\n            this.frameRef = new WeakReference<LauncherFrame>(frame);\r\n            this.launcher = frame.launcher;\r\n        }\r\n\r\n        @Override\r\n        public void instancesUpdated() {\r\n            LauncherFrame frame = frameRef.get();\r\n            if (frame != null) {\r\n                frame.instancesModel.update();\r\n            }\r\n        }\r\n\r\n        @Override\r\n        public void gameStarted() {\r\n            LauncherFrame frame = frameRef.get();\r\n            if (frame != null) {\r\n                frame.dispose();\r\n            }\r\n        }\r\n\r\n        @Override\r\n        public void gameClosed() {\r\n            launcher.showLauncherWindow();\r\n        }\r\n    }\r\n\r\n}\r\n```\r\n```\r\n/*\r\n * SK's Minecraft Launcher\r\n * Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors\r\n * Please see LICENSE.txt for license information.\r\n */\r\n\r\npackage com.skcraft.launcher.model.modpack;\r\n\r\nimport com.fasterxml.jackson.annotation.JsonIgnore;\r\nimport com.fasterxml.jackson.annotation.JsonManagedReference;\r\nimport com.fasterxml.jackson.annotation.JsonProperty;\r\nimport com.google.common.base.Strings;\r\nimport com.skcraft.launcher.Instance;\r\nimport com.skcraft.launcher.LauncherUtils;\r\nimport com.skcraft.launcher.model.minecraft.VersionManifest;\r\nimport com.skcraft.launcher.install.Installer;\r\nimport lombok.Data;\r\nimport lombok.EqualsAndHashCode;\r\nimport lombok.Getter;\r\nimport lombok.Setter;\r\n\r\nimport java.net.MalformedURLException;\r\nimport java.net.URL;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\n@Data\r\n@EqualsAndHashCode(callSuper = true)\r\npublic class Manifest extends BaseManifest {\r\n\r\n    public static final int MIN_PROTOCOL_VERSION = 2;\r\n\r\n    private int minimumVersion;\r\n    private URL baseUrl;\r\n    private String librariesLocation;\r\n    private String objectsLocation;\r\n    private String gameVersion;\r\n    @JsonProperty(\"launch\")\r\n    private LaunchModifier launchModifier;\r\n    private List<Feature> features = new ArrayList<Feature>();\r\n    @JsonManagedReference(\"manifest\")\r\n    private List<ManifestEntry> tasks = new ArrayList<ManifestEntry>();\r\n    @Getter @Setter @JsonIgnore\r\n    private Installer installer;\r\n    private VersionManifest versionManifest;\r\n\r\n    @JsonIgnore\r\n    public URL getLibrariesUrl() {\r\n        if (Strings.nullToEmpty(getLibrariesLocation()) == null) {\r\n            return null;\r\n        }\r\n\r\n        try {\r\n            return LauncherUtils.concat(baseUrl, Strings.nullToEmpty(getLibrariesLocation()) + \"/\");\r\n        } catch (MalformedURLException e) {\r\n            throw new RuntimeException(e);\r\n        }\r\n    }\r\n\r\n    @JsonIgnore\r\n    public URL getObjectsUrl() {\r\n        if (Strings.nullToEmpty(getObjectsLocation()) == null) {\r\n            return baseUrl;\r\n        }\r\n\r\n        try {\r\n            return LauncherUtils.concat(baseUrl, Strings.nullToEmpty(getObjectsLocation()) + \"/\");\r\n        } catch (MalformedURLException e) {\r\n            throw new RuntimeException(e);\r\n        }\r\n    }\r\n\r\n    public void updateName(String name) {\r\n        if (name != null) {\r\n            setName(name);\r\n        }\r\n    }\r\n\r\n    public void updateTitle(String title) {\r\n        if (title != null) {\r\n            setTitle(title);\r\n        }\r\n    }\r\n\r\n    public void updateGameVersion(String gameVersion) {\r\n        if (gameVersion != null) {\r\n            setGameVersion(gameVersion);\r\n        }\r\n    }\r\n\r\n    public void update(Instance instance) {\r\n        instance.setLaunchModifier(getLaunchModifier());\r\n    }\r\n}\r\n```\r\n```\r\n#\r\n# SK's Minecraft Launcher\r\n# Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors\r\n# Please see LICENSE.txt for license information.\r\n#\r\n\r\nversion=${project.version}\r\nagentName=Minecraft\r\nofflinePlayerName=Player\r\n\r\nversionManifestUrl=https://s3.amazonaws.com/Minecraft.Download/versions/%1$s/%1$s.json\r\nlibrariesSource=https://libraries.minecraft.net/\r\njarUrl=http://s3.amazonaws.com/Minecraft.Download/versions/%1$s/%1$s.jar\r\nassetsIndexUrl=https://s3.amazonaws.com/Minecraft.Download/indexes/%s.json\r\nassetsSource=http://resources.download.minecraft.net/\r\nyggdrasilAuthUrl=https://authserver.mojang.com/authenticate\r\nresetPasswordUrl=https://minecraft.net/resetpassword\r\n\r\nnewsUrl=http://jtrent238.github.io/JTMinecraftLauncher/news.html?version=%s\r\npackUrl=http://jtrent238.github.io/JTMinecraftLauncher/news.html?version=%s\r\npackageListUrl=http://jtrent238.github.io/JTMinecraftLauncher/%name%.html\r\nselfUpdateUrl=http://jtrent238.github.io/JTMinecraftLauncher/latest.json\r\n```"},"comment":{"url":"https://api.github.com/repos/SKCraft/Launcher/issues/comments/252452188","html_url":"https://github.com/SKCraft/Launcher/issues/163#issuecomment-252452188","issue_url":"https://api.github.com/repos/SKCraft/Launcher/issues/163","id":252452188,"user":{"login":"jtrent238","id":10227394,"avatar_url":"https://avatars.githubusercontent.com/u/10227394?v=3","gravatar_id":"","url":"https://api.github.com/users/jtrent238","html_url":"https://github.com/jtrent238","followers_url":"https://api.github.com/users/jtrent238/followers","following_url":"https://api.github.com/users/jtrent238/following{/other_user}","gists_url":"https://api.github.com/users/jtrent238/gists{/gist_id}","starred_url":"https://api.github.com/users/jtrent238/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jtrent238/subscriptions","organizations_url":"https://api.github.com/users/jtrent238/orgs","repos_url":"https://api.github.com/users/jtrent238/repos","events_url":"https://api.github.com/users/jtrent238/events{/privacy}","received_events_url":"https://api.github.com/users/jtrent238/received_events","type":"User","site_admin":false},"created_at":"2016-10-08T22:32:37Z","updated_at":"2016-10-08T22:32:37Z","body":"@sk89q I guess that is what it kept saying with the error."}}
{"actor":{"display_login":"jtrent238"}}