const b64 = require('base64-js');

function arrayToB64(array) {
  return b64
    .fromByteArray(array)
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=/g, '');
}

function b64ToArray(str) {
  str = (str + '==='.slice((str.length + 3) % 4))
    .replace(/-/g, '+')
    .replace(/_/g, '/');
  return b64.toByteArray(str);
}

function loadShim(polyfill) {
  return new Promise((resolve, reject) => {
    const shim = document.createElement('script');
    shim.src = polyfill;
    shim.addEventListener('load', () => resolve(true));
    shim.addEventListener('error', () => resolve(false));
    document.head.appendChild(shim);
  });
}

async function canHasSend(polyfill) {
  try {
    const key = await window.crypto.subtle.generateKey(
      {
        name: 'AES-GCM',
        length: 128
      },
      true,
      ['encrypt', 'decrypt']
    );

    await window.crypto.subtle.encrypt(
      {
        name: 'AES-GCM',
        iv: window.crypto.getRandomValues(new Uint8Array(12)),
        tagLength: 128
      },
      key,
      new ArrayBuffer(8)
    );
    return true;
  } catch (err) {
    return loadShim(polyfill);
  }
}

function isFile(id) {
  return /^[0-9a-fA-F]{10}$/.test(id);
}

function copyToClipboard(str) {
  const aux = document.createElement('input');
  aux.setAttribute('value', str);
  aux.contentEditable = true;
  aux.readOnly = true;
  document.body.appendChild(aux);
  if (navigator.userAgent.match(/iphone|ipad|ipod/i)) {
    const range = document.createRange();
    range.selectNodeContents(aux);
    const sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
    aux.setSelectionRange(0, str.length);
  } else {
    aux.select();
  }
  const result = document.execCommand('copy');
  document.body.removeChild(aux);
  return result;
}

const LOCALIZE_NUMBERS = !!(
  typeof Intl === 'object' &&
  Intl &&
  typeof Intl.NumberFormat === 'function' &&
  typeof navigator === 'object'
);

const UNITS = ['B', 'kB', 'MB', 'GB'];
function bytes(num) {
  if (num < 1) {
    return '0B';
  }
  const exponent = Math.min(Math.floor(Math.log10(num) / 3), UNITS.length - 1);
  const n = Number(num / Math.pow(1000, exponent));
  let nStr = n.toFixed(1);
  if (LOCALIZE_NUMBERS) {
    try {
      const locale = document.querySelector('html').lang;
      nStr = n.toLocaleString(locale, {
        minimumFractionDigits: 1,
        maximumFractionDigits: 1
      });
    } catch (e) {
      // fall through
    }
  }
  return `${nStr}${UNITS[exponent]}`;
}

function percent(ratio) {
  if (LOCALIZE_NUMBERS) {
    try {
      const locale = document.querySelector('html').lang;
      return ratio.toLocaleString(locale, { style: 'percent' });
    } catch (e) {
      // fall through
    }
  }
  return `${Math.floor(ratio * 100)}%`;
}

function number(n) {
  if (LOCALIZE_NUMBERS) {
    const locale = document.querySelector('html').lang;
    return n.toLocaleString(locale);
  }
  return n.toString();
}

function allowedCopy() {
  const support = !!document.queryCommandSupported;
  return support ? document.queryCommandSupported('copy') : false;
}

function delay(delay = 100) {
  return new Promise(resolve => setTimeout(resolve, delay));
}

function fadeOut(id) {
  const classes = document.getElementById(id).classList;
  classes.remove('fadeIn');
  classes.add('fadeOut');
  return delay(300);
}

function saveFile(file) {
  const dataView = new DataView(file.plaintext);
  const blob = new Blob([dataView], { type: file.type });
  const downloadUrl = URL.createObjectURL(blob);

  if (window.navigator.msSaveBlob) {
    return window.navigator.msSaveBlob(blob, file.name);
  }
  const a = document.createElement('a');
  a.href = downloadUrl;
  a.download = file.name;
  document.body.appendChild(a);
  a.click();
  URL.revokeObjectURL(downloadUrl);
}

function openLinksInNewTab(links, should = true) {
  links = links || Array.from(document.querySelectorAll('a:not([target])'));
  if (should) {
    links.forEach(l => {
      l.setAttribute('target', '_blank');
      l.setAttribute('rel', 'noopener noreferrer');
    });
  } else {
    links.forEach(l => {
      l.removeAttribute('target');
      l.removeAttribute('rel');
    });
  }
  return links;
}

module.exports = {
  fadeOut,
  delay,
  allowedCopy,
  bytes,
  percent,
  number,
  copyToClipboard,
  arrayToB64,
  b64ToArray,
  canHasSend,
  isFile,
  saveFile,
  openLinksInNewTab
};

@@ -3383,24 +3383,59 @@
 ile(file) %7B%0A
+  const reader = new FileReader();%0A
   const data
@@ -3471,16 +3471,16 @@
 ntext);%0A
-
   const 
@@ -3532,57 +3532,8 @@
  %7D);
-%0A  const downloadUrl = URL.createObjectURL(blob);
 %0A%0A  
@@ -3624,24 +3624,103 @@
 .name);%0A  %7D%0A
+  reader.addEventListener('loadend', function() %7B%0A    if (reader.result) %7B%0A    
   const a = 
@@ -3748,16 +3748,20 @@
 t('a');%0A
+    
   a.href
@@ -3767,21 +3767,27 @@
 f = 
-downloadUrl;%0A
+reader.result;%0A    
   a.
@@ -3808,16 +3808,20 @@
 e.name;%0A
+    
   docume
@@ -3844,16 +3844,20 @@
 ild(a);%0A
+    
   a.clic
@@ -3867,39 +3867,176 @@
 ;%0A  
-URL.revokeObjectURL(downloadUrl
+    return;%0A    %7D%0A    if (reader.error) %7B%0A      console.error(reader.error);%0A      window.location.href = '/error';%0A      //TODO%0A    %7D%0A  %7D);%0A  reader.readAsDataURL(blob
 );%0A%7D

change saveFile. attempting to fix for iOS