Index: /main/trunk/model-sites-dev/respooled/user-script/Download_YouTube_Videos_as_MP4.user.js
===================================================================
--- /main/trunk/model-sites-dev/respooled/user-script/Download_YouTube_Videos_as_MP4.user.js	(revision 29984)
+++ /main/trunk/model-sites-dev/respooled/user-script/Download_YouTube_Videos_as_MP4.user.js	(revision 29984)
@@ -0,0 +1,786 @@
+﻿// ==UserScript==
+// @name Download YouTube Videos as MP4
+// @description Adds a button that lets you download YouTube videos.
+// @homepageURL https://github.com/gantt/downloadyoutube
+// @author Gantt
+// @version 1.8.3
+// @date 2015-05-17
+// @namespace http://googlesystem.blogspot.com
+// @include http://www.youtube.com/*
+// @include https://www.youtube.com/*
+// @exclude http://www.youtube.com/embed/*
+// @exclude https://www.youtube.com/embed/*
+// @match http://www.youtube.com/*
+// @match https://www.youtube.com/*
+// @match http://s.ytimg.com/yts/jsbin/html5player*
+// @match https://s.ytimg.com/yts/jsbin/html5player*
+// @match http://manifest.googlevideo.com/*
+// @match https://manifest.googlevideo.com/*
+// @match http://*.googlevideo.com/videoplayback*
+// @match https://*.googlevideo.com/videoplayback*
+// @match http://*.youtube.com/videoplayback*
+// @match https://*.youtube.com/videoplayback*
+// @grant GM_xmlhttpRequest
+// @grant GM_getValue
+// @grant GM_setValue
+// @run-at document-end
+// @license MIT License
+// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAB3RJTUUH2wMOCgIoGUYEAQAAAAlwSFlzAAALEgAACxIB0t1+/AAAAARnQU1BAACxjwv8YQUAAAGSUExURfi/JO/v797e3sbGxq2traWlpZSUlJycnNbW1oyEhIRaWow5OZQhIZwYGKUQEKUICK0ICJQxMYxKSoxzc4x7e4RCQpQYGKUAAK0AALUAAL0AAK0QEIxra5QpKa0YGIxSUsYAAKUhIZR7e87Ozr0ICJRSUr29vYxjY6U5OaUpKa0hIb21tZwAALUICO/Ozu/GxqUxMZSEhLUYGO/W1r0YGKVCQpQQEL0pKffe3vfW1pxra5Q5OcZCQvfn585CQr2trZx7e8ZSUs5SUq05Oc5jY9ZjY84AAKWMjM5zc957e60pKdaMjOelpbWcnLWUlLVCQsYYGMYICNbOzpQICMYhIbV7e5xaWt6cnPfv79bGxt6lpe+9vc5KSs6lpb0xMc6EhM69vbUxMbUhIb1aWs61tcZaWuecnMYxMb1KSsZjY96UlNa1td7W1r17e9a9vZwQEN6trb1jY8YQENZra+fOzr1zc85aWufe3t6MjMY5OdZaWt61tdZ7e+/n5+e9vc6MjMZra+/e3ue1tdalpd7GxrUpKalL4aAAAAABdFJOUwBA5thmAAACxklEQVR42uXX/1/SQBgH8NuAoEQ2ijgbBivJLznBAiUUKiyJSgOVAk0tKZKw75mRRt/7v4MBY8ezjW39Vs8v8rqHz/u1jbvbidC/XL8KmcpOqVT6nSjXjooGw8WfFd+QWGfE4oLbtbr++PdMOy0BDYLjEj/0xevfWIyVAI7b/aIj/9WHsRrA8Yf9bqSexVgD4Lic9kWE/LgPwPGfNfJHDO4P8Iuq+S2M9QD8oUp+nxEAcFCtfgIA/14x/9ElAKDQbNQAwN9VAiYEABy0OgsAWAnB/AcBAtVWawkAfJ4CD0BQADZavYcQgI9h3CCQjpD5PcEgwG+SwLRhIL0vz78SjAPEU3hrHODfyX4I6rUJIP0G3oExoNwFXpoB+HwXmDEFpF9IwKA5YK+Tp9fMAdUOsC6YA553gKcmgdTfAhV1oMQqADndQDmJ0AZLAsFnCIV3VYDHJLAjDkZKciAaFz/lCeBJB1glgXBrNLndBWLJ9uZGAI+keTBLANL8SnWAzWRniAC2pG+6lQF0hfjTqCIBrEvjDwiggFSLuIUoLY0vEwAbUcsnc/LlnO02HGvEz+hXEeJ5Yj+4L2vNkxOJDSnlQzliIq2synr3embiUBjmw0FyU83KX04Ob+9aAK/Ppd5deZloz4HFlCHzt3sX0x2a6LcvQb4ab8r7i+DVdqvnCq/D5ZzqdhfAcr5B9wD0PNwPEu0ZnLwK9oPgNfCQJ2fhhhITJ3E8BjeUOXA+QNQlBh5xLjemVCgKjzgzNIJFjWF4yJoKhafgIWt6VHGmjgR0HvMuTipPdWQJ6AImbBRSE8aY/sC4er5xFx5vHyB4YRRpFWUf0AL4c+dHkHZRFo9TDeB9Aa3Llwjr8FlFwB+wO/rHm0VbPae9mPini/O5h/XGxatw2I6fGHAOuhiGZVxO98lTdgutP94yaIvVdqxZdpvFYTT9X9UfqQQlTXlm8wkAAAAASUVORK5CYII=
+// ==/UserScript==
+
+
+(function () {
+  var FORMAT_LABEL={'5':'FLV 240p','18':'MP4 360p','22':'MP4 720p','34':'FLV 360p','35':'FLV 480p','37':'MP4 1080p','38':'MP4 2160p','43':'WebM 360p','44':'WebM 480p','45':'WebM 720p','46':'WebM 1080p','135':'MP4 480p - no audio','137':'MP4 1080p - no audio','138':'MP4 2160p - no audio','139':'M4A 48kbps - audio','140':'M4A 128kbps - audio','141':'M4A 256kbps - audio','264':'MP4 1440p - no audio','266':'MP4 2160p - no audio','298':'MP4 720p60 - no audio','299':'MP4 1080p60 - no audio'};
+  var FORMAT_TYPE={'5':'flv','18':'mp4','22':'mp4','34':'flv','35':'flv','37':'mp4','38':'mp4','43':'webm','44':'webm','45':'webm','46':'webm','135':'mp4','137':'mp4','138':'mp4','139':'m4a','140':'m4a','141':'m4a','264':'mp4','266':'mp4','298':'mp4','299':'mp4'};
+  var FORMAT_ORDER=['5','18','34','43','35','135','44','22','298','45','37','299','46','264','38','266','139','140','141'];
+  var FORMAT_RULE={'flv':'max','mp4':'all','webm':'none','m4a':'max'};
+  // all=display all versions, max=only highest quality version, none=no version  
+  // the default settings show all MP4 videos, the highest quality FLV and no WebM
+  var SHOW_DASH_FORMATS=false;
+  var BUTTON_TEXT={'ar':'تنزيل','cs':'Stáhnout','de':'Herunterladen','en':'Download','es':'Descargar','fr':'Télécharger','hi':'डाउनलोड','hu':'Letöltés','id':'Unduh','it':'Scarica','ja':'ダウンロード','ko':'내려받기','pl':'Pobierz','pt':'Baixar','ro':'Descărcați','ru':'Скачать','tr':'İndir','zh':'下载','zh-TW':'下載'};
+  var BUTTON_TOOLTIP={'ar':'تنزيل هذا الفيديو','cs':'Stáhnout toto video','de':'Dieses Video herunterladen','en':'Download this video','es':'Descargar este vídeo','fr':'Télécharger cette vidéo','hi':'वीडियो डाउनलोड करें','hu':'Videó letöltése','id':'Unduh video ini','it':'Scarica questo video','ja':'このビデオをダウンロードする','ko':'이 비디오를 내려받기','pl':'Pobierz plik wideo','pt':'Baixar este vídeo','ro':'Descărcați acest videoclip','ru':'Скачать это видео','tr': 'Bu videoyu indir','zh':'下载此视频','zh-TW':'下載此影片'};
+  var DECODE_RULE=[];
+  var RANDOM=7489235179; // Math.floor(Math.random()*1234567890);
+  var CONTAINER_ID='download-youtube-video'+RANDOM;
+  var LISTITEM_ID='download-youtube-video-fmt'+RANDOM;
+  var BUTTON_ID='download-youtube-video-button'+RANDOM;
+  var DEBUG_ID='download-youtube-video-debug-info';
+  var STORAGE_URL='download-youtube-script-url';
+  var STORAGE_CODE='download-youtube-signature-code';
+  var STORAGE_DASH='download-youtube-dash-enabled';
+  var isDecodeRuleUpdated=false;  
+    
+  start();
+          
+function start() {
+  var pagecontainer=document.getElementById('page-container');
+  if (!pagecontainer) return;
+  if (/^https?:\/\/www\.youtube.com\/watch\?/.test(window.location.href)) run();       
+  var isAjax=/class[\w\s"'-=]+spf\-link/.test(pagecontainer.innerHTML);
+  var logocontainer=document.getElementById('logo-container');  
+  if (logocontainer && !isAjax) { // fix for blocked videos
+    isAjax=(' '+logocontainer.className+' ').indexOf(' spf-link ')>=0;
+  }
+  var content=document.getElementById('content');
+  if (isAjax && content) { // Ajax UI
+      var mo=window.MutationObserver||window.WebKitMutationObserver;
+      if(typeof mo!=='undefined') {
+        var observer=new mo(function(mutations) {
+          mutations.forEach(function(mutation) {
+              if(mutation.addedNodes!==null) {
+                for (var i=0; i<mutation.addedNodes.length; i++) {
+                    if (mutation.addedNodes[i].id=='watch7-container' ||
+                        mutation.addedNodes[i].id=='watch7-main-container') { // old value: movie_player
+                      run();
+                      break;
+                    }
+                }
+              }
+          });
+        });
+        observer.observe(content, {childList: true, subtree: true}); // old value: pagecontainer
+      } else { // MutationObserver fallback for old browsers
+        pagecontainer.addEventListener('DOMNodeInserted', onNodeInserted, false);
+      }
+  } 
+}
+
+function onNodeInserted(e) { 
+    if (e && e.target && (e.target.id=='watch7-container' || 
+        e.target.id=='watch7-main-container')) { // old value: movie_player
+      run();
+  }
+}
+  
+function run() {
+  if (document.getElementById(CONTAINER_ID)) return; // check download container
+  if (document.getElementById('p') && document.getElementById('vo')) return; // Feather not supported
+
+  var videoID, videoFormats, videoAdaptFormats, videoManifestURL, scriptURL=null;
+  var isSignatureUpdatingStarted=false;
+  var operaTable=new Array();
+  var language=document.documentElement.getAttribute('lang');
+  var textDirection='left';
+  if (document.body.getAttribute('dir')=='rtl') {
+    textDirection='right';
+  }
+  if (document.getElementById('watch7-action-buttons')) {  // old UI
+    fixTranslations(language, textDirection);
+  }
+        
+  // obtain video ID, formats map   
+  
+  var args=null;
+  var usw=(typeof this.unsafeWindow !== 'undefined')?this.unsafeWindow:window; // Firefox, Opera<15
+  if (usw.ytplayer && usw.ytplayer.config && usw.ytplayer.config.args) {
+    args=usw.ytplayer.config.args;
+  }
+  if (args) {
+    videoID=args['video_id'];
+    videoFormats=args['url_encoded_fmt_stream_map'];
+    videoAdaptFormats=args['adaptive_fmts'];
+    videoManifestURL=args['dashmpd'];
+    debug('DYVAM - Info: Standard mode. videoID '+(videoID?videoID:'none')+'; ');
+  }
+  if (usw.ytplayer && usw.ytplayer.config && usw.ytplayer.config.assets) {
+    scriptURL=usw.ytplayer.config.assets.js;
+  }  
+  
+  if (videoID==null) { // unsafeWindow workaround (Chrome, Opera 15+)
+    var buffer=document.getElementById(DEBUG_ID+'2');
+    if (buffer) {
+      while (buffer.firstChild) {
+        buffer.removeChild(buffer.firstChild);
+      }
+    } else {
+      buffer=createHiddenElem('pre', DEBUG_ID+'2');
+    }    
+    injectScript ('if(ytplayer&&ytplayer.config&&ytplayer.config.args){document.getElementById("'+DEBUG_ID+'2").appendChild(document.createTextNode(\'"video_id":"\'+ytplayer.config.args.video_id+\'", "js":"\'+ytplayer.config.assets.js+\'", "dashmpd":"\'+ytplayer.config.args.dashmpd+\'", "url_encoded_fmt_stream_map":"\'+ytplayer.config.args.url_encoded_fmt_stream_map+\'", "adaptive_fmts":"\'+ytplayer.config.args.adaptive_fmts+\'"\'));}');
+    var code=buffer.innerHTML;
+    if (code) {
+      videoID=findMatch(code, /\"video_id\":\s*\"([^\"]+)\"/);
+      videoFormats=findMatch(code, /\"url_encoded_fmt_stream_map\":\s*\"([^\"]+)\"/);
+      videoFormats=videoFormats.replace(/&amp;/g,'\\u0026');
+      videoAdaptFormats=findMatch(code, /\"adaptive_fmts\":\s*\"([^\"]+)\"/);
+      videoAdaptFormats=videoAdaptFormats.replace(/&amp;/g,'\\u0026');
+      videoManifestURL=findMatch(code, /\"dashmpd\":\s*\"([^\"]+)\"/);
+      scriptURL=findMatch(code, /\"js\":\s*\"([^\"]+)\"/);
+    }
+    debug('DYVAM - Info: Injection mode. videoID '+(videoID?videoID:'none')+'; ');
+  }
+     
+  if (videoID==null) { // if all else fails
+    var bodyContent=document.body.innerHTML;  
+    if (bodyContent!=null) {
+      videoID=findMatch(bodyContent, /\"video_id\":\s*\"([^\"]+)\"/);
+      videoFormats=findMatch(bodyContent, /\"url_encoded_fmt_stream_map\":\s*\"([^\"]+)\"/);
+      videoAdaptFormats=findMatch(bodyContent, /\"adaptive_fmts\":\s*\"([^\"]+)\"/);
+      videoManifestURL=findMatch(bodyContent, /\"dashmpd\":\s*\"([^\"]+)\"/);
+      if (scriptURL==null) {
+        scriptURL=findMatch(bodyContent, /\"js\":\s*\"([^\"]+)\"/);
+        if (scriptURL) {
+          scriptURL=scriptURL.replace(/\\/g,'');
+        }
+      }      
+    }
+    debug('DYVAM - Info: Brute mode. videoID '+(videoID?videoID:'none')+'; ');
+  }
+  
+  debug('DYVAM - Info: url '+window.location.href+'; useragent '+window.navigator.userAgent);  
+  
+  if (videoID==null || videoFormats==null || videoID.length==0 || videoFormats.length==0) {
+   debug('DYVAM - Error: No config information found. YouTube must have changed the code.');
+   return;
+  }
+  
+  // Opera 12 extension message handler
+  if (typeof window.opera !== 'undefined' && window.opera && typeof opera.extension !== 'undefined') {
+    opera.extension.onmessage = function(event) {
+      var index=findMatch(event.data.action, /xhr\-([0-9]+)\-response/);
+      if (index && operaTable[parseInt(index,10)]) {
+        index=parseInt(index,10);
+        var trigger=(operaTable[index])['onload'];
+        if (typeof trigger === 'function' && event.data.readyState == 4) {
+          if (trigger) {
+              trigger(event.data);         
+          }
+        }
+      }
+    }
+  }
+    
+  if (!isDecodeRuleUpdated) {
+    DECODE_RULE=getDecodeRules(DECODE_RULE);
+    isDecodeRuleUpdated=true;
+  }
+  if (scriptURL) {
+    if (scriptURL.indexOf('//')==0) {
+      var protocol=(document.location.protocol=='http:')?'http:':'https:';
+      scriptURL=protocol+scriptURL;
+    }
+    fetchSignatureScript(scriptURL);
+  }
+  
+   // video title
+  var videoTitle=document.title || 'video';
+  videoTitle=videoTitle.replace(/\s*\-\s*YouTube$/i,'').replace(/[#"\?:\*]/g,'').replace(/[&\|\\\/]/g,'_').replace(/'/g,'\'').replace(/^\s+|\s+$/g,'').replace(/\.+$/g,'');  
+                        
+  // parse the formats map
+  var sep1='%2C', sep2='%26', sep3='%3D';
+  if (videoFormats.indexOf(',')>-1) { 
+    sep1=','; 
+    sep2=(videoFormats.indexOf('&')>-1)?'&':'\\u0026'; 
+    sep3='=';
+  }
+  var videoURL=new Array();
+  var videoSignature=new Array();
+  if (videoAdaptFormats) {
+    videoFormats=videoFormats+sep1+videoAdaptFormats;
+  }
+  var videoFormatsGroup=videoFormats.split(sep1);
+  for (var i=0;i<videoFormatsGroup.length;i++) {
+    var videoFormatsElem=videoFormatsGroup[i].split(sep2);
+    var videoFormatsPair=new Array();
+    for (var j=0;j<videoFormatsElem.length;j++) {
+      var pair=videoFormatsElem[j].split(sep3);
+      if (pair.length==2) {
+        videoFormatsPair[pair[0]]=pair[1];
+      }
+    }
+    if (videoFormatsPair['url']==null) continue;
+    var url=unescape(unescape(videoFormatsPair['url'])).replace(/\\\//g,'/').replace(/\\u0026/g,'&');
+    if (videoFormatsPair['itag']==null) continue;
+    var itag=videoFormatsPair['itag'];
+    var sig=videoFormatsPair['sig']||videoFormatsPair['signature'];
+    if (sig) {
+      url=url+'&signature='+sig;
+      videoSignature[itag]=null;
+    } else if (videoFormatsPair['s']) {
+      url=url+'&signature='+decryptSignature(videoFormatsPair['s']);
+      videoSignature[itag]=videoFormatsPair['s'];
+    }
+    if (url.toLowerCase().indexOf('ratebypass')==-1) { // speed up download for dash
+      url=url+'&ratebypass=yes';
+    }
+    if (url.toLowerCase().indexOf('http')==0) { // validate URL
+      videoURL[itag]=url+'&title='+videoTitle;
+    }
+  }
+    
+  var showFormat=new Array();
+  for (var category in FORMAT_RULE) {
+    var rule=FORMAT_RULE[category];
+    for (var index in FORMAT_TYPE){
+      if (FORMAT_TYPE[index]==category) {
+        showFormat[index]=(rule=='all');
+      }
+    }
+    if (rule=='max') {
+      for (var i=FORMAT_ORDER.length-1;i>=0;i--) {
+        var format=FORMAT_ORDER[i];
+        if (FORMAT_TYPE[format]==category && videoURL[format]!=undefined) {
+          showFormat[format]=true;
+          break;
+        }
+      }
+    }
+  }
+  
+  var dashPref=getPref(STORAGE_DASH);
+  if (dashPref=='1') {
+    SHOW_DASH_FORMATS=true;
+  } else if (dashPref!='0') {
+    setPref(STORAGE_DASH,'0');
+  }
+  
+  var downloadCodeList=[];
+  for (var i=0;i<FORMAT_ORDER.length;i++) {
+    var format=FORMAT_ORDER[i];
+    if (format=='37' && videoURL[format]==undefined) { // hack for dash 1080p
+      if (videoURL['137']) {
+       format='137';
+      }
+      showFormat[format]=showFormat['37'];
+    } else if (format=='38' && videoURL[format]==undefined) { // hack for dash 4K
+      if (videoURL['138'] && !videoURL['266']) {
+       format='138';
+      }
+      showFormat[format]=showFormat['38'];
+    }    
+    if (!SHOW_DASH_FORMATS && format.length>2) continue;
+    if (videoURL[format]!=undefined && FORMAT_LABEL[format]!=undefined && showFormat[format]) {
+      downloadCodeList.push({url:videoURL[format],sig:videoSignature[format],format:format,label:FORMAT_LABEL[format]});
+      debug('DYVAM - Info: itag'+format+' url:'+videoURL[format]);
+    }
+  }  
+  
+  if (downloadCodeList.length==0) {
+    debug('DYVAM - Error: No download URL found. Probably YouTube uses encrypted streams.');
+    return; // no format
+  } 
+    
+  // find parent container
+  var newWatchPage=false;
+  var parentElement=document.getElementById('watch7-action-buttons');
+  if (parentElement==null) {
+    parentElement=document.getElementById('watch8-secondary-actions');
+    if (parentElement==null) {
+      debug('DYVAM Error - No container for adding the download button. YouTube must have changed the code.');
+      return;
+    } else {
+      newWatchPage=true;
+    }
+  }
+  
+  // get button labels
+  var buttonText=(BUTTON_TEXT[language])?BUTTON_TEXT[language]:BUTTON_TEXT['en'];
+  var buttonLabel=(BUTTON_TOOLTIP[language])?BUTTON_TOOLTIP[language]:BUTTON_TOOLTIP['en'];
+    
+  // generate download code for regular interface
+  var mainSpan=document.createElement('span');
+
+  if (newWatchPage) {
+    var spanIcon=document.createElement('span');
+    spanIcon.setAttribute('class', 'yt-uix-button-icon-wrapper');
+    var imageIcon=document.createElement('img');
+    imageIcon.setAttribute('src', '//s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif');
+    imageIcon.setAttribute('class', 'yt-uix-button-icon');
+    imageIcon.setAttribute('style', 'width:20px;height:20px;background-size:20px 20px;background-repeat:no-repeat;background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABG0lEQVRYR+2W0Q3CMAxE2wkYAdiEEWADmIxuACMwCmzABpCTEmRSO7YTQX+ChECV43t2nF7GYeHPuLD+0AKwC/DnWMAp/N5qimkBuAfBdRTF/+2/AV6ZYFUxVYuicAfoHegd6B3oHfhZB+ByF+JyV8FkrAB74pqH3DU5L3iGoBURhdVODIQF4EjEkWLmmhYALOQgNIBcHHke4buhxXAAaFnaAhqbQ5QAOHHkwhZ8balkx1ICCiEBWNZ+CivdB7REHIC2ZjZK2oWklDDdB1NSdCd/Js2PqQMpSIKYVcM8kE6QCwDBNRCqOBJrW0CL8kCYxL0A1k6YxWsANAiXeC2ABOEWbwHAWrwxpzgkmA/JtIqnxTOElmPnjlkc4A3FykAhA42AxwAAAABJRU5ErkJggg==);');
+    spanIcon.appendChild(imageIcon);
+    mainSpan.appendChild(spanIcon);
+  }
+
+  var spanButton=document.createElement('span');
+  spanButton.setAttribute('class', 'yt-uix-button-content');
+  spanButton.appendChild(document.createTextNode(buttonText+' '));
+  mainSpan.appendChild(spanButton);
+  
+  if (!newWatchPage) { // old UI
+    var imgButton=document.createElement('img');
+    imgButton.setAttribute('class', 'yt-uix-button-arrow');
+    imgButton.setAttribute('src', '//s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif');
+    mainSpan.appendChild(imgButton);
+  }
+
+  var listItems=document.createElement('ol');
+  listItems.setAttribute('style', 'display:none;');
+  listItems.setAttribute('class', 'yt-uix-button-menu');
+  for (var i=0;i<downloadCodeList.length;i++) {
+    var listItem=document.createElement('li');
+    var listLink=document.createElement('a');
+    listLink.setAttribute('style', 'text-decoration:none;');
+    listLink.setAttribute('href', downloadCodeList[i].url);
+    listLink.setAttribute('download', videoTitle+'.'+FORMAT_TYPE[downloadCodeList[i].format]);
+    var listButton=document.createElement('span');
+    listButton.setAttribute('class', 'yt-uix-button-menu-item');
+    listButton.setAttribute('loop', i+'');
+    listButton.setAttribute('id', LISTITEM_ID+downloadCodeList[i].format);
+    listButton.appendChild(document.createTextNode(downloadCodeList[i].label));
+    listLink.appendChild(listButton);
+    listItem.appendChild(listLink);
+    listItems.appendChild(listItem);
+  }
+  mainSpan.appendChild(listItems);
+  var buttonElement=document.createElement('button');
+  buttonElement.setAttribute('id', BUTTON_ID);
+  if (newWatchPage) {
+    buttonElement.setAttribute('class', 'yt-uix-button  yt-uix-button-size-default yt-uix-button-opacity yt-uix-tooltip');
+  } else { // old UI
+    buttonElement.setAttribute('class', 'yt-uix-button yt-uix-tooltip yt-uix-button-empty yt-uix-button-text');
+    buttonElement.setAttribute('style', 'margin-top:4px; margin-left:'+((textDirection=='left')?5:10)+'px;');
+  }
+  buttonElement.setAttribute('data-tooltip-text', buttonLabel);  
+  buttonElement.setAttribute('type', 'button');
+  buttonElement.setAttribute('role', 'button');
+  buttonElement.addEventListener('click', function(){return false;}, false);
+  buttonElement.appendChild(mainSpan);
+  var containerSpan=document.createElement('span');
+  containerSpan.setAttribute('id', CONTAINER_ID);
+  containerSpan.appendChild(document.createTextNode(' '));
+  containerSpan.appendChild(buttonElement);
+                                            
+  // add the button
+  if (!newWatchPage) { // watch7
+    parentElement.appendChild(containerSpan);
+  } else { // watch8
+    parentElement.insertBefore(containerSpan, parentElement.firstChild);
+  }
+    
+  // REPLACEWITH if (!isSignatureUpdatingStarted) {
+    for (var i=0;i<downloadCodeList.length;i++) { 
+      addFileSize(downloadCodeList[i].url, downloadCodeList[i].format);
+    }
+  // } 
+  
+  if (typeof GM_download !== 'undefined') {
+    for (var i=0;i<downloadCodeList.length;i++) {
+      var downloadFMT=document.getElementById(LISTITEM_ID+downloadCodeList[i].format);
+      var url=(downloadCodeList[i].url).toLowerCase();
+      if (url.indexOf('clen=')>0 && url.indexOf('dur=')>0 && url.indexOf('gir=')>0
+          && url.indexOf('lmt=')>0) {
+        downloadFMT.addEventListener('click', downloadVideoNatively, false);
+      }
+    }
+  }
+  
+  addFromManifest('140', '141'); // replace fmt140 with fmt141 if found in manifest
+  
+  function downloadVideoNatively(e) {
+    var elem=e.currentTarget;
+    e.returnValue=false;    
+    if (e.preventDefault) {
+      e.preventDefault();
+    }
+    var loop=elem.getAttribute('loop');
+    if (loop) {
+      GM_download(downloadCodeList[loop].url, videoTitle+'.'+FORMAT_TYPE[downloadCodeList[loop].format]);
+    }
+    return false;
+  }
+  
+  function addFromManifest(oldFormat, newFormat) { // find newFormat URL in manifest
+    if (videoManifestURL && videoURL[newFormat]==undefined && SHOW_DASH_FORMATS && FORMAT_RULE['m4a']=='max') {
+      var matchSig=findMatch(videoManifestURL, /\/s\/([a-zA-Z0-9\.]+)\//i);
+      if (matchSig) {
+        var decryptedSig=decryptSignature(matchSig);
+        if (decryptedSig) {
+          videoManifestURL=videoManifestURL.replace('/s/'+matchSig+'/','/signature/'+decryptedSig+'/');
+        }
+      }
+      if (videoManifestURL.indexOf('//')==0) {
+        var protocol=(document.location.protocol=='http:')?'http:':'https:';
+        videoManifestURL=protocol+videoManifestURL;
+      }
+      debug('DYVAM - Info: manifestURL '+videoManifestURL);
+      crossXmlHttpRequest({
+          method:'GET',
+          url:videoManifestURL, // check if URL exists
+          onload:function(response) {
+            if (response.readyState === 4 && response.status === 200 && response.responseText) {
+              var regexp = new RegExp('<BaseURL.+>(http[^<]+itag='+newFormat+'[^<]+)<\\/BaseURL>','i');
+              var matchURL=findMatch(response.responseText, regexp);
+              debug('DYVAM - Info: matchURL '+matchURL);
+              if (!matchURL) return;
+              matchURL=matchURL.replace(/&amp\;/g,'&');
+              for (var i=0;i<downloadCodeList.length;i++) {
+                if (downloadCodeList[i].format==oldFormat) {
+                  downloadCodeList[i].format==newFormat;
+                  var downloadFMT=document.getElementById(LISTITEM_ID+oldFormat);
+                  downloadFMT.setAttribute('id', LISTITEM_ID+newFormat);
+                  downloadFMT.parentNode.setAttribute('href', matchURL);
+                  downloadCodeList[i].url=matchURL;
+                  downloadFMT.firstChild.nodeValue=FORMAT_LABEL[newFormat];
+                  addFileSize(matchURL, newFormat);
+                }
+              }
+            }
+          } 
+        });
+    }  
+  }
+  
+  function injectStyle(code) {
+    var style=document.createElement('style');
+    style.type='text/css';
+    style.appendChild(document.createTextNode(code));
+    document.getElementsByTagName('head')[0].appendChild(style);
+  }
+  
+  function injectScript(code) {
+    var script=document.createElement('script');
+    script.type='application/javascript';
+    script.textContent=code;
+    document.body.appendChild(script);
+    document.body.removeChild(script);
+  }    
+  
+  function debug(str) {
+    var debugElem=document.getElementById(DEBUG_ID);
+    if (!debugElem) {
+      debugElem=createHiddenElem('div', DEBUG_ID);
+    }
+    debugElem.appendChild(document.createTextNode(str+' '));
+  }
+  
+  function createHiddenElem(tag, id) {
+    var elem=document.createElement(tag);
+    elem.setAttribute('id', id);
+    elem.setAttribute('style', 'display:none;');
+    document.body.appendChild(elem);
+    return elem;
+  }
+  
+  function fixTranslations(language, textDirection) {  
+    if (/^af|bg|bn|ca|cs|de|el|es|et|eu|fa|fi|fil|fr|gl|hi|hr|hu|id|it|iw|kn|lv|lt|ml|mr|ms|nl|pl|ro|ru|sl|sk|sr|sw|ta|te|th|uk|ur|vi|zu$/.test(language)) { // fix international UI
+      var likeButton=document.getElementById('watch-like');
+      if (likeButton) {
+        var spanElements=likeButton.getElementsByClassName('yt-uix-button-content');
+        if (spanElements) {
+          spanElements[0].style.display='none'; // hide like text
+        }
+      }
+      var marginPixels=10;
+      if (/^bg|ca|cs|el|eu|hr|it|ml|ms|pl|sl|sw|te$/.test(language)) {
+        marginPixels=1;
+      }
+      injectStyle('#watch7-secondary-actions .yt-uix-button{margin-'+textDirection+':'+marginPixels+'px!important}');
+    }
+  }
+  
+  function findMatch(text, regexp) {
+    var matches=text.match(regexp);
+    return (matches)?matches[1]:null;
+  }
+  
+  function isString(s) {
+    return (typeof s==='string' || s instanceof String);
+  }
+    
+  function isInteger(n) {
+    return (typeof n==='number' && n%1==0);
+  }
+  
+  function getPref(name) { // cross-browser GM_getValue
+    var a='', b='';
+    try {a=typeof GM_getValue.toString; b=GM_getValue.toString()} catch(e){}    
+    if (typeof GM_getValue === 'function' && 
+    (a === 'undefined' || b.indexOf('not supported') === -1)) {
+      return GM_getValue(name, null); // Greasemonkey, Tampermonkey, Firefox extension
+    } else {
+        var ls=null;
+        try {ls=window.localStorage||null} catch(e){}
+        if (ls) {
+          return ls.getItem(name); // Chrome script, Opera extensions
+        }
+    }
+    return;
+  }
+  
+  function setPref(name, value) { //  cross-browser GM_setValue
+    var a='', b='';
+    try {a=typeof GM_setValue.toString; b=GM_setValue.toString()} catch(e){}    
+    if (typeof GM_setValue === 'function' && 
+    (a === 'undefined' || b.indexOf('not supported') === -1)) {
+      GM_setValue(name, value); // Greasemonkey, Tampermonkey, Firefox extension
+    } else {
+        var ls=null;
+        try {ls=window.localStorage||null} catch(e){}
+        if (ls) {
+          return ls.setItem(name, value); // Chrome script, Opera extensions
+        }
+    }
+  }
+  
+  function crossXmlHttpRequest(details) { // cross-browser GM_xmlhttpRequest
+    if (typeof GM_xmlhttpRequest === 'function') { // Greasemonkey, Tampermonkey, Firefox extension, Chrome script
+      GM_xmlhttpRequest(details);
+    } else if (typeof window.opera !== 'undefined' && window.opera && typeof opera.extension !== 'undefined' && 
+               typeof opera.extension.postMessage !== 'undefined') { // Opera 12 extension
+        var index=operaTable.length;
+        opera.extension.postMessage({'action':'xhr-'+index, 'url':details.url, 'method':details.method});
+        operaTable[index]=details;
+    } else if (typeof window.opera === 'undefined' && typeof XMLHttpRequest === 'function') { // Opera 15+ extension
+        var xhr=new XMLHttpRequest();
+        xhr.onreadystatechange = function() {
+          if (xhr.readyState == 4) {
+            if (details['onload']) {
+              details['onload'](xhr);
+            }
+          }
+        }
+        xhr.open(details.method, details.url, true);
+        xhr.send();
+    }
+  }
+   
+  function addFileSize(url, format) {
+  
+    function updateVideoLabel(size, format) {
+      var elem=document.getElementById(LISTITEM_ID+format);
+      if (elem) {
+        size=parseInt(size,10);
+        if (size>=1073741824) {
+          size=parseFloat((size/1073741824).toFixed(1))+' GB';
+        } else if (size>=1048576) {
+          size=parseFloat((size/1048576).toFixed(1))+' MB';
+        } else {
+          size=parseFloat((size/1024).toFixed(1))+' KB';
+        }
+        if (elem.childNodes.length>1) {
+            elem.lastChild.nodeValue=' ('+size+')';
+        } else if (elem.childNodes.length==1) {
+            elem.appendChild(document.createTextNode(' ('+size+')'));
+        }
+      }
+    }
+        
+    var matchSize=findMatch(url, /[&\?]clen=([0-9]+)&/i);
+    if (matchSize) {
+      updateVideoLabel(matchSize, format);
+    } else {
+      try {
+        crossXmlHttpRequest({
+          method:'HEAD',
+          url:url,
+          onload:function(response) {
+            if (response.readyState == 4 && response.status == 200) { // add size
+              var size=0;
+              if (typeof response.getResponseHeader === 'function') {
+                size=response.getResponseHeader('Content-length');
+              } else if (response.responseHeaders) {
+                  var regexp = new RegExp('^Content\-length: (.*)$','im');
+                  var match = regexp.exec(response.responseHeaders);
+                  if (match) {
+                    size=match[1];
+                  }
+              }
+              if (size) {
+                updateVideoLabel(size, format);
+              }
+            }
+          }
+        });
+      } catch(e) { }
+    }
+  }
+  
+  function findSignatureCode(sourceCode) {
+    debug('DYVAM - Info: signature start '+getPref(STORAGE_CODE));
+    var signatureFunctionName = 
+    findMatch(sourceCode, 
+    /\.set\s*\("signature"\s*,\s*([a-zA-Z0-9_$][\w$]*)\(/)
+    || findMatch(sourceCode, 
+    /\.sig\s*\|\|\s*([a-zA-Z0-9_$][\w$]*)\(/)
+    || findMatch(sourceCode, 
+    /\.signature\s*=\s*([a-zA-Z_$][\w$]*)\([a-zA-Z_$][\w$]*\)/); //old
+    if (signatureFunctionName == null) return setPref(STORAGE_CODE, 'error');
+    signatureFunctionName=signatureFunctionName.replace('$','\\$');    
+    var regCode = new RegExp('function \\s*' + signatureFunctionName +
+    '\\s*\\([\\w$]*\\)\\s*{[\\w$]*=[\\w$]*\\.split\\(""\\);(.+);return [\\w$]*\\.join');
+    var functionCode = findMatch(sourceCode, regCode);
+    debug('DYVAM - Info: signaturefunction ' + signatureFunctionName + ' -- ' + functionCode);            
+    if (functionCode == null) return setPref(STORAGE_CODE, 'error');
+    
+    var reverseFunctionName = findMatch(sourceCode, 
+    /([\w$]*)\s*:\s*function\s*\(\s*[\w$]*\s*\)\s*{\s*(?:return\s*)?[\w$]*\.reverse\s*\(\s*\)\s*}/);
+    debug('DYVAM - Info: reversefunction ' + reverseFunctionName);
+    if (reverseFunctionName) reverseFunctionName=reverseFunctionName.replace('$','\\$');        
+    var sliceFunctionName = findMatch(sourceCode, 
+    /([\w$]*)\s*:\s*function\s*\(\s*[\w$]*\s*,\s*[\w$]*\s*\)\s*{\s*(?:return\s*)?[\w$]*\.(?:slice|splice)\(.+\)\s*}/);
+    debug('DYVAM - Info: slicefunction ' + sliceFunctionName);
+    if (sliceFunctionName) sliceFunctionName=sliceFunctionName.replace('$','\\$');    
+    
+    var regSlice = new RegExp('\\.(?:'+'slice'+(sliceFunctionName?'|'+sliceFunctionName:'')+
+    ')\\s*\\(\\s*(?:[a-zA-Z_$][\\w$]*\\s*,)?\\s*([0-9]+)\\s*\\)'); // .slice(5) sau .Hf(a,5)
+    var regReverse = new RegExp('\\.(?:'+'reverse'+(reverseFunctionName?'|'+reverseFunctionName:'')+
+    ')\\s*\\([^\\)]*\\)');  // .reverse() sau .Gf(a,45)
+    var regSwap = new RegExp('[\\w$]+\\s*\\(\\s*[\\w$]+\\s*,\\s*([0-9]+)\\s*\\)');
+    var regInline = new RegExp('[\\w$]+\\[0\\]\\s*=\\s*[\\w$]+\\[([0-9]+)\\s*%\\s*[\\w$]+\\.length\\]');
+    var functionCodePieces=functionCode.split(';');
+    var decodeArray=[];
+    for (var i=0; i<functionCodePieces.length; i++) {
+      functionCodePieces[i]=functionCodePieces[i].trim();
+      var codeLine=functionCodePieces[i];
+      if (codeLine.length>0) {
+        var arrSlice=codeLine.match(regSlice);
+        var arrReverse=codeLine.match(regReverse);
+        debug(i+': '+codeLine+' --'+(arrSlice?' slice length '+arrSlice.length:'') +' '+(arrReverse?'reverse':''));
+        if (arrSlice && arrSlice.length >= 2) { // slice
+        var slice=parseInt(arrSlice[1], 10);
+        if (isInteger(slice)){ 
+          decodeArray.push(-slice);
+        } else return setPref(STORAGE_CODE, 'error');
+      } else if (arrReverse && arrReverse.length >= 1) { // reverse
+        decodeArray.push(0);
+      } else if (codeLine.indexOf('[0]') >= 0) { // inline swap
+          if (i+2<functionCodePieces.length &&
+          functionCodePieces[i+1].indexOf('.length') >= 0 &&
+          functionCodePieces[i+1].indexOf('[0]') >= 0) {
+            var inline=findMatch(functionCodePieces[i+1], regInline);
+            inline=parseInt(inline, 10);
+            decodeArray.push(inline);
+            i+=2;
+          } else return setPref(STORAGE_CODE, 'error');
+      } else if (codeLine.indexOf(',') >= 0) { // swap
+        var swap=findMatch(codeLine, regSwap);      
+        swap=parseInt(swap, 10);
+        if (isInteger(swap) && swap>0){
+          decodeArray.push(swap);
+        } else return setPref(STORAGE_CODE, 'error');
+      } else return setPref(STORAGE_CODE, 'error');
+      }
+    }
+    
+    if (decodeArray) {
+      setPref(STORAGE_URL, scriptURL);
+      setPref(STORAGE_CODE, decodeArray.toString());
+      DECODE_RULE=decodeArray;
+      debug('DYVAM - Info: signature '+decodeArray.toString()+' '+scriptURL);
+      // update download links and add file sizes
+      for (var i=0;i<downloadCodeList.length;i++) {        
+        var elem=document.getElementById(LISTITEM_ID+downloadCodeList[i].format);
+        var url=downloadCodeList[i].url;
+        var sig=downloadCodeList[i].sig;
+        if (elem && url && sig) {
+          url=url.replace(/\&signature=[\w\.]+/, '&signature='+decryptSignature(sig));
+          elem.parentNode.setAttribute('href', url);
+          addFileSize(url, downloadCodeList[i].format);
+        }
+      }
+    }
+  }
+  
+  function isValidSignatureCode(arr) { // valid values: '5,-3,0,2,5', 'error'
+    if (!arr) return false;
+    if (arr=='error') return true;
+    arr=arr.split(',');
+    for (var i=0;i<arr.length;i++) {
+      if (!isInteger(parseInt(arr[i],10))) return false;
+    }
+    return true;
+  }
+  
+  function fetchSignatureScript(scriptURL) {
+    var storageURL=getPref(STORAGE_URL);
+    var storageCode=getPref(STORAGE_CODE);
+    if (!(/,0,|^0,|,0$|\-/.test(storageCode))) storageCode=null; // hack for only positive items
+    if (storageCode && isValidSignatureCode(storageCode) && storageURL &&
+        scriptURL.replace(/^https?/i,'')==storageURL.replace(/^https?/i,'')) return;
+    try {
+      debug('DYVAM fetch '+scriptURL);
+      isSignatureUpdatingStarted=true;    
+      crossXmlHttpRequest({
+        method:'GET',
+        url:scriptURL,
+        onload:function(response) {
+          debug('DYVAM fetch status '+response.status);
+          if (response.readyState === 4 && response.status === 200 && response.responseText) {
+            findSignatureCode(response.responseText);
+          }
+        } 
+      });
+    } catch(e) { }
+  }
+  
+  function getDecodeRules(rules) {
+    var storageCode=getPref(STORAGE_CODE);    
+    if (storageCode && storageCode!='error' && isValidSignatureCode(storageCode)) {
+      var arr=storageCode.split(',');
+      for (var i=0; i<arr.length; i++) {
+        arr[i]=parseInt(arr[i], 10);
+      }
+      rules=arr;
+      debug('DYVAM - Info: signature '+arr.toString()+' '+scriptURL);
+    }
+    return rules;
+  }
+  
+  function decryptSignature(sig) {
+    function swap(a,b){var c=a[0];a[0]=a[b%a.length];a[b]=c;return a};
+    function decode(sig, arr) { // encoded decryption
+      if (!isString(sig)) return null;
+      var sigA=sig.split('');
+      for (var i=0;i<arr.length;i++) {
+        var act=arr[i];
+        if (!isInteger(act)) return null;
+        sigA=(act>0)?swap(sigA, act):((act==0)?sigA.reverse():sigA.slice(-act));
+      }
+      var result=sigA.join('');
+      return result;
+    }
+    
+    if (sig==null) return '';    
+    var arr=DECODE_RULE;
+    if (arr) {
+      var sig2=decode(sig, arr);
+      if (sig2) return sig2;
+    } else {
+      setPref(STORAGE_URL, '');
+      setPref(STORAGE_CODE, '');
+    }
+    return sig; 
+  }  
+      
+  }
+ 
+})();
Index: /main/trunk/model-sites-dev/respooled/user-script/Popup_Videos_Respooled.user.js
===================================================================
--- /main/trunk/model-sites-dev/respooled/user-script/Popup_Videos_Respooled.user.js	(revision 29984)
+++ /main/trunk/model-sites-dev/respooled/user-script/Popup_Videos_Respooled.user.js	(revision 29984)
@@ -0,0 +1,850 @@
+// ==UserScript==
+// @name        Popup Videos Respooled
+// @version     1.0
+// @description Transfers user selected YouTube (and similar video sites) to the Popup Videos site for embelishment
+// @homepageURL http://www.greenstone.org/popup-videos-respooled
+// @namespace   http://www.greenstone.org
+// @include about:addons
+// @include http://www.youtube.com/*
+// @include https://www.youtube.com/*
+// @exclude http://www.youtube.com/embed/*
+// @exclude https://www.youtube.com/embed/*
+// @match http://www.youtube.com/*
+// @match https://www.youtube.com/*
+// @match http://s.ytimg.com/yts/jsbin/html5player*
+// @match https://s.ytimg.com/yts/jsbin/html5player*
+// @match http://manifest.googlevideo.com/*
+// @match https://manifest.googlevideo.com/*
+// @match http://*.googlevideo.com/videoplayback*
+// @match https://*.googlevideo.com/videoplayback*
+// @match http://*.youtube.com/videoplayback*
+// @match https://*.youtube.com/videoplayback*
+// @grant GM_xmlhttpRequest
+// @grant GM_getValue
+// @grant GM_setValue
+// @run-at document-end
+// @license GPL v3
+// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wYQAiYzj2+QOQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAABF1BMVEUAAABpOcRqOsVrO8ZsPcZuPsdvQMdwQchxQ8hyRMlzRsl1R8p2Scp3S8p5Tst6T8x8Ucx9Us1/Vc6AV86BWc6DWs+EXM+FXdCGX9CHYNGIYtGNaNOOatORbdSSbtWUcdaVc9aWdNeYdteaedicfNmff9qggdqhgtuihNujhtulh9ymidynit2pjd6qj96skN+tkt+uk+Cwl+CzmuG0m+K1neK6o+S7peS8puW+qea/q+bBrOfEsejFs+nGtOnItunJt+rKuerNvezPv+zQwO3Rwu3SxO3Txe7Ux+7Xyu/Yy/DZzfDazvHb0PHd0vHg1vPh2PPi2fTl3PXm3vXn3/bo4fbp4/br5Pft5/jv6vny7frz7/r///8b1pnDAAAAAXRSTlMAQObYZgAAAAFiS0dEXOrYAJcAAAKmSURBVFjD5ddre9IwFADgNhjCZUAZl21cnbXbHJt4m2UwJuIu1rmCUJV2//9/CAVKDyeFtn7TfGFPsvM+SXqSngrCv9y+XzXr+9lsNl9TWndPAYOfPtUTEbs9sxuNHbQm/sN/NRfRDjAlKK3d+wufnEUJ4QGUljQf8R8ThHgBlB1tW8ikQsgGgFJp8yQGKbIFoOzdhvg7SrYD7NQz/poQPwA78po/FRGgtNtlBLBzbvzPuIiAq9lACwFM5QG7IgKU+YiMgPgAx78WMdCeD31GAMtZaANEDtCbj33DAN6GUkCAjWD8jRgUOIRAMTDAwD5+FYMDYBeOQwAp14OwYiEA1scrCAYoK+BtKCC3AsqhAPbDAXbCATfLeCMSDmgvgQcxHHCyBL6EBOS/BereQDbKASTfgGIKQi8KgVhXEPSSB3APgX27c5R1A5mx/VcOAC+XgA4Bfd5rHqyAgrm43ABw4eQBA4CTX/ISODSXXQC4dv4zzweE3+BnVjcA4MHpfwGAK+93H1hCxnD6LwEQHXnFm5IbqKwGhhHwGFMewjgHHmPTNbQHEyk64L47JZBIcd1dlqxlYkTH8XoMZmLF/XIaJtfPgsrZPwhcCpxr2XWYmjD+/fphyhlgfDEF92l85R4/Rafxw9oMz/FxllejMjrOJWMNMPbwfVBbZLBZQ/dBrIc2uc/whVKwk3hcwBfKMaoPBOsNxSVOeppSgwwuccoGJ08smeAiiw10hous4i03Ux+rPss8qe9xVrSqL2C3Y3mdNk2m24GSd/x0FY3kFiBWu91YbVtqcRPApLPHLfW+pTXSXgBLVDdN3yG6SpYLpKrq0N9Hj9FtlJIEfHTRRF7xG27PYthpPi+md+KURmk8nS+fqJoR8MvPMrRu52LW1I42DBr9X7U/PqNiTnkh61QAAAAASUVORK5CYII=
+// ==/UserScript==
+
+// Based on :
+//  @ name Download YouTube Videos as MP4
+//  @ description Adds a button that lets you download YouTube videos.
+//  @ homepageURL https://github.com/gantt/downloadyoutube
+//  @ author Gantt
+//  @ version 1.8.1
+
+    function parseQueryString(queryString) {
+    
+        var vars = queryString.split('&');
+
+	var hashmap = {};
+        for (var i = 0; i < vars.length; i++) {
+            var pair = vars[i].split('=');
+	    var key = decodeURIComponent(pair[0]);
+	    var val = decodeURIComponent(pair[1]);
+	    hashmap[key] = val;
+        }
+
+	return hashmap;
+    }
+
+    function respoolme(downloadURL) {
+	//alert("before ajax call: " + downloadURL);
+	var paramMap = parseQueryString(downloadURL);
+	var id    = paramMap.id;
+	var title = paramMap.title;
+	var mime  = paramMap.mime;
+
+	var base_url = "http://localhost:8383/greenstone3/respoolme-downloader.jsp";
+	var url = base_url + "?downloadURL="+ encodeURIComponent(downloadURL) + "&id=" + id + "&title=" + title + "&mime=" + mime;
+	
+	//console.log("#### Downloading: http://localhost:8383/greenstone3/respoolme-downloader.jsp?downloadURL="+ encodeURIComponent(downloadURL));
+	console.log("#### Downloading: " + url);
+	var busyIcon = document.getElementById("busy-icon");
+	busyIcon.setAttribute("style","display:block;");
+	
+	GM_xmlhttpRequest({
+	    method: "GET",
+	    //url: "http://localhost:8383/greenstone3/respoolme-downloader.jsp?downloadURL="+ encodeURIComponent(downloadURL),
+	    url: url,
+	    onprogress: function(response) {
+		console.log("*** onprogress()");
+	    },
+	    onreadystatechange: function(response) {
+		console.log("*** onreadystatechange()");
+	    },
+	    onload: function(response) {
+		console.log("**** response text from calling index.jsp: " + response.responseText);
+		busyIcon.setAttribute("style","display:none;");
+	    }
+	});
+    }
+
+
+(function () {
+  var FORMAT_LABEL={'5':'FLV 240p','18':'MP4 360p','22':'MP4 720p','34':'FLV 360p','35':'FLV 480p','37':'MP4 1080p','38':'MP4 2160p','43':'WebM 360p','44':'WebM 480p','45':'WebM 720p','46':'WebM 1080p','135':'MP4 480p - no audio','137':'MP4 1080p - no audio','138':'MP4 2160p - no audio','139':'M4A 48kbps - audio','140':'M4A 128kbps - audio','141':'M4A 256kbps - audio','264':'MP4 1440p - no audio','298':'MP4 720p60 - no audio','299':'MP4 1080p60 - no audio'};
+  var FORMAT_TYPE={'5':'flv','18':'mp4','22':'mp4','34':'flv','35':'flv','37':'mp4','38':'mp4','43':'webm','44':'webm','45':'webm','46':'webm','135':'mp4','137':'mp4','138':'mp4','139':'m4a','140':'m4a','141':'m4a','264':'mp4','298':'mp4','299':'mp4'};
+  var FORMAT_ORDER=['5','18','34','43','35','135','44','22','298','45','37','299','46','264','38','139','140','141'];
+  var FORMAT_RULE={'flv':'max','mp4':'all','webm':'none','m4a':'max'};
+  // all=display all versions, max=only highest quality version, none=no version  
+  // the default settings show all MP4 videos, the highest quality FLV and no WebM
+  var SHOW_DASH_FORMATS=false;
+  var BUTTON_TEXT={'ar':'ØªÙØ²ÙÙ','cs':'StÃ¡hnout','de':'Herunterladen','en':'Respool Me!','es':'Descargar','fr':'TÃ©lÃ©charger','hi':'à€¡à€Ÿà€à€šà€²à¥à€¡','hu':'LetÃ¶ltÃ©s','id':'Unduh','it':'Scarica','ja':'ããŠã³ã­ãŒã','ko':'ëŽë €ë°êž°','pl':'Pobierz','pt':'Baixar','ro':'DescÄrcaÈi','ru':'Ð¡ÐºÐ°ÑÐ°ÑÑ','tr':'Ä°ndir','zh':'äžèœœ','zh-TW':'äžèŒ'};
+  var BUTTON_TOOLTIP={'ar':'ØªÙØ²ÙÙ ÙØ°Ø§ Ø§ÙÙÙØ¯ÙÙ','cs':'StÃ¡hnout toto video','de':'Dieses Video herunterladen','en':'Wire this video to Popup Videos Respooled','es':'Descargar este vÃ­deo','fr':'TÃ©lÃ©charger cette vidÃ©o','hi':'à€µà¥à€¡à€¿à€¯à¥ à€¡à€Ÿà€à€šà€²à¥à€¡ à€à€°à¥à€','hu':'VideÃ³ letÃ¶ltÃ©se','id':'Unduh video ini','it':'Scarica questo video','ja':'ãã®ãããªãããŠã³ã­ãŒããã','ko':'ìŽ ë¹ëì€ë¥Œ ëŽë €ë°êž°','pl':'Pobierz plik wideo','pt':'Baixar este vÃ­deo','ro':'DescÄrcaÈi acest videoclip','ru':'Ð¡ÐºÐ°ÑÐ°ÑÑ ÑÑÐŸ Ð²ÐžÐŽÐµÐŸ','tr': 'Bu videoyu indir','zh':'äžèœœæ­€è§é¢','zh-TW':'äžèŒæ­€åœ±ç'};
+  var DECODE_RULE=[];
+  var RANDOM=7489235179; // Math.floor(Math.random()*1234567890);
+  var CONTAINER_ID='download-youtube-video'+RANDOM;
+  var LISTITEM_ID='download-youtube-video-fmt'+RANDOM;
+  var BUTTON_ID='download-youtube-video-button'+RANDOM;
+  var DEBUG_ID='download-youtube-video-debug-info';
+  var STORAGE_URL='download-youtube-script-url';
+  var STORAGE_CODE='download-youtube-signature-code';
+  var STORAGE_DASH='download-youtube-dash-enabled';
+  var isDecodeRuleUpdated=false;  
+    
+  start();
+          
+function start() {
+  var pagecontainer=document.getElementById('page-container');
+  if (!pagecontainer) return;
+  if (/^https?:\/\/www\.youtube.com\/watch\?/.test(window.location.href)) run();     
+  var isAjax=/class[\w\s"'-=]+spf\-link/.test(pagecontainer.innerHTML);
+  var content=document.getElementById('content');
+  if (isAjax && content) { // Ajax UI
+      var mo=window.MutationObserver||window.WebKitMutationObserver;
+      if(typeof mo!=='undefined') {
+        var observer=new mo(function(mutations) {
+          mutations.forEach(function(mutation) {
+              if(mutation.addedNodes!==null) {
+                for (var i=0; i<mutation.addedNodes.length; i++) {
+                    if (mutation.addedNodes[i].id=='watch7-container') { // old value: movie_player
+                      run();
+                      break;
+                    }
+                }
+              }
+          });
+        });
+        observer.observe(content, {childList: true, subtree: true}); // old value: pagecontainer
+      } else { // MutationObserver fallback for old browsers
+	  // supressed the YouTube downloader menu // ****
+          // pagecontainer.addEventListener('DOMNodeInserted', onNodeInserted, false);
+      }
+  } 
+}
+
+function onNodeInserted(e) { 
+    if (e && e.target && e.target.id=='watch7-container') { // old value: movie_player
+      run();
+  }
+}
+  
+function run() {
+  if (document.getElementById(CONTAINER_ID)) return; // check download container
+  if (document.getElementById('p') && document.getElementById('vo')) return; // Feather not supported
+
+  var videoID, videoFormats, videoAdaptFormats, videoManifestURL, scriptURL=null;
+  var isSignatureUpdatingStarted=false;
+  var operaTable=new Array();
+  var language=document.documentElement.getAttribute('lang');
+  var textDirection='left';
+  if (document.body.getAttribute('dir')=='rtl') {
+    textDirection='right';
+  }
+  if (document.getElementById('watch7-action-buttons')) {  // old UI
+    fixTranslations(language, textDirection);
+  }
+        
+  // obtain video ID, formats map   
+  
+  var args=null;
+  var usw=(typeof this.unsafeWindow !== 'undefined')?this.unsafeWindow:window; // Firefox, Opera<15
+  if (usw.ytplayer && usw.ytplayer.config && usw.ytplayer.config.args) {
+    args=usw.ytplayer.config.args;
+  }
+  if (args) {
+    videoID=args['video_id'];
+    videoFormats=args['url_encoded_fmt_stream_map'];
+    videoAdaptFormats=args['adaptive_fmts'];
+    videoManifestURL=args['dashmpd'];
+    debug('DYVAM - Info: Standard mode. videoID '+(videoID?videoID:'none')+'; ');
+  }
+  if (usw.ytplayer && usw.ytplayer.config && usw.ytplayer.config.assets) {
+    scriptURL=usw.ytplayer.config.assets.js;
+  }  
+  
+  if (videoID==null) { // unsafeWindow workaround (Chrome, Opera 15+)
+    var buffer=document.getElementById(DEBUG_ID+'2')
+    if (buffer) {
+      while (buffer.firstChild) {
+        buffer.removeChild(buffer.firstChild);
+      }
+    } else {
+      buffer=createHiddenElem('pre', DEBUG_ID+'2');
+    }    
+    injectScript ('document.getElementById("'+DEBUG_ID+'2").appendChild(document.createTextNode(\'"video_id":"\'+ytplayer.config.args.video_id+\'", "js":"\'+ytplayer.config.assets.js+\'", "dashmpd":"\'+ytplayer.config.args.dashmpd+\'", "url_encoded_fmt_stream_map":"\'+ytplayer.config.args.url_encoded_fmt_stream_map+\'", "adaptive_fmts":"\'+ytplayer.config.args.adaptive_fmts+\'"\'));');
+    var code=buffer.innerHTML;
+    if (code) {
+      videoID=findMatch(code, /\"video_id\":\s*\"([^\"]+)\"/);
+      videoFormats=findMatch(code, /\"url_encoded_fmt_stream_map\":\s*\"([^\"]+)\"/);
+      videoFormats=videoFormats.replace(/&amp;/g,'\\u0026');
+      videoAdaptFormats=findMatch(code, /\"adaptive_fmts\":\s*\"([^\"]+)\"/);
+      videoAdaptFormats=videoAdaptFormats.replace(/&amp;/g,'\\u0026');
+      videoManifestURL=findMatch(code, /\"dashmpd\":\s*\"([^\"]+)\"/);
+      scriptURL=findMatch(code, /\"js\":\s*\"([^\"]+)\"/);
+    }
+    debug('DYVAM - Info: Injection mode. videoID '+(videoID?videoID:'none')+'; ');
+  }
+     
+  if (videoID==null) { // if all else fails
+    var bodyContent=document.body.innerHTML;  
+    if (bodyContent!=null) {
+      videoID=findMatch(bodyContent, /\"video_id\":\s*\"([^\"]+)\"/);
+      videoFormats=findMatch(bodyContent, /\"url_encoded_fmt_stream_map\":\s*\"([^\"]+)\"/);
+      videoAdaptFormats=findMatch(bodyContent, /\"adaptive_fmts\":\s*\"([^\"]+)\"/);
+      videoManifestURL=findMatch(bodyContent, /\"dashmpd\":\s*\"([^\"]+)\"/);
+      if (scriptURL==null) {
+        scriptURL=findMatch(bodyContent, /\"js\":\s*\"([^\"]+)\"/);
+        scriptURL=scriptURL.replace(/\\/g,'');
+      }      
+    }
+    debug('DYVAM - Info: Brute mode. videoID '+(videoID?videoID:'none')+'; ');
+  }
+  
+  debug('DYVAM - Info: url '+window.location.href+'; useragent '+window.navigator.userAgent);  
+  
+  if (videoID==null || videoFormats==null || videoID.length==0 || videoFormats.length==0) {
+   debug('DYVAM - Error: No config information found. YouTube must have changed the code.');
+   return;
+  }
+  
+  // Opera 12 extension message handler
+  if (typeof window.opera !== 'undefined' && window.opera && typeof opera.extension !== 'undefined') {
+    opera.extension.onmessage = function(event) {
+      var index=findMatch(event.data.action, /xhr\-([0-9]+)\-response/);
+      if (index && operaTable[parseInt(index,10)]) {
+        index=parseInt(index,10);
+        var trigger=(operaTable[index])['onload'];
+        if (typeof trigger === 'function' && event.data.readyState == 4) {
+          if (trigger) {
+              trigger(event.data);         
+          }
+        }
+      }
+    }
+  }
+    
+  if (!isDecodeRuleUpdated) {
+    DECODE_RULE=getDecodeRules(DECODE_RULE);
+    isDecodeRuleUpdated=true;
+  }
+  if (scriptURL) {
+    if (scriptURL.indexOf('//')==0) {
+      var protocol=(document.location.protocol=='http:')?'http:':'https:';
+      scriptURL=protocol+scriptURL;
+    }
+    fetchSignatureScript(scriptURL);
+  }
+  
+   // video title
+  var videoTitle=document.title || 'video';
+  videoTitle=videoTitle.replace(/\s*\-\s*YouTube$/i,'').replace(/[#"\?:\*]/g,'').replace(/[&\|\\\/]/g,'_').replace(/'/g,'\'').replace(/^\s+|\s+$/g,'').replace(/\.+$/g,'');  
+                        
+  // parse the formats map
+  var sep1='%2C', sep2='%26', sep3='%3D';
+  if (videoFormats.indexOf(',')>-1) { 
+    sep1=','; 
+    sep2=(videoFormats.indexOf('&')>-1)?'&':'\\u0026'; 
+    sep3='=';
+  }
+  var videoURL=new Array();
+  var videoSignature=new Array();
+  if (videoAdaptFormats) {
+    videoFormats=videoFormats+sep1+videoAdaptFormats;
+  }
+  var videoFormatsGroup=videoFormats.split(sep1);
+  for (var i=0;i<videoFormatsGroup.length;i++) {
+    var videoFormatsElem=videoFormatsGroup[i].split(sep2);
+    var videoFormatsPair=new Array();
+    for (var j=0;j<videoFormatsElem.length;j++) {
+      var pair=videoFormatsElem[j].split(sep3);
+      if (pair.length==2) {
+        videoFormatsPair[pair[0]]=pair[1];
+      }
+    }
+    if (videoFormatsPair['url']==null) continue;
+    var url=unescape(unescape(videoFormatsPair['url'])).replace(/\\\//g,'/').replace(/\\u0026/g,'&');
+    if (videoFormatsPair['itag']==null) continue;
+    var itag=videoFormatsPair['itag'];
+    var sig=videoFormatsPair['sig']||videoFormatsPair['signature'];
+    if (sig) {
+      url=url+'&signature='+sig;
+      videoSignature[itag]=null;
+    } else if (videoFormatsPair['s']) {
+      url=url+'&signature='+decryptSignature(videoFormatsPair['s']);
+      videoSignature[itag]=videoFormatsPair['s'];
+    }
+    if (url.toLowerCase().indexOf('ratebypass')==-1) { // speed up download for dash
+      url=url+'&ratebypass=yes';
+    }
+    if (url.toLowerCase().indexOf('http')==0) { // validate URL
+      videoURL[itag]=url+'&title='+videoTitle;
+    }
+  }
+    
+  var showFormat=new Array();
+  for (var category in FORMAT_RULE) {
+    var rule=FORMAT_RULE[category];
+    for (var index in FORMAT_TYPE){
+      if (FORMAT_TYPE[index]==category) {
+        showFormat[index]=(rule=='all');
+      }
+    }
+    if (rule=='max') {
+      for (var i=FORMAT_ORDER.length-1;i>=0;i--) {
+        var format=FORMAT_ORDER[i];
+        if (FORMAT_TYPE[format]==category && videoURL[format]!=undefined) {
+          showFormat[format]=true;
+          break;
+        }
+      }
+    }
+  }
+  
+  var dashPref=getPref(STORAGE_DASH);
+  if (dashPref=='1') {
+    SHOW_DASH_FORMATS=true;
+  } else if (dashPref!='0') {
+    setPref(STORAGE_DASH,'0');
+  }
+  
+  var downloadCodeList=[];
+  for (var i=0;i<FORMAT_ORDER.length;i++) {
+    var format=FORMAT_ORDER[i];
+    if (format=='37' && videoURL[format]==undefined) { // hack for dash 1080p
+      if (videoURL['137']) {
+       format='137';
+      }
+      showFormat[format]=showFormat['37'];
+    } else if (format=='38' && videoURL[format]==undefined) { // hack for dash 4K
+      if (videoURL['138']) {
+       format='138';
+      }
+      showFormat[format]=showFormat['38'];
+    }    
+    if (!SHOW_DASH_FORMATS && format.length>2) continue;
+    if (videoURL[format]!=undefined && FORMAT_LABEL[format]!=undefined && showFormat[format]) {
+      downloadCodeList.push({url:videoURL[format],sig:videoSignature[format],format:format,label:FORMAT_LABEL[format]});
+      debug('DYVAM - Info: itag'+format+' url:'+videoURL[format]);
+    }
+  }  
+  
+  if (downloadCodeList.length==0) {
+    debug('DYVAM - Error: No download URL found. Probably YouTube uses encrypted streams.');
+    return; // no format
+  } 
+    
+  // find parent container
+  var newWatchPage=false;
+  var parentElement=document.getElementById('watch7-action-buttons');
+  if (parentElement==null) {
+    parentElement=document.getElementById('watch8-secondary-actions');
+    if (parentElement==null) {
+      debug('DYVAM Error - No container for adding the download button. YouTube must have changed the code.');
+      return;
+    } else {
+      newWatchPage=true;
+    }
+  }
+  
+  // get button labels
+  var buttonText=(BUTTON_TEXT[language])?BUTTON_TEXT[language]:BUTTON_TEXT['en'];
+  var buttonLabel=(BUTTON_TOOLTIP[language])?BUTTON_TOOLTIP[language]:BUTTON_TOOLTIP['en'];
+    
+  // generate download code for regular interface
+  var mainSpan=document.createElement('span');
+
+  if (newWatchPage) {
+    var spanIcon=document.createElement('span');
+    spanIcon.setAttribute('class', 'yt-uix-button-icon-wrapper');
+    spanIcon.setAttribute('style', 'opacity: 1.0; color: white');
+    var imageIcon=document.createElement('img');
+    imageIcon.setAttribute('src', '//s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif');
+    imageIcon.setAttribute('class', 'yt-uix-button-icon');
+      imageIcon.setAttribute('style', 'width:20px;height:20px;background-size:20px 20px;background-repeat:no-repeat;background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABG0lEQVRYR+2W0Q3CMAxE2wkYAdiEEWADmIxuACMwCmzABpCTEmRSO7YTQX+ChECV43t2nF7GYeHPuLD+0AKwC/DnWMAp/N5qimkBuAfBdRTF/+2/AV6ZYFUxVYuicAfoHegd6B3oHfhZB+ByF+JyV8FkrAB74pqH3DU5L3iGoBURhdVODIQF4EjEkWLmmhYALOQgNIBcHHke4buhxXAAaFnaAhqbQ5QAOHHkwhZ8balkx1ICCiEBWNZ+CivdB7REHIC2ZjZK2oWklDDdB1NSdCd/Js2PqQMpSIKYVcM8kE6QCwDBNRCqOBJrW0CL8kCYxL0A1k6YxWsANAiXeC2ABOEWbwHAWrwxpzgkmA/JtIqnxTOElmPnjlkc4A3FykAhA42AxwAAAABJRU5ErkJggg==);'); // ****
+
+      var imageBusyIcon=document.createElement('img');
+      imageBusyIcon.setAttribute('class', 'yt-uix-button-icon');
+      imageBusyIcon.setAttribute('id', 'busy-icon');
+      imageBusyIcon.setAttribute('width', '90');
+      imageBusyIcon.setAttribute('style', 'display:none;');
+      imageBusyIcon.setAttribute('src', 'data:image/gif;base64,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');
+      
+      spanIcon.appendChild(imageIcon);
+      spanIcon.appendChild(imageBusyIcon);
+    mainSpan.appendChild(spanIcon);
+  }
+
+  var spanButton=document.createElement('span');
+  spanButton.setAttribute('class', 'yt-uix-button-content');
+  spanButton.setAttribute('style', 'opacity: 1.0; color: white')
+  spanButton.appendChild(document.createTextNode(buttonText+' '));
+  mainSpan.appendChild(spanButton);
+  
+  if (!newWatchPage) { // old UI
+    var imgButton=document.createElement('img');
+    imgButton.setAttribute('class', 'yt-uix-button-arrow');
+    imgButton.setAttribute('src', '//s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif');
+    mainSpan.appendChild(imgButton);
+  }
+
+  var listItems=document.createElement('ol');
+  listItems.setAttribute('style', 'display:none;');
+  listItems.setAttribute('class', 'yt-uix-button-menu');
+  for (var i=0;i<downloadCodeList.length;i++) {
+    var listItem=document.createElement('li');
+    var listLink=document.createElement('a');
+    listLink.setAttribute('style', 'text-decoration:none;');
+    listLink.setAttribute('href', downloadCodeList[i].url);
+    listLink.setAttribute('download', videoTitle+'.'+FORMAT_TYPE[downloadCodeList[i].format]);
+    var listButton=document.createElement('span');
+    listButton.setAttribute('class', 'yt-uix-button-menu-item');
+    listButton.setAttribute('loop', i+'');
+    listButton.setAttribute('id', LISTITEM_ID+downloadCodeList[i].format);
+    listButton.appendChild(document.createTextNode(downloadCodeList[i].label));
+    listLink.appendChild(listButton);
+    listItem.appendChild(listLink);
+    listItems.appendChild(listItem); 
+  }
+  //mainSpan.appendChild(listItems); // ****
+  var buttonElement=document.createElement('button');
+  buttonElement.setAttribute('id', BUTTON_ID);
+  if (newWatchPage) {
+    buttonElement.setAttribute('class', 'yt-uix-button  yt-uix-button-size-default yt-uix-button-opacity yt-uix-tooltip');
+    buttonElement.setAttribute('style', 'background-color:#6E00AF; opacity: 1.0;'); // ****
+  } else { // old UI
+    buttonElement.setAttribute('class', 'yt-uix-button yt-uix-tooltip yt-uix-button-empty yt-uix-button-text');
+    buttonElement.setAttribute('style', 'background-color:#6E00AF; opacity: 1.0; margin-top:4px; margin-left:'+((textDirection=='left')?5:10)+'px;'); // ****
+  }
+  buttonElement.setAttribute('data-tooltip-text', buttonLabel);  
+  buttonElement.setAttribute('type', 'button');
+  buttonElement.setAttribute('role', 'button');
+    //buttonElement.addEventListener('click', function(){return false;}, false);
+    buttonElement.addEventListener("click", function() { console.log("*** videoURL = " + JSON.stringify(videoURL)); respoolme(videoURL['18']) }, false);
+
+  buttonElement.appendChild(mainSpan);
+  var containerSpan=document.createElement('span');
+  containerSpan.setAttribute('id', CONTAINER_ID);
+  containerSpan.appendChild(document.createTextNode(' '));
+  containerSpan.appendChild(buttonElement);
+                                            
+  // add the button
+  if (!newWatchPage) { // watch7
+    parentElement.appendChild(containerSpan);
+  } else { // watch8
+      parentElement.insertBefore(containerSpan, parentElement.firstChild);
+      //document.getElementById("early-body").appendChild(containerSpan);
+
+  }
+    
+  // REPLACEWITH if (!isSignatureUpdatingStarted) {
+    for (var i=0;i<downloadCodeList.length;i++) { 
+      addFileSize(downloadCodeList[i].url, downloadCodeList[i].format);
+    }
+  // } 
+  
+  if (typeof GM_download !== 'undefined') {
+    for (var i=0;i<downloadCodeList.length;i++) {
+      var downloadFMT=document.getElementById(LISTITEM_ID+downloadCodeList[i].format);
+      var url=(downloadCodeList[i].url).toLowerCase();
+      if (url.indexOf('clen=')>0 && url.indexOf('dur=')>0 && url.indexOf('gir=')>0
+          && url.indexOf('lmt=')>0) {
+	  // supressed the YouTube downloader menu // ****
+        //downloadFMT.addEventListener('click', downloadVideoNatively, false);
+      }
+    }
+  }
+  
+  addFromManifest('140', '141'); // replace fmt140 with fmt141 if found in manifest
+  
+  function downloadVideoNatively(e) {
+    var elem=e.currentTarget;
+    e.returnValue=false;    
+    if (e.preventDefault) {
+      e.preventDefault();
+    }
+    var loop=elem.getAttribute('loop');
+    if (loop) {
+      GM_download(downloadCodeList[loop].url, videoTitle+'.'+FORMAT_TYPE[downloadCodeList[loop].format]);
+    }
+    return false;
+  }
+  
+  function addFromManifest(oldFormat, newFormat) { // find newFormat URL in manifest
+    if (videoManifestURL && videoURL[newFormat]==undefined && SHOW_DASH_FORMATS && FORMAT_RULE['m4a']=='max') {
+      var matchSig=findMatch(videoManifestURL, /\/s\/([a-zA-Z0-9\.]+)\//i);
+      if (matchSig) {
+        var decryptedSig=decryptSignature(matchSig);
+        if (decryptedSig) {
+          videoManifestURL=videoManifestURL.replace('/s/'+matchSig+'/','/signature/'+decryptedSig+'/');
+        }
+      }
+      if (videoManifestURL.indexOf('//')==0) {
+        var protocol=(document.location.protocol=='http:')?'http:':'https:';
+        videoManifestURL=protocol+videoManifestURL;
+      }
+      debug('DYVAM - Info: manifestURL '+videoManifestURL);
+      crossXmlHttpRequest({
+          method:'GET',
+          url:videoManifestURL, // check if URL exists
+          onload:function(response) {
+            if (response.readyState === 4 && response.status === 200 && response.responseText) {
+              var regexp = new RegExp('<BaseURL.+>(http[^<]+itag='+newFormat+'[^<]+)<\\/BaseURL>','i');
+              var matchURL=findMatch(response.responseText, regexp);
+              debug('DYVAM - Info: matchURL '+matchURL);
+              if (!matchURL) return;
+              matchURL=matchURL.replace(/&amp\;/g,'&');
+              for (var i=0;i<downloadCodeList.length;i++) {
+                if (downloadCodeList[i].format==oldFormat) {
+                  downloadCodeList[i].format==newFormat;
+                  var downloadFMT=document.getElementById(LISTITEM_ID+oldFormat);
+                  downloadFMT.setAttribute('id', LISTITEM_ID+newFormat);
+                  downloadFMT.parentNode.setAttribute('href', matchURL);
+                  downloadCodeList[i].url=matchURL;
+                  downloadFMT.firstChild.nodeValue=FORMAT_LABEL[newFormat];
+                  addFileSize(matchURL, newFormat);
+                }
+              }
+            }
+          } 
+        });
+    }  
+  }
+  
+  function injectStyle(code) {
+    var style=document.createElement('style');
+    style.type='text/css';
+    style.appendChild(document.createTextNode(code));
+    document.getElementsByTagName('head')[0].appendChild(style);
+  }
+  
+  function injectScript(code) {
+    var script=document.createElement('script');
+    script.type='application/javascript';
+    script.textContent=code;
+    document.body.appendChild(script);
+    document.body.removeChild(script);
+  }    
+  
+  function debug(str) {
+    var debugElem=document.getElementById(DEBUG_ID);
+    if (!debugElem) {
+      debugElem=createHiddenElem('div', DEBUG_ID);
+    }
+    debugElem.appendChild(document.createTextNode(str+' '));
+  }
+  
+  function createHiddenElem(tag, id) {
+    var elem=document.createElement(tag);
+    elem.setAttribute('id', id);
+    elem.setAttribute('style', 'display:none;');
+    document.body.appendChild(elem);
+    return elem;
+  }
+  
+  function fixTranslations(language, textDirection) {  
+    if (/^af|bg|bn|ca|cs|de|el|es|et|eu|fa|fi|fil|fr|gl|hi|hr|hu|id|it|iw|kn|lv|lt|ml|mr|ms|nl|pl|ro|ru|sl|sk|sr|sw|ta|te|th|uk|ur|vi|zu$/.test(language)) { // fix international UI
+      var likeButton=document.getElementById('watch-like');
+      if (likeButton) {
+        var spanElements=likeButton.getElementsByClassName('yt-uix-button-content');
+        if (spanElements) {
+          spanElements[0].style.display='none'; // hide like text
+        }
+      }
+      var marginPixels=10;
+      if (/^bg|ca|cs|el|eu|hr|it|ml|ms|pl|sl|sw|te$/.test(language)) {
+        marginPixels=1;
+      }
+      injectStyle('#watch7-secondary-actions .yt-uix-button{margin-'+textDirection+':'+marginPixels+'px!important}');
+    }
+  }
+  
+  function findMatch(text, regexp) {
+    var matches=text.match(regexp);
+    return (matches)?matches[1]:null;
+  }
+  
+  function isString(s) {
+    return (typeof s==='string' || s instanceof String);
+  }
+    
+  function isInteger(n) {
+    return (typeof n==='number' && n%1==0);
+  }
+  
+  function getPref(name) { // cross-browser GM_getValue
+    var a='', b='';
+    try {a=typeof GM_getValue.toString; b=GM_getValue.toString()} catch(e){}    
+    if (typeof GM_getValue === 'function' && 
+    (a === 'undefined' || b.indexOf('not supported') === -1)) {
+      return GM_getValue(name, null); // Greasemonkey, Tampermonkey, Firefox extension
+    } else {
+        var ls=null;
+        try {ls=window.localStorage||null} catch(e){}
+        if (ls) {
+          return ls.getItem(name); // Chrome script, Opera extensions
+        }
+    }
+    return;
+  }
+  
+  function setPref(name, value) { //  cross-browser GM_setValue
+    var a='', b='';
+    try {a=typeof GM_setValue.toString; b=GM_setValue.toString()} catch(e){}    
+    if (typeof GM_setValue === 'function' && 
+    (a === 'undefined' || b.indexOf('not supported') === -1)) {
+      GM_setValue(name, value); // Greasemonkey, Tampermonkey, Firefox extension
+    } else {
+        var ls=null;
+        try {ls=window.localStorage||null} catch(e){}
+        if (ls) {
+          return ls.setItem(name, value); // Chrome script, Opera extensions
+        }
+    }
+  }
+  
+  function crossXmlHttpRequest(details) { // cross-browser GM_xmlhttpRequest
+    if (typeof GM_xmlhttpRequest === 'function') { // Greasemonkey, Tampermonkey, Firefox extension, Chrome script
+      GM_xmlhttpRequest(details);
+    } else if (typeof window.opera !== 'undefined' && window.opera && typeof opera.extension !== 'undefined' && 
+               typeof opera.extension.postMessage !== 'undefined') { // Opera 12 extension
+        var index=operaTable.length;
+        opera.extension.postMessage({'action':'xhr-'+index, 'url':details.url, 'method':details.method});
+        operaTable[index]=details;
+    } else if (typeof window.opera === 'undefined' && typeof XMLHttpRequest === 'function') { // Opera 15+ extension
+        var xhr=new XMLHttpRequest();
+        xhr.onreadystatechange = function() {
+          if (xhr.readyState == 4) {
+            if (details['onload']) {
+              details['onload'](xhr);
+            }
+          }
+        }
+        xhr.open(details.method, details.url, true);
+        xhr.send();
+    }
+  }
+   
+  function addFileSize(url, format) {
+  
+    function updateVideoLabel(size, format) {
+      var elem=document.getElementById(LISTITEM_ID+format);
+      if (elem) {
+        size=parseInt(size,10);
+        if (size>=1073741824) {
+          size=parseFloat((size/1073741824).toFixed(1))+' GB';
+        } else if (size>=1048576) {
+          size=parseFloat((size/1048576).toFixed(1))+' MB';
+        } else {
+          size=parseFloat((size/1024).toFixed(1))+' KB';
+        }
+        if (elem.childNodes.length>1) {
+            elem.lastChild.nodeValue=' ('+size+')';
+        } else if (elem.childNodes.length==1) {
+            elem.appendChild(document.createTextNode(' ('+size+')'));
+        }
+      }
+    }
+        
+    var matchSize=findMatch(url, /[&\?]clen=([0-9]+)&/i);
+    if (matchSize) {
+      updateVideoLabel(matchSize, format);
+    } else {
+      try {
+        crossXmlHttpRequest({
+          method:'HEAD',
+          url:url,
+          onload:function(response) {
+            if (response.readyState == 4 && response.status == 200) { // add size
+              var size=0;
+              if (typeof response.getResponseHeader === 'function') {
+                size=response.getResponseHeader('Content-length');
+              } else if (response.responseHeaders) {
+                  var regexp = new RegExp('^Content\-length: (.*)$','im');
+                  var match = regexp.exec(response.responseHeaders);
+                  if (match) {
+                    size=match[1];
+                  }
+              }
+              if (size) {
+                updateVideoLabel(size, format);
+              }
+            }
+          }
+        });
+      } catch(e) { }
+    }
+  }
+  
+  function findSignatureCode(sourceCode) {
+    debug('DYVAM - Info: signature start '+getPref(STORAGE_CODE));
+    var signatureFunctionName = 
+    findMatch(sourceCode, 
+    /\.set\s*\("signature"\s*,\s*([a-zA-Z0-9_$][\w$]*)\(/)
+    || findMatch(sourceCode, 
+    /\.sig\s*\|\|\s*([a-zA-Z0-9_$][\w$]*)\(/)
+    || findMatch(sourceCode, 
+    /\.signature\s*=\s*([a-zA-Z_$][\w$]*)\([a-zA-Z_$][\w$]*\)/); //old
+    if (signatureFunctionName == null) return setPref(STORAGE_CODE, 'error');
+    signatureFunctionName=signatureFunctionName.replace('$','\\$');    
+    var regCode = new RegExp('function \\s*' + signatureFunctionName +
+    '\\s*\\([\\w$]*\\)\\s*{[\\w$]*=[\\w$]*\\.split\\(""\\);(.+);return [\\w$]*\\.join');
+    var functionCode = findMatch(sourceCode, regCode);
+    debug('DYVAM - Info: signaturefunction ' + signatureFunctionName + ' -- ' + functionCode);            
+    if (functionCode == null) return setPref(STORAGE_CODE, 'error');
+    
+    var reverseFunctionName = findMatch(sourceCode, 
+    /([\w$]*)\s*:\s*function\s*\(\s*[\w$]*\s*\)\s*{\s*(?:return\s*)?[\w$]*\.reverse\s*\(\s*\)\s*}/);
+    debug('DYVAM - Info: reversefunction ' + reverseFunctionName);
+    if (reverseFunctionName) reverseFunctionName=reverseFunctionName.replace('$','\\$');        
+    var sliceFunctionName = findMatch(sourceCode, 
+    /([\w$]*)\s*:\s*function\s*\(\s*[\w$]*\s*,\s*[\w$]*\s*\)\s*{\s*(?:return\s*)?[\w$]*\.(?:slice|splice)\(.+\)\s*}/);
+    debug('DYVAM - Info: slicefunction ' + sliceFunctionName);
+    if (sliceFunctionName) sliceFunctionName=sliceFunctionName.replace('$','\\$');    
+    
+    var regSlice = new RegExp('\\.(?:'+'slice'+(sliceFunctionName?'|'+sliceFunctionName:'')+
+    ')\\s*\\(\\s*(?:[a-zA-Z_$][\\w$]*\\s*,)?\\s*([0-9]+)\\s*\\)'); // .slice(5) sau .Hf(a,5)
+    var regReverse = new RegExp('\\.(?:'+'reverse'+(reverseFunctionName?'|'+reverseFunctionName:'')+
+    ')\\s*\\([^\\)]*\\)');  // .reverse() sau .Gf(a,45)
+    var regSwap = new RegExp('[\\w$]+\\s*\\(\\s*[\\w$]+\\s*,\\s*([0-9]+)\\s*\\)');
+    var regInline = new RegExp('[\\w$]+\\[0\\]\\s*=\\s*[\\w$]+\\[([0-9]+)\\s*%\\s*[\\w$]+\\.length\\]');
+    var functionCodePieces=functionCode.split(';');
+    var decodeArray=[];
+    for (var i=0; i<functionCodePieces.length; i++) {
+      functionCodePieces[i]=functionCodePieces[i].trim();
+      var codeLine=functionCodePieces[i];
+      if (codeLine.length>0) {
+        var arrSlice=codeLine.match(regSlice);
+        var arrReverse=codeLine.match(regReverse);
+        debug(i+': '+codeLine+' --'+(arrSlice?' slice length '+arrSlice.length:'') +' '+(arrReverse?'reverse':''));
+        if (arrSlice && arrSlice.length >= 2) { // slice
+        var slice=parseInt(arrSlice[1], 10);
+        if (isInteger(slice)){ 
+          decodeArray.push(-slice);
+        } else return setPref(STORAGE_CODE, 'error');
+      } else if (arrReverse && arrReverse.length >= 1) { // reverse
+        decodeArray.push(0);
+      } else if (codeLine.indexOf('[0]') >= 0) { // inline swap
+          if (i+2<functionCodePieces.length &&
+          functionCodePieces[i+1].indexOf('.length') >= 0 &&
+          functionCodePieces[i+1].indexOf('[0]') >= 0) {
+            var inline=findMatch(functionCodePieces[i+1], regInline);
+            inline=parseInt(inline, 10);
+            decodeArray.push(inline);
+            i+=2;
+          } else return setPref(STORAGE_CODE, 'error');
+      } else if (codeLine.indexOf(',') >= 0) { // swap
+        var swap=findMatch(codeLine, regSwap);      
+        swap=parseInt(swap, 10);
+        if (isInteger(swap) && swap>0){
+          decodeArray.push(swap);
+        } else return setPref(STORAGE_CODE, 'error');
+      } else return setPref(STORAGE_CODE, 'error');
+      }
+    }
+    
+    if (decodeArray) {
+      setPref(STORAGE_URL, scriptURL);
+      setPref(STORAGE_CODE, decodeArray.toString());
+      DECODE_RULE=decodeArray;
+      debug('DYVAM - Info: signature '+decodeArray.toString()+' '+scriptURL);
+      // update download links and add file sizes
+      for (var i=0;i<downloadCodeList.length;i++) {        
+        var elem=document.getElementById(LISTITEM_ID+downloadCodeList[i].format);
+        var url=downloadCodeList[i].url;
+        var sig=downloadCodeList[i].sig;
+        if (elem && url && sig) {
+          url=url.replace(/\&signature=[\w\.]+/, '&signature='+decryptSignature(sig));
+          elem.parentNode.setAttribute('href', url);
+          addFileSize(url, downloadCodeList[i].format);
+        }
+      }
+    }
+  }
+  
+  function isValidSignatureCode(arr) { // valid values: '5,-3,0,2,5', 'error'
+    if (!arr) return false;
+    if (arr=='error') return true;
+    arr=arr.split(',');
+    for (var i=0;i<arr.length;i++) {
+      if (!isInteger(parseInt(arr[i],10))) return false;
+    }
+    return true;
+  }
+  
+  function fetchSignatureScript(scriptURL) {
+    var storageURL=getPref(STORAGE_URL);
+    var storageCode=getPref(STORAGE_CODE);
+    if (!(/,0,|^0,|,0$|\-/.test(storageCode))) storageCode=null; // hack for only positive items
+    if (storageCode && isValidSignatureCode(storageCode) && storageURL &&
+        scriptURL.replace(/^https?/i,'')==storageURL.replace(/^https?/i,'')) return;
+    try {
+      debug('DYVAM fetch '+scriptURL);
+      isSignatureUpdatingStarted=true;    
+      crossXmlHttpRequest({
+        method:'GET',
+        url:scriptURL,
+        onload:function(response) {
+          debug('DYVAM fetch status '+response.status);
+          if (response.readyState === 4 && response.status === 200 && response.responseText) {
+            findSignatureCode(response.responseText);
+          }
+        } 
+      });
+    } catch(e) { }
+  }
+  
+  function getDecodeRules(rules) {
+    var storageCode=getPref(STORAGE_CODE);    
+    if (storageCode && storageCode!='error' && isValidSignatureCode(storageCode)) {
+      var arr=storageCode.split(',');
+      for (var i=0; i<arr.length; i++) {
+        arr[i]=parseInt(arr[i], 10);
+      }
+      rules=arr;
+      debug('DYVAM - Info: signature '+arr.toString()+' '+scriptURL);
+    }
+    return rules;
+  }
+  
+  function decryptSignature(sig) {
+    function swap(a,b){var c=a[0];a[0]=a[b%a.length];a[b]=c;return a};
+    function decode(sig, arr) { // encoded decryption
+      if (!isString(sig)) return null;
+      var sigA=sig.split('');
+      for (var i=0;i<arr.length;i++) {
+        var act=arr[i];
+        if (!isInteger(act)) return null;
+        sigA=(act>0)?swap(sigA, act):((act==0)?sigA.reverse():sigA.slice(-act));
+      }
+      var result=sigA.join('');
+      return result;
+    }
+    
+    if (sig==null) return '';    
+    var arr=DECODE_RULE;
+    if (arr) {
+      var sig2=decode(sig, arr);
+      if (sig2) return sig2;
+    } else {
+      setPref(STORAGE_URL, '');
+      setPref(STORAGE_CODE, '');
+    }
+    return sig; 
+  }  
+      
+  }
+ 
+})();
+
