diff --git a/Mage.Client/src/main/java/mage/client/cards/ManaPieChart.java b/Mage.Client/src/main/java/mage/client/cards/ManaPieChart.java
index a8d447e700..cf33d0e1e7 100644
--- a/Mage.Client/src/main/java/mage/client/cards/ManaPieChart.java
+++ b/Mage.Client/src/main/java/mage/client/cards/ManaPieChart.java
@@ -67,6 +67,10 @@ public class ManaPieChart extends JComponent {
         for (int i = 0; i < slices.length; i++) {
             total += slices[i].value;
         }
+        
+        if (total == 0.0D) {
+            return; //there are no slices or no slices with a value > 0, stop here
+        }
 
         double curValue = 0.0D;
         int startAngle = 0;
diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportFromClipboardDialog.java b/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportFromClipboardDialog.java
index 1eeb251ad4..eef1987dfa 100644
--- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportFromClipboardDialog.java
+++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportFromClipboardDialog.java
@@ -1,5 +1,7 @@
 package mage.client.deckeditor;
 
+import mage.util.StreamUtils;
+
 import java.awt.*;
 import java.awt.event.*;
 import java.io.BufferedWriter;
@@ -39,15 +41,16 @@ public class DeckImportFromClipboardDialog extends JDialog {
     }
 
     private void onOK() {
+        BufferedWriter bw = null;
         try {
             File temp = File.createTempFile("cbimportdeck", ".txt");
-            BufferedWriter bw = new BufferedWriter(new FileWriter(temp));
+            bw = new BufferedWriter(new FileWriter(temp));
             bw.write(txtDeckList.getText());
-            bw.close();
-
             tmpPath = temp.getPath();
         } catch (IOException e) {
             e.printStackTrace();
+        } finally {
+            StreamUtils.closeQuietly(bw);
         }
 
         dispose();
diff --git a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java
index e1dee12925..25164a55aa 100644
--- a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java
+++ b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java
@@ -43,6 +43,7 @@ import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.InputStreamReader;
 import java.io.Writer;
+import java.io.Closeable;
 import java.net.InetSocketAddress;
 import java.net.Proxy;
 import java.net.SocketException;
@@ -73,6 +74,7 @@ import mage.client.util.Config;
 import mage.client.util.gui.countryBox.CountryItemEditor;
 import mage.client.util.sets.ConstructedFormats;
 import mage.remote.Connection;
+import mage.utils.StreamUtils;
 import org.apache.log4j.Logger;
 
 /**
@@ -565,6 +567,7 @@ public class ConnectDialog extends MageDialog {
 
     private void findPublicServerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
         BufferedReader in = null;
+        Writer output = null;
         try {
             String serverUrl = PreferencesDialog.getCachedValue(KEY_CONNECTION_URL_SERVER_LIST, "http://xmage.de/files/server-list.txt");
             if (serverUrl.contains("xmage.info/files/")) {
@@ -618,7 +621,7 @@ public class ConnectDialog extends MageDialog {
             }
             List<String> servers = new ArrayList<>();
             if (in != null) {
-                Writer output = null;
+
                 if (!URLNotFound) {
                     // write serverlist to be able to read if URL is not available
                     File file = new File("serverlist.txt");
@@ -637,10 +640,6 @@ public class ConnectDialog extends MageDialog {
 
                     }
                 }
-                if (output != null) {
-                    output.close();
-                }
-                in.close();
             }
             if (servers.isEmpty()) {
                 JOptionPane.showMessageDialog(null, "Couldn't find any server.");
@@ -668,15 +667,12 @@ public class ConnectDialog extends MageDialog {
         } catch (Exception ex) {
             logger.error(ex, ex);
         } finally {
-            if (in != null) {
-                try {
-                    in.close();
-                } catch (Exception e) {
-                }
-            }
+            StreamUtils.closeQuietly(in);
+            StreamUtils.closeQuietly(output);
         }
     }//GEN-LAST:event_jButton1ActionPerformed
 
+
     private void jProxySettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jProxySettingsButtonActionPerformed
         PreferencesDialog.main(new String[]{PreferencesDialog.OPEN_CONNECTION_TAB});
     }//GEN-LAST:event_jProxySettingsButtonActionPerformed
diff --git a/Mage.Client/src/main/java/mage/client/util/gui/ArrowBuilder.java b/Mage.Client/src/main/java/mage/client/util/gui/ArrowBuilder.java
index 1c19bd5eca..3520af3b4c 100644
--- a/Mage.Client/src/main/java/mage/client/util/gui/ArrowBuilder.java
+++ b/Mage.Client/src/main/java/mage/client/util/gui/ArrowBuilder.java
@@ -45,16 +45,12 @@ public class ArrowBuilder {
      * Get the panel where all arrows are being drawn.
      * @return
      */
-    public JPanel getArrowsManagerPanel() {
+    public synchronized JPanel getArrowsManagerPanel() {
         if (arrowsManagerPanel == null) {
-            synchronized (ArrowBuilder.class) {
-                if (arrowsManagerPanel == null) {
-                    arrowsManagerPanel = new JPanel();
-                    arrowsManagerPanel.setVisible(true);
-                    arrowsManagerPanel.setOpaque(false);
-                    arrowsManagerPanel.setLayout(null);
-                }
-            }
+            arrowsManagerPanel = new JPanel();
+            arrowsManagerPanel.setVisible(true);
+            arrowsManagerPanel.setOpaque(false);
+            arrowsManagerPanel.setLayout(null);
         }
         return arrowsManagerPanel;
     }
diff --git a/Mage.Client/src/main/java/mage/client/util/object/SaveObjectUtil.java b/Mage.Client/src/main/java/mage/client/util/object/SaveObjectUtil.java
index 397da1cff0..c319f27b5b 100644
--- a/Mage.Client/src/main/java/mage/client/util/object/SaveObjectUtil.java
+++ b/Mage.Client/src/main/java/mage/client/util/object/SaveObjectUtil.java
@@ -1,5 +1,7 @@
 package mage.client.util.object;
 
+import mage.utils.StreamUtils;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -61,10 +63,9 @@ public final class SaveObjectUtil {
                 oos.writeObject(object);
                 oos.close();
 
-            } catch (FileNotFoundException e) {
-                return;
-            } catch (IOException io) {
-                return;
+            } catch (Exception e) {
+            } finally {
+                StreamUtils.closeQuietly(oos);
             }
         }
     }
diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java
index f5c1af5d52..9350ff3a5b 100644
--- a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java
+++ b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java
@@ -41,6 +41,7 @@ import mage.client.constants.Constants.ResourceSymbolSize;
 import mage.client.util.GUISizeHelper;
 import mage.client.util.ImageHelper;
 import mage.client.util.gui.BufferedImageBuilder;
+import mage.utils.StreamUtils;
 import org.apache.batik.dom.svg.SVGDOMImplementation;
 import org.apache.batik.transcoder.TranscoderException;
 import org.apache.batik.transcoder.TranscoderInput;
@@ -249,10 +250,15 @@ public final class ManaSymbols {
                 + "color-rendering: optimizeQuality;"
                 + "image-rendering: optimizeQuality;"
                 + "}";
+
         File cssFile = File.createTempFile("batik-default-override-", ".css");
-        FileWriter w = new FileWriter(cssFile);
-        w.write(css);
-        w.close();
+        FileWriter w = null;
+        try {
+            w = new FileWriter(cssFile);
+            w.write(css);
+        } finally {
+            StreamUtils.closeQuietly(w);
+        }
 
         TranscodingHints transcoderHints = new TranscodingHints();
 
@@ -284,7 +290,6 @@ public final class ManaSymbols {
 
         try {
             TranscoderInput input = new TranscoderInput(new FileInputStream(svgFile));
-
             ImageTranscoder t = new ImageTranscoder() {
 
                 @Override
diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/UI.java b/Mage.Client/src/main/java/org/mage/card/arcane/UI.java
index 0b2ed25f00..d07264d8a8 100644
--- a/Mage.Client/src/main/java/org/mage/card/arcane/UI.java
+++ b/Mage.Client/src/main/java/org/mage/card/arcane/UI.java
@@ -1,5 +1,7 @@
 package org.mage.card.arcane;
 
+import mage.utils.StreamUtils;
+
 import java.awt.Component;
 import java.awt.Container;
 import java.awt.Dimension;
@@ -72,8 +74,8 @@ public final class UI {
     }
 
     public static ImageIcon getImageIcon (String path) {
+        InputStream stream = null;
         try {
-            InputStream stream;
             stream = UI.class.getResourceAsStream(path);
             if (stream == null && new File(path).exists()) {
                 stream = new FileInputStream(path);
@@ -86,6 +88,8 @@ public final class UI {
             return new ImageIcon(data);
         } catch (IOException ex) {
             throw new RuntimeException("Error reading image: " + path);
+        } finally {
+            StreamUtils.closeQuietly(stream);
         }
     }
 
diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/Util.java b/Mage.Client/src/main/java/org/mage/card/arcane/Util.java
index 57f704056f..2645c314db 100644
--- a/Mage.Client/src/main/java/org/mage/card/arcane/Util.java
+++ b/Mage.Client/src/main/java/org/mage/card/arcane/Util.java
@@ -37,9 +37,13 @@ public final class Util {
     }
 
     public static void broadcast(byte[] data, int port) throws IOException {
-        DatagramSocket socket = new DatagramSocket();
-        broadcast(socket, data, port, NetworkInterface.getNetworkInterfaces());
-        socket.close();
+        DatagramSocket socket = null;
+        try {
+            socket = new DatagramSocket();
+            broadcast(socket, data, port, NetworkInterface.getNetworkInterfaces());
+        } finally {
+            socket.close();
+        }
     }
 
     private static void broadcast(DatagramSocket socket, byte[] data, int port, Enumeration<NetworkInterface> ifaces)
diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java
index caef7e5d21..e90d1cf9c5 100644
--- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java
+++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java
@@ -9,6 +9,7 @@ import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import mage.util.StreamUtils;
 import org.mage.plugins.card.dl.DownloadJob;
 
 import static org.mage.card.arcane.ManaSymbols.getSymbolFileNameAsSVG;
@@ -106,20 +107,21 @@ public class ScryfallSymbolsSource implements Iterable<DownloadJob> {
             if (destFile.exists() && (destFile.length() > 0)){
                 continue;
             }
-
+            FileOutputStream stream = null;
             try {
                 // base64 transform
                 String data64 = foundedData.get(searchCode);
                 Base64.Decoder dec = Base64.getDecoder();
                 byte[] fileData = dec.decode(data64);
 
-                FileOutputStream stream = new FileOutputStream(destFile);
+                stream = new FileOutputStream(destFile);
                 stream.write(fileData);
-                stream.close();
 
                 LOGGER.info("New svg symbol downloaded: " + needCode);
             } catch  (Exception e) {
                 LOGGER.error("Can't decode svg icon and save to file: " + destFile.getPath() + ", reason: " + e.getMessage());
+            } finally {
+                StreamUtils.closeQuietly(stream);
             }
         }
     }
diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java
index 9e333430b7..5755522b1b 100644
--- a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java
+++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java
@@ -24,6 +24,7 @@ import mage.client.MageFrame;
 import mage.client.dialog.PreferencesDialog;
 import mage.client.util.sets.ConstructedFormats;
 import mage.remote.Connection;
+import mage.util.StreamUtils;
 import net.java.truevfs.access.TFile;
 import net.java.truevfs.access.TFileOutputStream;
 import net.java.truevfs.access.TVFS;
@@ -745,34 +746,6 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
                     }
                 }
 
-                /*
-                if(!destFile.getParentFile().exists()){
-                    destFile.getParentFile().mkdirs();
-                }
-                 */
-
- /*
-                // WTF start?! TODO: wtf
-                File existingFile = new File(imagePath.replaceFirst("\\w{3}.zip", ""));
-                if (existingFile.exists()) {
-                    try {
-                        new TFile(existingFile).cp_rp(outputFile);
-                    } catch (IOException e) {
-                        logger.error("Error while copying file " + card.getName(), e);
-                    }
-                    synchronized (sync) {
-                        update(cardIndex + 1, count);
-                    }
-                    existingFile.delete();
-                    File parent = existingFile.getParentFile();
-                    if (parent != null && parent.isDirectory() && parent.list().length == 0) {
-                        parent.delete();
-                    }
-                    return;
-                }
-                // WTF end?!
-                 */
-                // START to download
                 cardImageSource.doPause(url.getPath());
                 URLConnection httpConn = url.openConnection(p);
                 httpConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2");
@@ -782,18 +755,18 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
                 if (responseCode == 200) {
                     // download OK
                     // save data to temp
-                    BufferedOutputStream out;
-                    try (BufferedInputStream in = new BufferedInputStream(httpConn.getInputStream())) {
-                        out = new BufferedOutputStream(new TFileOutputStream(fileTempImage));
+                    OutputStream out = null;
+                    OutputStream tfileout = null;
+                    InputStream in = null;
+                    try {
+                        in = new BufferedInputStream(httpConn.getInputStream());
+                        tfileout = new TFileOutputStream(fileTempImage);
+                        out = new BufferedOutputStream(tfileout);
                         byte[] buf = new byte[1024];
                         int len;
                         while ((len = in.read(buf)) != -1) {
                             // user cancelled
                             if (cancel) {
-                                in.close();
-                                out.flush();
-                                out.close();
-
                                 // stop download, save current state and exit
                                 TFile archive = destFile.getTopLevelArchive();
                                 ///* not need to unmout/close - it's auto action
@@ -804,8 +777,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
                                     } catch (Exception e) {
                                         logger.error("Can't close archive file: " + e.getMessage(), e);
                                     }
-
-                                }//*/
+                                }
                                 try {
                                     TFile.rm(fileTempImage);
                                 } catch (Exception e) {
@@ -816,9 +788,12 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
                             out.write(buf, 0, len);
                         }
                     }
-                    // TODO: remove to finnaly section?
-                    out.flush();
-                    out.close();
+                    finally {
+                        StreamUtils.closeQuietly(in);
+                        StreamUtils.closeQuietly(out);
+                        StreamUtils.closeQuietly(tfileout);
+                    }
+
 
                     // TODO: add two faces card correction? (WTF)
                     // SAVE final data
@@ -847,81 +822,6 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
                     }
                 }
 
-                /*
-                // Logger.getLogger(this.getClass()).info(url.toString());
-                boolean useTempFile = false;
-                int responseCode = 0;
-                URLConnection httpConn = null;
-
-                if (temporaryFile != null && temporaryFile.length() > 100) {
-                    useTempFile = true;
-                } else {
-                    cardImageSource.doPause(url.getPath());
-                    httpConn = url.openConnection(p);
-                    httpConn.connect();
-                    responseCode = ((HttpURLConnection) httpConn).getResponseCode();
-                }
-
-                if (responseCode == 200 || useTempFile) {
-                    if (!useTempFile) {
-                        BufferedOutputStream out;
-                        try (BufferedInputStream in = new BufferedInputStream(httpConn.getInputStream())) {
-                            //try (BufferedInputStream in = new BufferedInputStream(url.openConnection(p).getInputStream())) {
-                            out = new BufferedOutputStream(new TFileOutputStream(temporaryFile));
-                            byte[] buf = new byte[1024];
-                            int len;
-                            while ((len = in.read(buf)) != -1) {
-                                // user cancelled
-                                if (cancel) {
-                                    in.close();
-                                    out.flush();
-                                    out.close();
-                                    temporaryFile.delete();
-                                    return;
-                                }
-                                out.write(buf, 0, len);
-                            }
-
-                        }
-                        out.flush();
-                        out.close();
-                    }
-
-                    // TODO: WTF?! start
-                    if (card != null && card.isTwoFacedCard()) {
-                        BufferedImage image = ImageIO.read(temporaryFile);
-                        if (image.getHeight() == 470) {
-                            BufferedImage renderedImage = new BufferedImage(265, 370, BufferedImage.TYPE_INT_RGB);
-                            renderedImage.getGraphics();
-                            Graphics2D graphics2D = renderedImage.createGraphics();
-                            if (card.isTwoFacedCard() && card.isSecondSide()) {
-                                graphics2D.drawImage(image, 0, 0, 265, 370, 313, 62, 578, 432, null);
-                            } else {
-                                graphics2D.drawImage(image, 0, 0, 265, 370, 41, 62, 306, 432, null);
-                            }
-                            graphics2D.dispose();
-                            writeImageToFile(renderedImage, outputFile);
-                        } else {
-                            outputFile.getParentFile().mkdirs();
-                            new TFile(temporaryFile).cp_rp(outputFile);
-                        }
-                        //temporaryFile.delete();
-                    } else {
-                        outputFile.getParentFile().mkdirs();
-                        new TFile(temporaryFile).cp_rp(outputFile);
-                    }
-                    // WTF?! end
-                } else {
-                    if (card != null && !useSpecifiedPaths) {
-                        logger.warn("Image download for " + card.getName()
-                                + (!card.getDownloadName().equals(card.getName()) ? " downloadname: " + card.getDownloadName() : "")
-                                + '(' + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString());
-                    }
-                    if (logger.isDebugEnabled()) { // Shows the returned html from the request to the web server
-                        logger.debug("Returned HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream()));
-                    }
-                }
-                 */
             } catch (AccessDeniedException e) {
                 logger.error("Can't access to files: " + card.getName() + "(" + card.getSet() + "). Try rebooting your system to remove the file lock.");
             } catch (Exception e) {
@@ -933,26 +833,6 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
                 update(cardIndex + 1, count);
             }
         }
-
-//        private void writeImageToFile(BufferedImage image, TFile file) throws IOException {
-//            Iterator iter = ImageIO.getImageWritersByFormatName("jpg");
-//
-//            ImageWriter writer = (ImageWriter) iter.next();
-//            ImageWriteParam iwp = writer.getDefaultWriteParam();
-//            iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
-//            iwp.setCompressionQuality(0.96f);
-//
-//            File tempFile = new File(getImagesDir() + File.separator + image.hashCode() + file.getName());
-//            FileImageOutputStream output = new FileImageOutputStream(tempFile);
-//            writer.setOutput(output);
-//            IIOImage image2 = new IIOImage(image, null, null);
-//            writer.write(null, image2, iwp);
-//            writer.dispose();
-//            output.close();
-//
-//            new TFile(tempFile).cp_rp(file);
-//            tempFile.delete();
-//        }
     }
 
     private void update(int card, int count) {
diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/properties/SettingsManager.java b/Mage.Client/src/main/java/org/mage/plugins/card/properties/SettingsManager.java
index 075a3d9008..c7a6b87d62 100644
--- a/Mage.Client/src/main/java/org/mage/plugins/card/properties/SettingsManager.java
+++ b/Mage.Client/src/main/java/org/mage/plugins/card/properties/SettingsManager.java
@@ -12,13 +12,9 @@ public class SettingsManager {
 
     private static SettingsManager settingsManager = null;
 
-    public static SettingsManager getIntance() {
+    public static synchronized SettingsManager getIntance() {
         if (settingsManager == null) {
-            synchronized (SettingsManager.class) {
-                if (settingsManager == null) {
-                    settingsManager = new SettingsManager();
-                }
-            }
+            settingsManager = new SettingsManager();
         }
         return settingsManager;
     }
diff --git a/Mage.Client/src/main/java/org/mage/plugins/theme/ThemePluginImpl.java b/Mage.Client/src/main/java/org/mage/plugins/theme/ThemePluginImpl.java
index 43c788e983..6f9b00879f 100644
--- a/Mage.Client/src/main/java/org/mage/plugins/theme/ThemePluginImpl.java
+++ b/Mage.Client/src/main/java/org/mage/plugins/theme/ThemePluginImpl.java
@@ -150,47 +150,43 @@ public class ThemePluginImpl implements ThemePlugin {
         return bgPanel;
     }
 
-    private ImagePanel createImagePanelInstance() {
+    private synchronized ImagePanel createImagePanelInstance() {
         if (background == null) {
-            synchronized (ThemePluginImpl.class) {
-                if (background == null) {
-                    String filename = "/background.png";
-                    try {
-                        if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_BACKGROUND_IMAGE_DEFAULT, "true").equals("true")) {
-                            InputStream is = this.getClass().getResourceAsStream(filename);
-                            if (is == null) {
-                                throw new FileNotFoundException("Couldn't find " + filename + " in resources.");
-                            }
-                            background = ImageIO.read(is);
-                        } else {
-                            String path = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_BACKGROUND_IMAGE, "");
-                            if (path != null && !path.isEmpty()) {
-                                try {
-                                    File f = new File(path);
-                                    if (f != null) {
-                                        background = ImageIO.read(f);
-                                    }
-                                } catch (Exception e) {
-                                    background = null;
-                                }
-                            }
-                        }
-                        if (background == null) {
-                            InputStream is = this.getClass().getResourceAsStream(filename);
-                            if (is == null) {
-                                throw new FileNotFoundException("Couldn't find " + filename + " in resources.");
-                            }
-                            background = ImageIO.read(is);
-                        }
-                        if (background == null) {
+                String filename = "/background.png";
+                try {
+                    if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_BACKGROUND_IMAGE_DEFAULT, "true").equals("true")) {
+                        InputStream is = this.getClass().getResourceAsStream(filename);
+                        if (is == null) {
                             throw new FileNotFoundException("Couldn't find " + filename + " in resources.");
                         }
-                    } catch (Exception e) {
-                        log.error(e.getMessage(), e);
-                        return null;
+                        background = ImageIO.read(is);
+                    } else {
+                        String path = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_BACKGROUND_IMAGE, "");
+                        if (path != null && !path.isEmpty()) {
+                            try {
+                                File f = new File(path);
+                                if (f != null) {
+                                    background = ImageIO.read(f);
+                                }
+                            } catch (Exception e) {
+                                background = null;
+                            }
+                        }
                     }
+                    if (background == null) {
+                        InputStream is = this.getClass().getResourceAsStream(filename);
+                        if (is == null) {
+                            throw new FileNotFoundException("Couldn't find " + filename + " in resources.");
+                        }
+                        background = ImageIO.read(is);
+                    }
+                    if (background == null) {
+                        throw new FileNotFoundException("Couldn't find " + filename + " in resources.");
+                    }
+                } catch (Exception e) {
+                    log.error(e.getMessage(), e);
+                    return null;
                 }
-            }
         }
         return new ImagePanel(background, ImagePanelStyle.SCALED);
     }
diff --git a/Mage.Common/src/main/java/mage/utils/StreamUtils.java b/Mage.Common/src/main/java/mage/utils/StreamUtils.java
new file mode 100644
index 0000000000..1b228b454a
--- /dev/null
+++ b/Mage.Common/src/main/java/mage/utils/StreamUtils.java
@@ -0,0 +1,30 @@
+package mage.utils;
+
+import java.io.Closeable;
+
+public final class StreamUtils {
+
+    /***
+     * Quietly closes the closable, ignoring nulls and exceptions
+     * @param c - the closable to be closed
+     */
+    public static void closeQuietly(Closeable c) {
+        if (c != null) {
+            try {
+                c.close();
+            }
+            catch (Exception e) {
+            }
+        }
+    }
+
+    public static void closeQuietly(AutoCloseable ac) {
+        if (ac != null) {
+            try {
+                ac.close();
+            }
+            catch (Exception e) {
+            }
+        }
+    }
+}
diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java
index a7c5a914c9..d3785cfa65 100644
--- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java
+++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java
@@ -957,10 +957,11 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
     }
 
     protected final void getSuggestedActions() {
+        Scanner scanner = null;
         try {
             File file = new File(FILE_WITH_INSTRUCTIONS);
             if (file.exists()) {
-                Scanner scanner = new Scanner(file);
+                scanner = new Scanner(file);
                 while (scanner.hasNextLine()) {
                     String line = scanner.nextLine();
                     if (line.startsWith("cast:")
@@ -976,6 +977,10 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
         } catch (Exception e) {
             // swallow
             e.printStackTrace();
+        } finally {
+            if(scanner != null) {
+                scanner.close();
+            }
         }
     }
 
diff --git a/Mage.Server/src/main/java/mage/server/ChatSession.java b/Mage.Server/src/main/java/mage/server/ChatSession.java
index da9b897f7e..e73c0410f1 100644
--- a/Mage.Server/src/main/java/mage/server/ChatSession.java
+++ b/Mage.Server/src/main/java/mage/server/ChatSession.java
@@ -90,8 +90,8 @@ public class ChatSession {
                 String userName = clients.get(userId);
                 if (reason != DisconnectReason.LostConnection) { // for lost connection the user will be reconnected or session expire so no removeUserFromAllTablesAndChat of chat yet
                     final Lock w = lock.writeLock();
-                    w.lock();
                     try {
+                        w.lock();
                         clients.remove(userId);
                     } finally {
                         w.unlock();
diff --git a/Mage.Server/src/main/java/mage/server/ExtensionPackageLoader.java b/Mage.Server/src/main/java/mage/server/ExtensionPackageLoader.java
index 6c5b3f80ad..8894ae6720 100644
--- a/Mage.Server/src/main/java/mage/server/ExtensionPackageLoader.java
+++ b/Mage.Server/src/main/java/mage/server/ExtensionPackageLoader.java
@@ -29,6 +29,7 @@
 package mage.server;
 
 import mage.server.util.PluginClassLoader;
+import mage.util.StreamUtils;
 
 import java.io.File;
 import java.io.IOException;
@@ -54,10 +55,12 @@ public final class ExtensionPackageLoader {
         String entryPoint = entryPointReader.nextLine().trim();
         entryPointReader.close();
 
-        PluginClassLoader classLoader = new PluginClassLoader();
-        for(File f : packagesDirectory.listFiles()) classLoader.addURL(f.toURI().toURL());
-
+        PluginClassLoader classLoader = null;
         try {
+            classLoader = new PluginClassLoader();
+            for(File f : packagesDirectory.listFiles()) {
+                classLoader.addURL(f.toURI().toURL());
+            }
             return (ExtensionPackage) Class.forName(entryPoint, false, classLoader).newInstance();
         } catch (InstantiationException | IllegalAccessException e) {
             throw new RuntimeException(e);
@@ -65,6 +68,8 @@ public final class ExtensionPackageLoader {
             throw new RuntimeException("Entry point class not found!", e);
         } catch (ClassCastException e) {
             throw new RuntimeException("Entry point not an instance of ExtensionPackage.", e);
+        } finally {
+            StreamUtils.closeQuietly(classLoader);
         }
     }
 }
diff --git a/Mage.Server/src/main/java/mage/server/UserManager.java b/Mage.Server/src/main/java/mage/server/UserManager.java
index cd30111745..767f7bb59a 100644
--- a/Mage.Server/src/main/java/mage/server/UserManager.java
+++ b/Mage.Server/src/main/java/mage/server/UserManager.java
@@ -231,8 +231,8 @@ public enum UserManager {
             }
             logger.debug("Users to remove " + toRemove.size());
             final Lock w = lock.readLock();
-            w.lock();
             try {
+                w.lock();
                 for (User user : toRemove) {
                     users.remove(user.getId());
                 }
diff --git a/Mage.Server/src/main/java/mage/server/game/GameController.java b/Mage.Server/src/main/java/mage/server/game/GameController.java
index 8082d6576d..8bce119961 100644
--- a/Mage.Server/src/main/java/mage/server/game/GameController.java
+++ b/Mage.Server/src/main/java/mage/server/game/GameController.java
@@ -64,6 +64,7 @@ import mage.server.util.ConfigSettings;
 import mage.server.util.Splitter;
 import mage.server.util.SystemUtil;
 import mage.server.util.ThreadExecutor;
+import mage.utils.StreamUtils;
 import mage.utils.timer.PriorityTimer;
 import mage.view.*;
 import mage.view.ChatMessage.MessageColor;
@@ -902,17 +903,23 @@ public class GameController implements GameCallback {
     }
 
     public boolean saveGame() {
+        OutputStream file = null;
+        ObjectOutput output = null;
+        OutputStream buffer = null;
         try {
-            OutputStream file = new FileOutputStream("saved/" + game.getId().toString() + ".game");
-            OutputStream buffer = new BufferedOutputStream(file);
-            try (ObjectOutput output = new ObjectOutputStream(new GZIPOutputStream(buffer))) {
-                output.writeObject(game);
-                output.writeObject(game.getGameStates());
-            }
+            file = new FileOutputStream("saved/" + game.getId().toString() + ".game");
+            buffer = new BufferedOutputStream(file);
+            output = new ObjectOutputStream(new GZIPOutputStream(buffer));
+            output.writeObject(game);
+            output.writeObject(game.getGameStates());
             logger.debug("Saved game:" + game.getId());
             return true;
         } catch (IOException ex) {
             logger.fatal("Cannot save game.", ex);
+        } finally {
+            StreamUtils.closeQuietly(file);
+            StreamUtils.closeQuietly(output);
+            StreamUtils.closeQuietly(buffer);
         }
         return false;
     }
diff --git a/Mage.Server/src/main/java/mage/server/game/GameReplay.java b/Mage.Server/src/main/java/mage/server/game/GameReplay.java
index 820bc9a6d3..01a4a1dd99 100644
--- a/Mage.Server/src/main/java/mage/server/game/GameReplay.java
+++ b/Mage.Server/src/main/java/mage/server/game/GameReplay.java
@@ -40,6 +40,7 @@ import mage.game.GameState;
 import mage.game.GameStates;
 import mage.server.Main;
 import mage.util.CopierObjectInputStream;
+import mage.utils.StreamUtils;
 import org.apache.log4j.Logger;
 
 
@@ -84,21 +85,31 @@ public class GameReplay {
     }
 
     private Game loadGame(UUID gameId) {
+        InputStream file = null;
+        InputStream buffer = null;
+        InputStream gzip = null;
+        ObjectInput input = null;
         try{
-            InputStream file = new FileInputStream("saved/" + gameId.toString() + ".game");
-            InputStream buffer = new BufferedInputStream(file);
-            try (ObjectInput input = new CopierObjectInputStream(Main.classLoader, new GZIPInputStream(buffer))) {
-                Game loadGame = (Game) input.readObject();
-                GameStates states = (GameStates) input.readObject();
-                loadGame.loadGameStates(states);
-                return loadGame;
-            }
+            file = new FileInputStream("saved/" + gameId.toString() + ".game");
+            buffer = new BufferedInputStream(file);
+            gzip = new GZIPInputStream(buffer);
+            input = new CopierObjectInputStream(Main.classLoader, gzip);
+            Game loadGame = (Game) input.readObject();
+            GameStates states = (GameStates) input.readObject();
+            loadGame.loadGameStates(states);
+            return loadGame;
+
         }
         catch(ClassNotFoundException ex) {
             logger.fatal("Cannot load game. Class not found.", ex);
         }
         catch(IOException ex) {
             logger.fatal("Cannot load game:" + gameId, ex);
+        } finally {
+            StreamUtils.closeQuietly(file);
+            StreamUtils.closeQuietly(buffer);
+            StreamUtils.closeQuietly(input);
+            StreamUtils.closeQuietly(gzip);
         }
         return null;
     }
diff --git a/Mage.Server/src/main/java/mage/server/util/ServerMessagesUtil.java b/Mage.Server/src/main/java/mage/server/util/ServerMessagesUtil.java
index d596f8a653..2cedad7aa8 100644
--- a/Mage.Server/src/main/java/mage/server/util/ServerMessagesUtil.java
+++ b/Mage.Server/src/main/java/mage/server/util/ServerMessagesUtil.java
@@ -27,6 +27,7 @@
  */
 package mage.server.util;
 
+import mage.utils.StreamUtils;
 import org.apache.log4j.Logger;
 
 import java.io.File;
@@ -49,7 +50,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
  * @author nantuko
  */
 public enum ServerMessagesUtil {
-instance;
+    instance;
     private static final Logger log = Logger.getLogger(ServerMessagesUtil.class);
     private static final String SERVER_MSG_TXT_FILE = "server.msg.txt";
     private ScheduledExecutorService updateExecutor;
@@ -147,13 +148,22 @@ instance;
             log.warn("Couldn't find server.msg");
             return null;
         }
-        Scanner scanner = new Scanner(is);
+
+        Scanner scanner = null;
         List<String> newMessages = new ArrayList<>();
-        while (scanner.hasNextLine()) {
-            String message = scanner.nextLine();
-            if (!message.trim().isEmpty()) {
-                newMessages.add(message.trim());
+        try {
+            scanner = new Scanner(is);
+            while (scanner.hasNextLine()) {
+                String message = scanner.nextLine();
+                if (!message.trim().isEmpty()) {
+                    newMessages.add(message.trim());
+                }
             }
+        } catch(Exception e) {
+            log.error(e,e);
+        } finally {
+            StreamUtils.closeQuietly(scanner);
+            StreamUtils.closeQuietly(is);
         }
         return newMessages;
     }
diff --git a/Mage.Server/src/main/java/mage/server/util/SystemUtil.java b/Mage.Server/src/main/java/mage/server/util/SystemUtil.java
index 3ec95e5b0e..5a3d71371a 100644
--- a/Mage.Server/src/main/java/mage/server/util/SystemUtil.java
+++ b/Mage.Server/src/main/java/mage/server/util/SystemUtil.java
@@ -14,6 +14,7 @@ import java.util.stream.Collectors;
 import mage.abilities.Ability;
 import mage.cards.Card;
 import mage.cards.Cards;
+import mage.cards.repository.CardCriteria;
 import mage.cards.repository.CardInfo;
 import mage.cards.repository.CardRepository;
 import mage.choices.Choice;
@@ -338,7 +339,10 @@ public final class SystemUtil {
                 String cardName = matchCommand.group(3);
                 Integer amount = Integer.parseInt(matchCommand.group(4));
 
-                List<CardInfo> cards = CardRepository.instance.findCards(cardName);
+                List<CardInfo> cards = CardRepository.instance.findCards(new CardCriteria().setCodes("UST").name(cardName));
+                if (cards.isEmpty()) {
+                    cards = CardRepository.instance.findCards(cardName);
+                }
                 if (cards.isEmpty()) {
                     if ("token".equalsIgnoreCase(zone)) {
                         // eg: token:Human:HippoToken:1
diff --git a/Mage.Sets/src/mage/cards/a/AvenShrine.java b/Mage.Sets/src/mage/cards/a/AvenShrine.java
index 64b88e4c70..c5c2a2b9c8 100644
--- a/Mage.Sets/src/mage/cards/a/AvenShrine.java
+++ b/Mage.Sets/src/mage/cards/a/AvenShrine.java
@@ -93,10 +93,7 @@ class AvenShrineTriggeredAbility extends TriggeredAbilityImpl {
     public boolean checkTrigger(GameEvent event, Game game) {
         Spell spell = game.getStack().getSpell(event.getTargetId());
         MageObject mageObject = game.getObject(sourceId);
-        if (spell != null
-                && !spell.isCopy()
-                && spell.getCard() != null
-                && !spell.getCard().isCopy()) {
+        if (spell != null) {
             game.getState().setValue("avenShrine" + mageObject, spell);
             return true;
         }
diff --git a/Mage.Sets/src/mage/cards/d/DwarvenShrine.java b/Mage.Sets/src/mage/cards/d/DwarvenShrine.java
index 7cb9e59e6c..53f37a2c75 100644
--- a/Mage.Sets/src/mage/cards/d/DwarvenShrine.java
+++ b/Mage.Sets/src/mage/cards/d/DwarvenShrine.java
@@ -93,10 +93,7 @@ class DwarvenShrineTriggeredAbility extends TriggeredAbilityImpl {
     public boolean checkTrigger(GameEvent event, Game game) {
         Spell spell = game.getStack().getSpell(event.getTargetId());
         MageObject mageObject = game.getObject(sourceId);
-        if (spell != null
-                && !spell.isCopy()
-                && spell.getCard() != null
-                && !spell.getCard().isCopy()) {
+        if (spell != null) {
             game.getState().setValue("dwarvenShrine" + mageObject, spell);
             return true;
         }
diff --git a/Mage.Sets/src/mage/cards/e/EmpyrialArchangel.java b/Mage.Sets/src/mage/cards/e/EmpyrialArchangel.java
index 133675ffb7..f622375b46 100644
--- a/Mage.Sets/src/mage/cards/e/EmpyrialArchangel.java
+++ b/Mage.Sets/src/mage/cards/e/EmpyrialArchangel.java
@@ -91,7 +91,6 @@ class EmpyrialArchangelEffect extends ReplacementEffectImpl {
         Permanent p = game.getPermanent(source.getSourceId());
         if (p != null) {
             p.damage(damageEvent.getAmount(), event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable());
-            return true;
         }
         return true;
     }
diff --git a/Mage.Sets/src/mage/cards/f/FalkenrathAristocrat.java b/Mage.Sets/src/mage/cards/f/FalkenrathAristocrat.java
index 71962fce82..5dfba5bc4a 100644
--- a/Mage.Sets/src/mage/cards/f/FalkenrathAristocrat.java
+++ b/Mage.Sets/src/mage/cards/f/FalkenrathAristocrat.java
@@ -105,7 +105,7 @@ class FalkenrathAristocratEffect extends OneShotEffect {
                 Permanent sourceCreature = game.getPermanent(source.getSourceId());
                 if (sacrificedCreature.hasSubtype(SubType.HUMAN, game) && sourceCreature != null) {
                     sourceCreature.addCounters(CounterType.P1P1.createInstance(), source, game);
-                    return true;
+                    break;
                 }
             }
         }
diff --git a/Mage.Sets/src/mage/cards/g/GilderBairn.java b/Mage.Sets/src/mage/cards/g/GilderBairn.java
index 1ce8089546..7f71ffd626 100644
--- a/Mage.Sets/src/mage/cards/g/GilderBairn.java
+++ b/Mage.Sets/src/mage/cards/g/GilderBairn.java
@@ -95,12 +95,11 @@ class GilderBairnEffect extends OneShotEffect {
     @Override
     public boolean apply(Game game, Ability source) {
         Permanent target = game.getPermanent(source.getFirstTarget());
-        if (target == null) {
-            return false;
-        }
-        for (Counter counter : target.getCounters(game).values()) {
-            Counter newCounter = new Counter(counter.getName(), counter.getCount());
-            target.addCounters(newCounter, source, game);
+        if (target != null) {
+            for (Counter counter : target.getCounters(game).values()) {
+                Counter newCounter = new Counter(counter.getName(), counter.getCount());
+                target.addCounters(newCounter, source, game);
+            }
         }
         return false;
     }
diff --git a/Mage.Sets/src/mage/cards/i/IceCave.java b/Mage.Sets/src/mage/cards/i/IceCave.java
index 188f79f42b..bcdf7f4d6f 100644
--- a/Mage.Sets/src/mage/cards/i/IceCave.java
+++ b/Mage.Sets/src/mage/cards/i/IceCave.java
@@ -102,7 +102,7 @@ class IceCaveEffect extends OneShotEffect {
                             if (cost.pay(source, game, source.getSourceId(), playerId, false, null)) {
                                 game.informPlayers(player.getLogName() + " pays" + cost.getText() + " to counter " + spell.getIdName() + '.');
                                 game.getStack().counter(spell.getId(), source.getSourceId(), game);
-                                return true;
+                                break;
                             }
                         }
                     }
diff --git a/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java b/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java
index 87b1171250..0ff4c0e503 100644
--- a/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java
+++ b/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java
@@ -99,7 +99,6 @@ class KjeldoranRoyalGuardEffect extends ReplacementEffectImpl {
         Permanent p = game.getPermanent(source.getSourceId());
         if (p != null) {
             p.damage(damageEvent.getAmount(), event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable());
-            return true;
         }
         return true;
     }
diff --git a/Mage.Sets/src/mage/cards/l/LegionsInitiative.java b/Mage.Sets/src/mage/cards/l/LegionsInitiative.java
index 3206227ed3..e20c35f1dc 100644
--- a/Mage.Sets/src/mage/cards/l/LegionsInitiative.java
+++ b/Mage.Sets/src/mage/cards/l/LegionsInitiative.java
@@ -129,7 +129,6 @@ class LegionsInitiativeExileEffect extends OneShotEffect {
             //create delayed triggered ability
             AtTheBeginOfCombatDelayedTriggeredAbility delayedAbility = new AtTheBeginOfCombatDelayedTriggeredAbility(new LegionsInitiativeReturnFromExileEffect());
             game.addDelayedTriggeredAbility(delayedAbility, source);
-            return true;
         }
         return true;
     }
diff --git a/Mage.Sets/src/mage/cards/n/NaturesWill.java b/Mage.Sets/src/mage/cards/n/NaturesWill.java
index 215999aa9b..c6a2e8bbc0 100644
--- a/Mage.Sets/src/mage/cards/n/NaturesWill.java
+++ b/Mage.Sets/src/mage/cards/n/NaturesWill.java
@@ -84,19 +84,16 @@ class NaturesWillEffect extends OneShotEffect {
     @Override
     public boolean apply(Game game, Ability source) {
         Set<UUID> damagedPlayers = (HashSet<UUID>) this.getValue("damagedPlayers");
-        if (damagedPlayers == null) {
-            return false;
-        }
-
-        List<Permanent> lands = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source.getSourceId(), game);
-        for (Permanent land : lands) {
-            if (damagedPlayers.contains(land.getControllerId())) {
-                land.tap(game);
-            } else if (land.getControllerId().equals(source.getControllerId())) {
-                land.untap(game);
+        if (damagedPlayers != null) {
+            List<Permanent> lands = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source.getSourceId(), game);
+            for (Permanent land : lands) {
+                if (damagedPlayers.contains(land.getControllerId())) {
+                   land.tap(game);
+                } else if (land.getControllerId().equals(source.getControllerId())) {
+                    land.untap(game);
+                }
             }
         }
-
         return false;
     }
 }
diff --git a/Mage.Sets/src/mage/cards/s/SongOfBlood.java b/Mage.Sets/src/mage/cards/s/SongOfBlood.java
new file mode 100644
index 0000000000..308e0fe90d
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/s/SongOfBlood.java
@@ -0,0 +1,158 @@
+/*
+ *  Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without modification, are
+ *  permitted provided that the following conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above copyright notice, this list of
+ *        conditions and the following disclaimer.
+ *
+ *     2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *        of conditions and the following disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ *  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  The views and conclusions contained in the software and documentation are those of the
+ *  authors and should not be interpreted as representing official policies, either expressed
+ *  or implied, of BetaSteward_at_googlemail.com.
+ */
+package mage.cards.s;
+
+import java.util.Set;
+import java.util.UUID;
+import mage.abilities.Ability;
+import mage.abilities.DelayedTriggeredAbility;
+import mage.abilities.effects.Effect;
+import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.continuous.BoostTargetEffect;
+import mage.cards.Card;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.cards.Cards;
+import mage.cards.CardsImpl;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.Outcome;
+import mage.constants.Zone;
+import mage.filter.common.FilterCreatureCard;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.game.events.GameEvent.EventType;
+import mage.game.permanent.Permanent;
+import mage.players.Player;
+import mage.target.targetpointer.FixedTarget;
+
+/**
+ *
+ * @author spjspj
+ */
+public class SongOfBlood extends CardImpl {
+
+    public SongOfBlood(UUID ownerId, CardSetInfo setInfo) {
+        super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}");
+
+        // Put the top four cards of your library into your graveyard.
+        // Whenever a creature attacks this turn, it gets +1/+0 until end of turn for each creature card put into your graveyard this way.
+        this.getSpellAbility().addEffect(new SongOfBloodEffect());
+    }
+
+    public SongOfBlood(final SongOfBlood card) {
+        super(card);
+    }
+
+    @Override
+    public SongOfBlood copy() {
+        return new SongOfBlood(this);
+    }
+}
+
+class SongOfBloodEffect extends OneShotEffect {
+
+    public SongOfBloodEffect() {
+        super(Outcome.LoseLife);
+        this.staticText = "Put the top four cards of your library into your graveyard.";
+
+    }
+
+    public SongOfBloodEffect(final SongOfBloodEffect effect) {
+        super(effect);
+    }
+
+    @Override
+    public SongOfBloodEffect copy() {
+        return new SongOfBloodEffect(this);
+    }
+
+    @Override
+    public boolean apply(Game game, Ability source) {
+        Player controller = game.getPlayer(source.getControllerId());
+        if (controller != null) {
+            Cards cardsToGraveyard = new CardsImpl();
+            cardsToGraveyard.addAll(controller.getLibrary().getTopCards(game, 4));
+            if (!cardsToGraveyard.isEmpty()) {
+                Set<Card> movedCards = controller.moveCardsToGraveyardWithInfo(cardsToGraveyard.getCards(game), source, game, Zone.LIBRARY);
+                Cards cardsMoved = new CardsImpl();
+                cardsMoved.addAll(movedCards);
+                int creatures = cardsMoved.count(new FilterCreatureCard(), game);
+                if (creatures > 0) {
+                    // Setup a delayed trigger to give +X/+0 to any creature attacking this turn..
+                    DelayedTriggeredAbility delayedAbility = new SongOfBloodTriggeredAbility(creatures);
+                    game.addDelayedTriggeredAbility(delayedAbility, source);
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+}
+
+class SongOfBloodTriggeredAbility extends DelayedTriggeredAbility {
+
+    int booster;
+
+    public SongOfBloodTriggeredAbility(int booster) {
+        super(new BoostTargetEffect(booster, 0, Duration.EndOfTurn), Duration.EndOfTurn, false);
+        this.booster = booster;
+    }
+
+    public SongOfBloodTriggeredAbility(SongOfBloodTriggeredAbility ability) {
+        super(ability);
+        this.booster = ability.booster;
+    }
+
+    @Override
+    public boolean checkEventType(GameEvent event, Game game) {
+        return event.getType() == EventType.ATTACKER_DECLARED;
+    }
+
+    @Override
+    public boolean checkTrigger(GameEvent event, Game game) {
+        Permanent permanent = game.getPermanent(event.getSourceId());
+        if (permanent != null) {
+            for (Effect effect : getEffects()) {
+                effect.setTargetPointer(new FixedTarget(permanent, game));
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public SongOfBloodTriggeredAbility copy() {
+        return new SongOfBloodTriggeredAbility(this);
+    }
+
+    @Override
+    public String getRule() {
+        return "Whenever a creature attacks this turn, it gets +1/+0 (+" + booster + "/0) until end of turn for each creature card put into your graveyard this way.";
+    }
+}
diff --git a/Mage.Sets/src/mage/sets/Visions.java b/Mage.Sets/src/mage/sets/Visions.java
index e1458607a9..c16b6af1a0 100644
--- a/Mage.Sets/src/mage/sets/Visions.java
+++ b/Mage.Sets/src/mage/sets/Visions.java
@@ -165,6 +165,7 @@ public class Visions extends ExpansionSet {
         cards.add(new SetCardInfo("Sisay's Ring", 154, Rarity.COMMON, mage.cards.s.SisaysRing.class));
         cards.add(new SetCardInfo("Snake Basket", 155, Rarity.RARE, mage.cards.s.SnakeBasket.class));
         cards.add(new SetCardInfo("Solfatara", 93, Rarity.COMMON, mage.cards.s.Solfatara.class));
+        cards.add(new SetCardInfo("Song of Blood", 94, Rarity.COMMON, mage.cards.s.SongOfBlood.class));
         cards.add(new SetCardInfo("Spider Climb", 70, Rarity.COMMON, mage.cards.s.SpiderClimb.class));
         cards.add(new SetCardInfo("Spitting Drake", 95, Rarity.UNCOMMON, mage.cards.s.SpittingDrake.class));
         cards.add(new SetCardInfo("Squandered Resources", 137, Rarity.RARE, mage.cards.s.SquanderedResources.class));
diff --git a/Mage.Updater/src/main/java/com/magefree/update/helpers/FileHelper.java b/Mage.Updater/src/main/java/com/magefree/update/helpers/FileHelper.java
index 63b9d873e1..d23c0bdf4c 100644
--- a/Mage.Updater/src/main/java/com/magefree/update/helpers/FileHelper.java
+++ b/Mage.Updater/src/main/java/com/magefree/update/helpers/FileHelper.java
@@ -4,7 +4,7 @@ import java.io.*;
 import java.net.HttpURLConnection;
 import java.util.ArrayList;
 import java.util.List;
-
+import java.io.Closeable;
 /**
  * Helper for file operations.
  *
@@ -84,15 +84,17 @@ public final class FileHelper {
      */
     public static void downloadFile(String filename, HttpURLConnection urlConnection) {
         System.out.println("Downloading " + filename);
+        InputStream in = null;
+        FileOutputStream out = null;
         try {
-            InputStream in = urlConnection.getInputStream();
+            in = urlConnection.getInputStream();
             File f = new File(filename);
             if (!f.exists() && f.getParentFile() != null) {
                 f.getParentFile().mkdirs();
                 System.out.println("Directories have been created: " + f.getParentFile().getPath());
             }
 
-            FileOutputStream out = new FileOutputStream(filename);
+            out = new FileOutputStream(filename);
             byte[] buf = new byte[4 * 1024];
             int bytesRead;
 
@@ -103,6 +105,19 @@ public final class FileHelper {
             System.out.println("File has been updated: " + filename);
         } catch (IOException e) {
             System.out.println("i/o exception - " + e.getMessage());
+        } finally {
+            closeQuietly(in);
+            closeQuietly(out);
+        }
+    }
+
+    public static void closeQuietly(Closeable s) {
+        if(s != null) {
+            try {
+                s.close();
+            } catch (Exception e) {
+                System.out.println("i/o exception - " + e.getMessage());
+            }
         }
     }
 }
diff --git a/Mage.Verify/src/main/java/mage/verify/MtgJson.java b/Mage.Verify/src/main/java/mage/verify/MtgJson.java
index b187667140..287aecef3d 100644
--- a/Mage.Verify/src/main/java/mage/verify/MtgJson.java
+++ b/Mage.Verify/src/main/java/mage/verify/MtgJson.java
@@ -2,6 +2,7 @@ package mage.verify;
 
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import mage.util.StreamUtils;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -94,9 +95,16 @@ public final class MtgJson {
             }
             stream = new FileInputStream(file);
         }
-        ZipInputStream zipInputStream = new ZipInputStream(stream);
-        zipInputStream.getNextEntry();
-        return new ObjectMapper().readValue(zipInputStream, ref);
+        ZipInputStream zipInputStream = null;
+        try {
+            zipInputStream = new ZipInputStream(stream);
+            zipInputStream.getNextEntry();
+            return new ObjectMapper().readValue(zipInputStream, ref);
+        } finally {
+            StreamUtils.closeQuietly(zipInputStream);
+            StreamUtils.closeQuietly(stream);
+        }
+
     }
 
     public static Map<String, JsonSet> sets() {
diff --git a/Mage/src/main/java/mage/util/Copier.java b/Mage/src/main/java/mage/util/Copier.java
index e6b7aa4b49..56c2385424 100644
--- a/Mage/src/main/java/mage/util/Copier.java
+++ b/Mage/src/main/java/mage/util/Copier.java
@@ -50,36 +50,44 @@ public class Copier<T> {
 
     public T copy(T obj) {
         T copy = null;
+
+        FastByteArrayOutputStream fbos = null;
+        ObjectOutputStream out = null;
+        ObjectInputStream in = null;
         try {
-            FastByteArrayOutputStream fbos = new FastByteArrayOutputStream();
-            ObjectOutputStream out= new ObjectOutputStream(fbos);
+            fbos = new FastByteArrayOutputStream();
+            out = new ObjectOutputStream(fbos);
 
             // Write the object out to a byte array
             out.writeObject(obj);
             out.flush();
-            out.close();
 
             // Retrieve an input stream from the byte array and read
             // a copy of the object back in.
-            ObjectInputStream in = new CopierObjectInputStream(loader, fbos.getInputStream());
+            in = new CopierObjectInputStream(loader, fbos.getInputStream());
             copy = (T) in.readObject();
         }
         catch(IOException | ClassNotFoundException e) {
             e.printStackTrace();
+        } finally {
+            StreamUtils.closeQuietly(fbos);
+            StreamUtils.closeQuietly(out);
+            StreamUtils.closeQuietly(in);
         }
         return copy;
 
     }
 
     public byte[] copyCompressed(T obj) {
+        FastByteArrayOutputStream fbos = null;
+        ObjectOutputStream out = null;
         try {
-            FastByteArrayOutputStream fbos = new FastByteArrayOutputStream();
-            ObjectOutputStream out= new ObjectOutputStream(new GZIPOutputStream(fbos));
+            fbos = new FastByteArrayOutputStream();
+            out = new ObjectOutputStream(new GZIPOutputStream(fbos));
 
             // Write the object out to a byte array
             out.writeObject(obj);
             out.flush();
-            out.close();
 
             byte[] copy = new byte[fbos.getSize()];
             System.arraycopy(fbos.getByteArray(), 0, copy, 0, fbos.getSize());
@@ -87,6 +95,9 @@ public class Copier<T> {
         }
         catch(IOException e) {
             e.printStackTrace();
+        } finally {
+            StreamUtils.closeQuietly(fbos);
+            StreamUtils.closeQuietly(out);
         }
         return null;
     }
diff --git a/Mage/src/main/java/mage/util/StreamUtils.java b/Mage/src/main/java/mage/util/StreamUtils.java
new file mode 100644
index 0000000000..2be62157c3
--- /dev/null
+++ b/Mage/src/main/java/mage/util/StreamUtils.java
@@ -0,0 +1,30 @@
+package mage.util;
+
+import java.io.Closeable;
+
+public final class StreamUtils {
+
+    /***
+     * Quietly closes the closable, ignoring nulls and exceptions
+     * @param c - the closable to be closed
+     */
+    public static void closeQuietly(Closeable c) {
+        if (c != null) {
+            try {
+                c.close();
+            }
+            catch (Exception e) {
+            }
+        }
+    }
+
+    public static void closeQuietly(AutoCloseable ac) {
+        if (ac != null) {
+            try {
+                ac.close();
+            }
+            catch (Exception e) {
+            }
+        }
+    }
+}