Change input item options handling in the lua http interface. Fixes normal playlist...
authorAntoine Cellerier <dionoea@videolan.org>
Thu, 3 Apr 2008 20:11:13 +0000 (22:11 +0200)
committerAntoine Cellerier <dionoea@videolan.org>
Sun, 6 Apr 2008 17:00:26 +0000 (19:00 +0200)
share/lua/http/dialogs/input
share/lua/http/dialogs/sout
share/lua/http/flash.html
share/lua/http/js/functions.js
share/lua/http/requests/status.xml
share/lua/intf/http.lua

index fd09943..dbcfec9 100644 (file)
@@ -32,14 +32,23 @@ This dialog needs the following dialogs to be fully functional: browse
     <img class="close" src="images/white_cross_small.png" alt="Close" onclick="hide('input');"/>
   </div>
   <div class="controls">
-    <label for="input_mrl">Input (MRL)</label>
+    <label for="input_mrl">Input</label>
     <?vlc if current_page == "vlm" then ?>
       <input type="text" name="input_mrl" id="input_mrl" size="60" onkeypress="if( event.keyCode == 13 ) vlm_input_change();"/>
+    <?vlc else ?>
+      <input type="text" name="input_mrl" id="input_mrl" size="60" onkeypress="if( event.keyCode == 13 ) in_play();"/>
+    <?vlc end ?>
+    <div>
+    Options
+    <!-- <input type="button" value="Refresh options" onclick="refresh_input_options_list();" /> -->
+    <input type="button" value="Add option" onclick="add_input_option(':option=value');" />
+    <div id="input_options_list"></div>
+    </div>
+    <?vlc if current_page == "vlm" then ?>
       <input type="button" value="Ok" onclick="vlm_input_change();" />
       <input type="button" value="Cancel" onclick="hide('input');" />
       <input type="hidden" id="input_dest" value="" />
     <?vlc else ?>
-      <input type="text" name="input_mrl" id="input_mrl" size="60" onkeypress="if( event.keyCode == 13 ) in_play();"/>
       <input type="button" value="Play" onclick="in_play();" />
       <input type="button" value="Enqueue" onclick="in_enqueue();" />
     <?vlc end ?>
index d8a64d5..0760f04 100644 (file)
@@ -33,15 +33,15 @@ Note that the sout chain is used and sent to VLC by the input dialog
     <img class="close" src="images/white_cross_small.png" alt="Close" onclick="hide('sout');"/>
   </div>
   <div class="controls">
-    <label for="sout_mrl">Destination (MRL)</label>
+    <label for="sout_mrl">Destination</label>
     <?vlc if current_page == "vlm" then ?>
-      <input type="text" name="sout_mrl" id="sout_mrl" size="60" onkeypress="if( event.keyCode == 13 ) vlm_output_change();"/>
+      <input type="text" name="sout_mrl" id="sout_mrl" size="60" onkeypress="if( event.keyCode == 13 ) vlm_output_change();" disabled="disabled" />
       <br/>
       <input type="button" value="Ok" onclick="vlm_output_change();" />
       <input type="button" value="Cancel" onclick="hide('sout');" />
       <input type="hidden" id="sout_dest" />
     <?vlc else ?>
-      <input type="text" name="sout_mrl" id="sout_mrl" size="60" onkeypress="if( event.keyCode == 13 ) save_sout();" />
+      <input type="text" name="sout_mrl" id="sout_mrl" size="60" onkeypress="if( event.keyCode == 13 ) save_sout();" disabled="disabled" />
       <br/>
       <input type="button" value="Save" onclick="save_sout();" />
     <?vlc end ?>
index a12ac69..7f0ad77 100644 (file)
@@ -1,48 +1,48 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
-\r
-<html xmlns="http://www.w3.org/1999/xhtml">\r
-\r
-<head>\r
-  <title>VLC media player - Web Interface with Flash Viewer</title>\r
-  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r
-  <link href="style.css" rel="stylesheet" type="text/css" />\r
-  <!--[if IE ]>\r
-  <link href="iehacks.css" rel="stylesheet" type="text/css" />\r
-  <![endif]-->\r
-  <script type="text/javascript" src="js/functions.js"></script>\r
-<script type="text/javascript">\r
-// <![CDATA[\r
-host = document.location.toString().replace( /http:\/\//, '' ).replace( /[:/].*/, '' );\r
-// ]]>\r
-</script>\r
-</head>\r
-\r
-<body onload="hide('playlist');">\r
-<?vlc\r
-current_page = "index"\r
-dialogs("browse","main","input","playlist") ?>\r
-\r
-  <input id="sout_mrl" type="hidden" value=":sout=#transcode{vcodec=FLV1,acodec=mp3,channels=2,samplerate=44100}:std{access=http,mux=ffmpeg{mux=flv},dst=0.0.0.0:8081/stream.flv} :no-sout-keep" />\r
-\r
-  <div style='height: 100%; width: 100%; text-align: center;'>\r
-  <object type="application/x-shockwave-flash" data="http://flowplayer.sourceforge.net/video/FlowPlayer.swf" width="800px" height="600px" id="FlowPlayer" style="z-index: 0">\r
-         <param name="allowScriptAccess" value="sameDomain" />\r
-         <param name="movie" value="http://flowplayer.sourceforge.net/video/FlowPlayer.swf" />\r
-         <param name="quality" value="high" />\r
-    <!--         <param name="scale" value="noScale" />-->\r
-         <param name="wmode" value="transparent" />\r
-       <!--  <param name="flashvars" value="config={ loop: false, initialScale: \'fit\', autoPlay: false, configInject: true}" />-->\r
-  <script type="text/javascript">\r
-// <![CDATA[\r
-  document.write( '' +\r
-'        <param name="flashvars" value="config={ loop: false, initialScale: \'fit\', autoPlay: false, playList: [{ url: \'http://' + host + ':8081/stream.flv\', controlEnabled: true}] }" />' );\r
-// ]]>\r
-</script>\r
-  </object>\r
-  <p style="font-size: small;">Uses the <a href="http://flowplayer.sourceforge.net/">Flow Player</a> free flash video player for playback (client side).</p>\r
-  </div>\r
-\r
-<?vlc dialogs("footer") ?>\r
-</body>\r
-\r
-</html>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+  <title>VLC media player - Web Interface with Flash Viewer</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  <link href="style.css" rel="stylesheet" type="text/css" />
+  <!--[if IE ]>
+  <link href="iehacks.css" rel="stylesheet" type="text/css" />
+  <![endif]-->
+  <script type="text/javascript" src="js/functions.js"></script>
+<script type="text/javascript">
+// <![CDATA[
+host = document.location.toString().replace( /http:\/\//, '' ).replace( /[:/].*/, '' );
+input_options.push( ":sout=#transcode{vcodec=FLV1,acodec=mp3,channels=2,samplerate=44100}:std{access=http,mux=ffmpeg{mux=flv},dst=0.0.0.0:8081/stream.flv}" );
+input_options.push( ":no-sout-keep" );
+// ]]>
+</script>
+</head>
+
+<body onload="hide('playlist'); refresh_input_options_list();">
+<?vlc
+current_page = "index"
+dialogs("browse","main","input","playlist") ?>
+
+  <div style='height: 100%; width: 100%; text-align: center;'>
+  <object type="application/x-shockwave-flash" data="http://flowplayer.sourceforge.net/video/FlowPlayer.swf" width="800px" height="600px" id="FlowPlayer" style="z-index: 0">
+         <param name="allowScriptAccess" value="sameDomain" />
+         <param name="movie" value="http://flowplayer.sourceforge.net/video/FlowPlayer.swf" />
+         <param name="quality" value="high" />
+    <!--         <param name="scale" value="noScale" />-->
+         <param name="wmode" value="transparent" />
+       <!--  <param name="flashvars" value="config={ loop: false, initialScale: \'fit\', autoPlay: false, configInject: true}" />-->
+  <script type="text/javascript">
+// <![CDATA[
+  document.write( '' +
+'        <param name="flashvars" value="config={ loop: false, initialScale: \'fit\', autoPlay: false, playList: [{ url: \'http://' + host + ':8081/stream.flv\', controlEnabled: true}] }" />' );
+// ]]>
+</script>
+  </object>
+  <p style="font-size: small;">Uses the <a href="http://flowplayer.sourceforge.net/">Flow Player</a> free flash video player for playback (client side).</p>
+  </div>
+
+<?vlc dialogs("footer") ?>
+</body>
+
+</html>
index d9e5e5b..7153abf 100644 (file)
@@ -36,6 +36,8 @@ var albumart_id = -1;
 var slider_mouse_down = 0;
 var slider_dx = 0;
 
+var input_options = new Array();
+
 /* findPosX() from http://www.quirksmode.rg/js/indpos.html */
 function findPosX(obj)
 {
@@ -283,23 +285,25 @@ function clear_children( elt )
  * Interface actions
  *********************************************************************/
 /* input actions */
-function in_play()
+function in_playenqueue( cmd )
 {
     var input = value('input_mrl');
-    if( value('sout_mrl') != '' )
-        input += ' '+value('sout_mrl');
-    var url = 'requests/status.xml?command=in_play&input='+encodeURIComponent( addslashes(escapebackslashes(input)) );
+    var url = 'requests/status.xml?command=in_'+cmd+'&input='+encodeURIComponent( addslashes(escapebackslashes(input)) );
+    for( i in input_options )
+        if( input_options[i] != ':option=value' )
+            url += '&option='+encodeURIComponent( addslashes(escapebackslashes(input_options[i]) ));
     loadXMLDoc( url, parse_status );
     setTimeout( 'update_playlist()', 1000 );
 }
+
+function in_play()
+{
+    in_playenqueue( 'play' );
+}
+
 function in_enqueue()
 {
-    var input = value('input_mrl');
-    if( value('sout_mrl') != '' )
-        input += ' '+value('sout_mrl');
-    var url = 'requests/status.xml?command=in_enqueue&input='+encodeURIComponent( addslashes(escapebackslashes(input)) );
-    loadXMLDoc( url, parse_status );
-    setTimeout( 'update_playlist()', 1000 );
+    in_playenqueue( 'enqueue' );
 }
 
 /* playlist actions */
@@ -771,12 +775,15 @@ function update_input_disc()
             mrl.value += ":"+chapter;
     }
 
+    remove_input_options( ':sub-track' );
+    remove_input_options( ':audio-track' );
+
     if( type != "cdda" )
     {
         if( subs != '' )
-            mrl.value += " :sub-track="+subs;
+            add_input_option( ":sub-track="+subs );
         if( audio != '' )
-            mrl.value += " :audio-track="+audio;
+            add_input_option( ":audio-track="+audio );
     }
 
 }
@@ -825,24 +832,27 @@ function update_input_net()
         mrl.value += url;
     }
 
+    remove_input_options( ':access-filter' );
     if( checked( "input_net_timeshift" ) )
-        mrl.value += " :access-filter=timeshift";
+        add_input_option( ":access-filter=timeshift" );
 }
 
 /* update the input MRL using data from the input fake helper */
 function update_input_fake()
 {
+    remove_input_options( ":fake" );
     var mrl = document.getElementById( 'input_mrl' );
 
     mrl.value = "fake:";
-    mrl.value += " :fake-file=" + value( "input_fake_filename" );
+
+    add_input_option( ":fake-file=" + value( "input_fake_filename" ) );
 
     if( value( "input_fake_width" ) )
-        mrl.value += " :fake-width=" + value( "input_fake_width" );
+        add_input_option( ":fake-width=" + value( "input_fake_width" ) );
     if( value( "input_fake_height" ) )
-        mrl.value += " :fake-height=" + value( "input_fake_height" );
+        add_input_option( ":fake-height=" + value( "input_fake_height" ) );
     if( value( "input_fake_ar" ) )
-        mrl.value += " :fake-ar=" + value( "input_fake_ar" );
+        add_input_option( ":fake-ar=" + value( "input_fake_ar" ) );
 }
 
 /**********************************************************************
@@ -867,8 +877,10 @@ function toggle_show_sout_helper()
 /* update the sout MRL using data from the sout_helper */
 function update_sout()
 {
-    var mrl = document.getElementById( 'sout_mrl' );
-    mrl.value = "";
+    var option = "";
+    /* Remove all options starting with :sout since we're going to write them
+     * again. */
+    remove_input_options( ":sout" );
 
     check_and_replace_int( 'sout_http_port', 8080 );
     check_and_replace_int( 'sout_mmsh_port', 8080 );
@@ -892,36 +904,37 @@ function update_sout()
 
     if( transcode )
     {
-        mrl.value += ":sout=#transcode{";
+        option = ":sout=#transcode{";
         var alot = false; /* alot == at least one transcode */
         if( checked( 'sout_vcodec_s' ) )
         {
-            mrl.value += "vcodec="+value( 'sout_vcodec' )+",vb="+value( 'sout_vb' )+",scale="+value( 'sout_scale' );
+            option += "vcodec="+value( 'sout_vcodec' )+",vb="+value( 'sout_vb' )+",scale="+value( 'sout_scale' );
             alot = true;
         }
         if( checked( 'sout_acodec_s' ) )
         {
-            if( alot ) mrl.value += ",";
-            mrl.value += "acodec="+value( 'sout_acodec' )+",ab="+value( 'sout_ab' );
+            if( alot ) option += ",";
+            option += "acodec="+value( 'sout_acodec' )+",ab="+value( 'sout_ab' );
             if( value( 'sout_channels' ) )
-                mrl.value += ",channels="+value( 'sout_channels' );
+                option += ",channels="+value( 'sout_channels' );
             alot = true;
         }
         if( checked( 'sout_soverlay' ) )
         {
-            if( alot ) mrl.value += ",";
-            mrl.value += "soverlay";
+            if( alot ) option += ",";
+            option += "soverlay";
             alot = true;
         }
         else if( checked( 'sout_sub' ) )
         {
-            if( alot ) mrl.value += ",";
-            mrl.value += "scodec="+value( 'sout_scodec' );
+            if( alot ) option += ",";
+            option += "scodec="+value( 'sout_scodec' );
             alot = true;
         }
-        mrl.value += value( 'sout_transcode_extra' );
+        option += value( 'sout_transcode_extra' );
             
-        mrl.value += "}";
+        option += "}";
+
     }
 
     var output = checked( 'sout_display' ) + checked( 'sout_file' )
@@ -931,93 +944,101 @@ function update_sout()
     if( output )
     {
         if( transcode )
-            mrl.value += ":";
+            option += ":";
         else
-            mrl.value += ":sout=#";
+            option += ":sout=#";
         var aloo = false; /* aloo == at least one output */
         var mux = radio_value( 'sout_mux' );
         var ttl = parseInt( value( 'sout_ttl' ) );
-        if( output > 1 ) mrl.value += "duplicate{";
+        if( output > 1 ) option += "duplicate{";
         if( checked( 'sout_display' ) )
         {
-            if( output > 1 ) mrl.value += "dst="
-            mrl.value += "display";
+            if( output > 1 ) option += "dst="
+            option += "display";
             aloo = true;
         }
         if( checked( 'sout_file' ) )
         {
-            if( aloo ) mrl.value += ",";
-            if( output > 1 ) mrl.value += "dst="
-            mrl.value += "std{access=file,mux="+mux+",dst="+value( 'sout_file_filename' )+"}";
+            if( aloo ) option += ",";
+            if( output > 1 ) option += "dst="
+            option += "std{access=file,mux="+mux+",dst="+value( 'sout_file_filename' )+"}";
             aloo = true;
         }
         if( checked( 'sout_http' ) )
         {
-            if( aloo ) mrl.value += ",";
-            if( output > 1 ) mrl.value += "dst="
-            mrl.value += "std{access=http,mux="+mux+",dst="+value( 'sout_http_addr' );
+            if( aloo ) option += ",";
+            if( output > 1 ) option += "dst="
+            option += "std{access=http,mux="+mux+",dst="+value( 'sout_http_addr' );
             if( value( 'sout_http_port' ) )
-                mrl.value += ":"+value( 'sout_http_port' );
-            mrl.value += "}";
+                option += ":"+value( 'sout_http_port' );
+            option += "}";
             aloo = true;
         }
         if( checked( 'sout_mmsh' ) )
         {
-            if( aloo ) mrl.value += ",";
-            if( output > 1 ) mrl.value += "dst="
-            mrl.value += "std{access=mmsh,mux="+mux+",dst="+value( 'sout_mmsh_addr' );
+            if( aloo ) option += ",";
+            if( output > 1 ) option += "dst="
+            option += "std{access=mmsh,mux="+mux+",dst="+value( 'sout_mmsh_addr' );
             if( value( 'sout_mmsh_port' ) )
-                mrl.value += ":"+value( 'sout_mmsh_port' );
-            mrl.value += "}";
+                option += ":"+value( 'sout_mmsh_port' );
+            option += "}";
             aloo = true;
         }
         if( checked( 'sout_rtp' ) )
         {
-            if( aloo ) mrl.value += ",";
-            if( output > 1 ) mrl.value += "dst="
-            mrl.value += "std{access=rtp";
-            if( ttl ) mrl.value += "{ttl="+ttl+"}";
-            mrl.value += ",mux="+mux+",dst="+value( 'sout_rtp_addr' );
+            if( aloo ) option += ",";
+            if( output > 1 ) option += "dst="
+            option += "std{access=rtp";
+            if( ttl ) option += "{ttl="+ttl+"}";
+            option += ",mux="+mux+",dst="+value( 'sout_rtp_addr' );
             if( value( 'sout_rtp_port' ) )
-                mrl.value += ":"+value( 'sout_rtp_port' );
+                option += ":"+value( 'sout_rtp_port' );
             if( checked( 'sout_sap' ) )
             {
-                mrl.value += ",sap";
+                option += ",sap";
                 if( value( 'sout_sap_group' ) != '' )
                 {
-                    mrl.value += ",group=\""+value( 'sout_sap_group' )+"\"";
+                    option += ",group=\""+value( 'sout_sap_group' )+"\"";
                 }
-                mrl.value += ",name=\""+value( 'sout_sap_name' )+"\"";
+                option += ",name=\""+value( 'sout_sap_name' )+"\"";
             }
-            mrl.value += "}";
+            option += "}";
             aloo = true;
         }
         if( checked( 'sout_udp' ) )
         {
-            if( aloo ) mrl.value += ",";
-            if( output > 1 ) mrl.value += "dst="
-            mrl.value += "std{access=udp";
-            if( ttl ) mrl.value += "{ttl="+ttl+"}";
-            mrl.value += ",mux="+mux+",dst="+value( 'sout_udp_addr' );
+            if( aloo ) option += ",";
+            if( output > 1 ) option += "dst="
+            option += "std{access=udp";
+            if( ttl ) option += "{ttl="+ttl+"}";
+            option += ",mux="+mux+",dst="+value( 'sout_udp_addr' );
             if( value('sout_udp_port' ) )
-                mrl.value += ":"+value( 'sout_udp_port' );
+                option += ":"+value( 'sout_udp_port' );
             if( checked( 'sout_sap' ) )
             {
-                mrl.value += ",sap";
+                option += ",sap";
                 if( value( 'sout_sap_group' ) != '' )
                 {
-                    mrl.value += ",group=\""+value( 'sout_sap_group' )+"\"";
+                    option += ",group=\""+value( 'sout_sap_group' )+"\"";
                 }
-                mrl.value += ",name=\""+value( 'sout_sap_name' )+"\"";
+                option += ",name=\""+value( 'sout_sap_name' )+"\"";
             }
-            mrl.value += "}";
+            option += "}";
             aloo = true;
         }
-        if( output > 1 ) mrl.value += "}";
+        if( output > 1 ) option += "}";
     }
 
+    if( option != "" )
+        input_options.push( option );
+
     if( ( transcode || output ) && checked( 'sout_all' ) )
-        mrl.value += " :sout-all";
+        input_options.push( ":sout-all" );
+
+    /*var mrl = document.getElementById( 'sout_mrl' );
+    mrl.value = input_options.join( " " )*/
+
+    refresh_input_options_list();
 }
 
 /* reset sout mrl value */
@@ -1032,6 +1053,63 @@ function save_sout()
     document.getElementById('sout_old_mrl').value = value('sout_mrl');
 }
 
+function refresh_input_options_list()
+{
+    var iol = document.getElementById( 'input_options_list' );
+    clear_children( iol );
+    input_options.sort();
+    for( i in input_options )
+    {
+        var o = document.createElement( 'div' );
+        var ot = document.createElement( 'input' );
+        ot.setAttribute( 'type', 'text' );
+        ot.setAttribute( 'size', '60' );
+        ot.setAttribute( 'value', input_options[i] );
+        ot.setAttribute( 'id', 'input_option_item_'+i );
+        ot.setAttribute( 'onchange', 'javascript:save_input_option('+i+',this.value);' );
+        ot.setAttribute( 'onfocus', 'if( this.value == ":option=value" ) this.value = ":";' );
+        ot.setAttribute( 'onblur', 'if( this.value == ":" ) this.value = ":option=value";' );
+        o.appendChild( ot );
+        var od = document.createElement( 'a' );
+        od.setAttribute( 'href', 'javascript:delete_input_option('+i+');' );
+        var delimg = document.createElement( "img" );
+        delimg.setAttribute( 'src', 'images/delete_small.png' );
+        delimg.setAttribute( 'alt', '(delete)' );
+        od.appendChild( delimg );
+        o.appendChild( od );
+        iol.appendChild( o );
+    }
+}
+
+function delete_input_option( i )
+{
+    input_options.splice(i,1);
+    refresh_input_options_list();
+}
+
+function save_input_option( i, value )
+{
+    input_options[i] = value;
+    refresh_input_options_list();
+}
+
+function add_input_option( value )
+{
+    input_options.push( value );
+    refresh_input_options_list();
+}
+
+function remove_input_options( prefix )
+{
+    for( i in input_options )
+        if( input_options[i].substring( 0, prefix.length ) == prefix )
+        {
+            delete input_options[i];
+            i--;
+        }
+}
+
+
 /**********************************************************************
  * Browser dialog functions
  *********************************************************************/
index 0e4b827..0b41fa0 100644 (file)
@@ -30,8 +30,12 @@ local input = _GET['input']
 local command = _GET['command']
 local id = tonumber(_GET['id'] or -1)
 local val = _GET['val']
+local options = _GET['option']
+if type(options) ~= "table" then -- Deal with the 0 or 1 option case
+  options = { options }
+end
 
---vlc.msg.err("requests/status.xml got:","input: "..tostring(input),"command: "..tostring(command),"id: "..tostring(id),"val: "..tostring(val))
+---[[]] vlc.msg.err("requests/status.xml got:","input: "..tostring(input),"command: "..tostring(command),"id: "..tostring(id),"val: "..tostring(val))
 
 local function stripslashes(s)
   return string.gsub(s,"\\(%.)","%1")
@@ -40,13 +44,16 @@ end
 local status = vlc.playlist.status()
 
 if command == "in_play" then
-  local options = {}
-  for o in string.gmatch(input," :[^ ]*") do -- FIXME: options should be in seperate variables, not in the same string as the input.
-    table.insert(options,string.sub(o,3))
+  ---[[
+  vlc.msg.err( "<options>" )
+  for a,b in ipairs(options) do
+    vlc.msg.err(b)
   end
+  vlc.msg.err( "</options>" )
+  --]]
   vlc.playlist.add({{path=stripslashes(input),options=options}})
 elseif command == "in_enqueue" then
-  vlc.playlist.enqueue(stripslashes(input))
+  vlc.playlist.enqueue({{path=stripslashes(input),options=options}})
 elseif command == "pl_play" then
   vlc.playlist.goto(id)
 elseif command == "pl_pause" then
index 2c2cd1b..0f60941 100644 (file)
@@ -35,7 +35,7 @@ require "httpd"
 require "acl"
 require "common"
 
-vlc.msg.err("Lua HTTP interface")
+vlc.msg.info("Lua HTTP interface")
 
 open_tag = "<?vlc"
 close_tag = "?>"
@@ -175,7 +175,19 @@ function parse_url_request(request)
     for k,v in string.gmatch(request,"([^=&]+)=?([^=&]*)") do
         local k_ = vlc.decode_uri(k)
         local v_ = vlc.decode_uri(v)
-        t[k_]=v_
+        if t[k_] ~= nil then
+            local t2
+            if type(t[k_]) ~= "table" then
+                t2 = {}
+                table.insert(t2,t[k_])
+                t[k_] = t2
+            else
+                t2 = t[k_]
+            end
+            table.insert(t2,v_)
+        else
+            t[k_] = v_
+        end
     end
     return t
 end