$M={};
$M.debug=2;//1粗略,2详细,其他保存到debug_info
$M.debug_len=100;
$M.debug_info=[];
$M.online=false;//这个不用管，打包的时候会自动改
$M.compile=new Map();
$M.global={}
$M.global.$load;//加载动画
$M.global.$loadTime=300;//多久后可以加载动画,毫秒
$M.global.$workerUrl;//线程url地址

$M.global.$userClick={}
$M.global.$userClick.event;//用户点击事件
$M.global.$userClick.tag;//用户点击事件是否已执行标志
$M.global.$userClick.list=[];//用户点击事件,等待列表,执行一次
$M.global.$userClick.listEvery=[];//用户点击事件,等待列表,每触发一次都会执行



$M.userClick=function(id,onece)
{
	let curClick=$M.global.$userClick

	let dom=window
	if(id)dom=$M.find(id)
	if(!dom)
	{
		$M.info('【监听点击】未发现元素')
		return
	}
	let make=(list)=>
	{
		for (const iterator of list) 
		{
			try 
			{
				iterator(event)
			} 
			catch (error) 
			{
				$M.info('【监听点击】执行错误',error)
			}
		}
	}

	let back
	back=(event)=>
	{
		curClick.event=event
		if(onece)dom.removeEventListener('click',back)

		make(curClick.list)
		make(curClick.listEvery)
		curClick.list=[]

	}

	if(!curClick.tag)dom.addEventListener
	(
		'click',back
	)
	curClick.tag=true

	let one=(fun)=>
	{
		if(curClick.tag.event)fun(curClick.tag.event)
		else curClick.list.push(fun)
		
	}
	let every=(fun)=>
	{
		if(curClick.tag.event)fun(curClick.tag.event)
		curClick.listEvery.push(fun)
	}
	let ignore=(fun)=>{if(curClick.tag.event)fun(curClick.tag.event)}
	return {one,every,ignore}
}

$M.autoChange=function(target,config,fun)
{
	// Firefox和Chrome早期版本中带有前缀
	var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver

	if(MutationObserver)
	{
		// 创建观察者对象
		var observer = new MutationObserver
		(
			function(mutations) 
			{  
				mutations.forEach
				(
					function(mutation) 
					{ 
						fun && fun(mutation,true); 
					}
				); 
			}
		); 
	}
	else
	{
		target.addEventListener
		( 
			config.replace,function(event)
			{
				fun && fun(event,false); 
			}
		)
	}

	// 传入目标节点和观察选项
	observer.observe(target, config); 

	return {stop:observer.disconnect}
}

$M.autoGc=function()
{
	function make(dom)
	{
		var index;
		if(!dom.tagName)return'';
		try 
		{
			function gc(dom)
			{
				if(dom._setinterval)
				{
					for (index = 0; index <dom._setinterval.length; index++) 
					{
						clearInterval(dom._setinterval[index])
					}
				}
				if(dom._settimeout)
				{
					for (index = 0; index <dom._settimeout.length; index++) 
					{
						clearTimeout(dom._settimeout[index])
					}
				}
				if(dom.unRely)
				{
					dom.unRely()
				}
				if(dom.un)
				{
					dom.un()
				}
			}
			gc(dom);
			let list=dom.querySelectorAll('[_settimeout],[_setinterval],[_unRely],[_un]');
			for (let index = 0; index < list.length; index++) 
			{
				gc(list[index]);
			}
		} 
		catch (error) 
		{
			$M.info('自动回收内存时发生错误',error)
		}
	}

	$M.autoChange
	(
		document.body,{childList:true,subtree:true,replace:'DOMNodeRemoved'},function(mutation,tag)
		{
			if(tag)
			{
				if(!mutation.removedNodes.length)return
				for (let index = 0; index < mutation.removedNodes.length; index++) 
				{
					make(mutation.removedNodes[index])
				}
			}
			else
			{
				make(mutation.target)
			}
		}
	)
}

$M.scroll=function()
{
	onscroll=function(ev)
	{
		$M.dispatch('body','scroll',{top:ev.scrollTop,left:ev.scrollLeft});
	}
}


$M.info=function(mes,error)
{
	let stack=''
	try
	{
		throw(new Error("调用栈:"));
	}
	catch(e)
	{
		stack=e.stack.replace('Error: ','');
		stack=stack.replace(/(\s*?)(\S.*?[\n|$|\s])/g,'$2');
		stack=stack.replace(/at\sConsole.console.log.*?[\n|$]/g,'')
	}
	if($M.debug==2)
	{
		console.log((new Date()).toLocaleTimeString(),mes,error?error:'')
	}
	else if($M.debug==1)
	{
		console.log((new Date()).toLocaleTimeString(),mes)
	}
	else
	{
		if($M.debug_info.length>$M.debug_len)$M.debug_info.shift();
		$M.debug_info.push({date:(new Date()).toString(),message:mes,error:error?error:''})
	}
}

$M.error=function(tag,tagOnline)
{
	//监听js错误
	window.onerror = function(message, source, lineno, colno, error) 
	{
		$M.info('[未捕捉错误]',[message, source, lineno, colno, error])
	} 

	if((tagOnline || !$M.online) && tag)
	{
		if($M.isPc())return
		var script=document.createElement('script')
		script.setAttribute('defer','true')
		script.setAttribute('onload',"new VConsole()")
		script.src='https://res.wx.qq.com/mmbizwap/zh_CN/htmledition/js/vconsole/3.0.0/vconsole.min.js';
		document.head.insertBefore(script,tag.nextElementSibling);
	}	
} 

$M.next=function (arr)
{
	var global={};
	if(!arr || arr.length<=0)return;
	function fire()
	{
		if(arr.length<=0)return;
		var _fun=arr.shift();
		if(typeof _fun == 'function')
		{
			_fun(fire,global);
		}
		else
		{
			$M.info('is not function',_fun)
		}
	}
	fire()
}

$M.href=function(url)
{
	alert('跳转到'+url);
}

$M.randRom=function(lowerValue,upperValue)
{
	return Math.floor(Math.random() * (upperValue - lowerValue + 1) + lowerValue);
}

$M.HTMLEncode=function(str) 
{
	if(!str || !str.length || (typeof str != 'string')) return "";
	str = str.replace(/&/g,"&amp;");
	str = str.replace(/</g,"&lt;");
	str = str.replace(/>/g,"&gt;");
	str = str.replace(/ /g,"&nbsp;");
	str = str.replace(/\'/g,"&#39;");
	str = str.replace(/\"/g,"&quot;");
	return str;  
}

$M.HTMLDecode =function(str)
{ 
	if(!str || !str.length || (typeof str != 'string')) return "";
	str = str.replace(/&amp;/g,"&");
	str = str.replace(/&lt;/g,"<");
	str = str.replace(/&gt;/g,">");
	str = str.replace(/&nbsp;/g," ");
	str = str.replace(/&#39;/g,"\'");
	str = str.replace(/&quot;/g,"\"");
	return str;  
} 

$M.insert=function(curdom,d,tag)
{
	curdom=$M.find(curdom);
	if(!curdom)
	{
		$M.info('未找到元素',curdom);
		return '';
	};
	requestAnimationFrame
	(
		function()
		{
			if(tag)
			{
				curdom.outerHTML=d;
			}
			else
			{
				curdom.innerHTML=d;
			}
		}
	)
}

$M.rem=function(correctly,target)
{
	if($M.isPc())return;
	//correctly设计图总尺寸
	//target，在设计图总尺寸时，1rem等于多少像素（1rem等于浏览器根字体大小）

	var docEl = document.documentElement,
	resizeEvt = ('orientationchange' in window)?'orientationchange':'resize',
	recalc = function () 
	{
		var clientWidth = docEl.clientWidth;
		if (clientWidth === undefined) return;
		docEl.style.fontSize = target * (clientWidth/correctly) + 'px';
	};

	if('number' != (typeof correctly))
	{
		correctly=750;
	}
	if('number' != (typeof target))
	{
		target=16*(correctly/docEl.clientWidth);
	}
	
	recalc();

	window.addEventListener(resizeEvt, recalc, false);
	document.addEventListener('DOMContentLoaded', recalc, false);
}


$M.setTimeout=function(doma,fun,time,arg)
{
	dom=$M.find(doma);
	if(!dom)
	{
		$M.info('未找到元素',doma);
		return '';
	};
	if(fun && time)
	{
		dom._settimeout=dom._settimeout?dom._settimeout:[];
		dom._settimeout.push(setTimeout(fun,time,arg));
		dom.setAttribute('_settimeout','true');
	}
	else
	{
		$M.info('绑定超时参数不完整',[fun,time])
	}
}

$M.setInterval=function(doma,fun,time,arg)
{
	var dom=$M.find(doma);
	if(!dom)
	{
		$M.info('未找到元素',doma);
		return '';
	};
	if(fun && time)
	{
		dom._setinterval=dom._setinterval?dom._setinterval:[];
		dom._setinterval.push(setInterval(fun,time,arg));
		dom.setAttribute('_setinterval','true');
	}
	else
	{
		$M.info('绑定时钟参数不完整',[fun,time])
	}
}
$M.deepCopy=function(source,target={}) 
{
	for (var prop in source) 
	{
		if (typeof source[prop] === 'object') 
		{
			target[prop] = (source[prop].constructor === Array) ? [] : {};
			$M.deepCopy(source[prop],target[prop]);
		} 
		else 
		{
			target[prop] = source[prop];
		}
	}
	return target; 
  }
$M.dispatch=function(id,evn,obj)
{
	if(!evn) return;
	if((typeof obj)!='object')obj={};
	var myEvent = new CustomEvent
	(
		evn, 
		{
			detail:obj,
			bubbles: false,
			cancelable: false
		}
	);
	var _dom=$M.find(id);
	if(!_dom)
	{
		$M.info('[事件派发]未找到元素',id);
		return '';
	};
	_dom.dispatchEvent(myEvent);
}

$M.so=function(id)
{
	var dom=$M.find(id);
	if(dom && dom.selectedIndex==-1)
	{
		return '';
	}
	return dom.querySelectorAll('option')[dom.selectedIndex]
}

$M.stop=function(event)
{
	//js阻止事件冒泡
	event.cancelBubble = true;
	if(event.stopPropagation)
	{
		event.stopPropagation();
	}
	//js阻止链接默认行为，没有停止冒泡
	if(event.preventDefault)
	{
		event.preventDefault(); 
	}
}

$M.param=function(str)
{
	function parse(items)
	{
		items = items.split('&'); 
		var resultObj = {}; 
		for(var index = 0 ; index < items.length ; index++ )
		{ 
			if(! items[index])
			{ 
				continue; 
			} 
			var kv = items[index].split('='); 
			resultObj[decodeURIComponent(kv[0])] = typeof kv[1] === "undefined" ? "":decodeURIComponent(kv[1]); 
		} 
		return resultObj; 
	}
	try 
	{
		var search = window.location.search; 
		if(typeof str == 'string')
		{
			return parse(str); 
		}
		else if(search)
		{ 
			var search = search.substring(1); 
			return parse(search); 
		} 
		else
		{
			return {};
		}		
	} 
	catch (error) 
	{
		return {};
	}
}

$M.unParam=function(data)
{
	var str="";
	if(data instanceof Object)
	{
		for (var key in data) 
		{ 
			
			str+=encodeURIComponent(key)+'='+encodeURIComponent((data[key] instanceof Object)?JSON.stringify(data[key]):data[key])+'&';
		}
		if(str)str=str.replace(/&$/,'')
	}
	return str;
}

$M.frame=function()
{
	if (self != top) 
	{
		top.location = self.location;
	}
}

$M.removeChilds=function(elea)
{
	var ele=$M.find(elea);
	if(!ele)
	{
		$M.info('[删除元素子元素]未找到元素',elea);
		return '';
	};
	try 
	{
		var childList=ele.children;
		for(var i=0,len=childList.length;i<len;i++)
		{
			ele.removeChild(childList[i]);
		}
	} 
	catch (error) 
	{
		$M.info('[删除元素子元素]未找到元素',elea);
	}
}




$M.removeChild=function(elea)
{
	var ele=$M.find(elea);
	if(!ele)
	{
		$M.info('未找到元素',elea);
		return '';
	};
	if(elea.remove && elea.remove())return
	try 
	{
		ele.parentNode.removeChild(ele);	
	} 
	catch (error) 
	{
		$M.info('未找到元素',elea);
	}
}

$M.sleep=function(dom,time)
{
	if(typeof dom == 'number')
	{
		time=dom
		dom=undefined
	}
	let tr=new Promise
	(
		(reslove,reject)=>
		{
			if(dom)
			{
				$M.setTimeout
				(
					dom,
					function()
					{
						reslove(true);
					},time
				)
			}
			else
			{
				setTimeout
				(
					function()
					{
						reslove(true);
					},time
				).unref();
			}
		}
	);
	return tr;
}

$M.race=function(pro,time=3000,tag='')
{
	if(!Number.isInteger(time))
	{
		time=3000;
		tag=time;
	}
	return Promise.race
	(
		[
			pro,
			new Promise
			(
				function(reslove,reject)
				{
					setTimeout
					(
						() => 
						{
							reject(`${tag?tag:'任务'}超时：${time}ms`);
						}, time
					);
				}
			)
		]
	)
}

$M.worker=async function(obj,ti=10000,rej)
{ 
    var data=`onmessage=async function(event)
    {
        try 
        {
            var $Worker=event.data;
            if($Worker.script)
            {
				if(Array.isArray($Worker.script))
				{
					for (const iterator of $Worker.script) 
					{
						importScripts(iterator)
					}
				}
				else
				{
					importScripts($Worker.script)
				}
            }
            let data=await (new Function('$post',$Worker.code))(postMessage)
            if(data !== undefined)postMessage({code:1,data:data});
        } 
        catch (error) 
        {
            postMessage({code:1,data:error.message})
        }
	}`;   
	// $M.worker({code:'return 1'},(result)=>{
	// 	console.print(JSON.stringify(result))
	// })
    var blob=new Blob([data]);  
    let url=window.URL.createObjectURL(blob);
    $M.global.$workerUrl=url

    var w=new Worker(url)


    let make=(w,res,rej)=>
    {
        w.onmessage=function(event)
        {
            if(res)res(event.data)
        };
        w.onerror=function(error)
        {
            if(rej)rej({code:1,data:error})
        }
        w.postMessage(obj);
    }

    try 
    {
        if(ti instanceof Function)
        {
            make(w,ti,rej)
            return w
        }
        return await $M.race
        (
            new Promise
            (
                function(reslove,reject)
                {
                    make(w,reslove,reject)
                }
            ),ti
        )
    } 
    catch (error) 
    {
        $M.info('【worker出错】',error)
        return {code:1,data:error}
    }
    finally
    {
        if(!(ti instanceof Function))w.terminate();
        window.URL.revokeObjectURL(url);
    }
}   




$M.isDOM=function (params,tr) 
{
	if(params && params.tagName)
	{
		return params.tagName;
	}
	else
	{
		if(tr)
		{
			$M.info('不是一个元素');
		}
	}
}

$M.isIE=function() 
{ 
	if (!!window.ActiveXObject || "ActiveXObject" in window)
	{
		return true;
	}
	else
	{
		return false;
	}
}


$M.isWx=function()
{
	var ua = window.navigator.userAgent.toLowerCase();
	if(ua.match(/MicroMessenger/i) == 'micromessenger')
	{
		return true;
	}
	else
	{
		return false;
	}
}

$M.isPc=function()
{
	var userAgentInfo=navigator.userAgent;   
	var Agents =["Android","iPhone","Windows Phone","iPad","iPod"];   
	var flag=true;   
	for(var v=0;v<Agents.length;v++) 
	{   
	   if(userAgentInfo.indexOf(Agents[v])>0) 
	   {   
		 flag=false;   
		 break;   
	   }   
	}   
	return flag;   
}

$M.isTouch=function()
{
	return "ontouchend" in document ? true : false;
}

$M.style=function(thata)
{
	//返回css样式
	var that=$M.find(thata);
	if(!that)
	{
		$M.info('[元素样式]未找到元素',thata);
		return '';
	};
	return that.currentStyle?that.currentStyle:window.getComputedStyle(that, null);
}


$M.fade=function(id,time=0.9)
{
	var curdom=$M.find(id);
	if(!curdom)
	{
		$M.info('未找到元素',id);
		return '';
	};
	var after=curdom.style.opacity?curdom.style.opacity:1
	if(!after || after==0)return
	if(curdom.$_fade)
	{
		clearTimeout(curdom.$_fade)
		curdom.style.transition=curdom.$_faderesCheck
	}
	curdom.style.opacity=0
	setTimeout
	(
		function()
		{
			var resCheck=curdom.style.transition
			var tag
			if(resCheck)
			{
				if(resCheck.indexOf('opacity')==-1)
				{
					curdom.style.transition+=',opacity '+time+'s'
					tag=true
				}
			}
			else
			{
				curdom.style.transition+='opacity '+time+'s'
				tag=true
			}
			curdom.style.opacity=after
			if(tag)
			{
				curdom.$_fade=$M.setTimeout
				(
					curdom,
					function()
					{
						curdom.$_fade=undefined
						curdom.$_faderesCheck=resCheck
						curdom.style.transition=resCheck
					},time*1000
				)
			}
		}
	)
}

$M.show=function(id)
{
	var curdom=$M.find(id);
	if(!curdom)
	{
		$M.info('未找到元素',id);
		return '';
	};

	$M.fade(curdom)
	
	if(curdom.style.display=='none')
	{
		if(curdom.hasAttribute('_style'))
		{
			curdom.style.display=curdom.getAttribute('_style');
		}
		else
		{
			curdom.setAttribute('_style','block');
			curdom.style.display='block';
		}
	}
}

$M.hide=function(id)
{
	var curdom=$M.find(id);
	if(!curdom)
	{
		$M.info('[隐藏元素]未找到元素',id);
		return '';
	};
	
	var curCss=$M.style(curdom);
	if(curCss)
	{
		if(curCss.display!='none')
		{
			if(!curdom.hasAttribute('_style'))curdom.setAttribute('_style',curCss.display);
			curdom.style.display='none';
		}
	}
	else
	{
		$M.info('[隐藏元素]不正确：'+curdom)
	}
}


$M.toggle=function(id)
{
	var curdom=$M.find(id);
	if(!curdom)
	{
		$M.info('[隐藏元素]未找到元素',id);
		return '';
	};
	var curCss=$M.style(curdom);
	if(curCss)
	{
		if(curCss.display=='none')
		{
			$M.show(curdom)
			return true
		}
		else
		{
			$M.hide(curdom)
			return false
		}
	}
	else
	{
		$M.info('[隐藏元素]不正确：'+curdom)
	}
}

$M.rand=function()
{
	return (new Date()).getTime().toString().slice(6)+(Math.random().toString().slice(2))
}

$M.randString=function(len,type)
{
	if(!len)return ''
	var str='qwertyuiopasdfghjklzxcvbnm'
	var strint='0123456789'
	var strRand=''
	for (let index = 0; index < len; index++) 
	{
		if(type)strRand+=str[$M.randRom(0,25)]	
		else strRand+=strint[$M.randRom(0,9)]	
	}
	return strRand
}

$M.stopMenu=function()
{
	if(document.oncontextmenu)
	{
		document.oncontextmenu=undefined
		return
	}
    document.oncontextmenu = function() 
    {
        return false;
    }
}

$M.removeComment=function (code)  
{    
	if(!code)return code
	return code
	//.replace(/(?:^|\n|\r|\s)\s*\/\*[\s\S]*?\*\/\s*(?:\r|\s|\n|$)/g, '\r\n')
	.replace(/(?:^|\n|\r|\s)\s*\/\/.*(?:\r|\s|\n|$)/g, '\r\n')
}

$M.aniInit = function () 
{
	
	if(typeof Animation !== 'undefined') return
	$M.include('https://cdn.bootcss.com/web-animations/2.3.1/web-animations-next-lite.min.js')
}

$M.aniPath = function (dom,path) 
{
    dom = $M.find(dom)
    if(!dom)return false
    path=path.replace(/\n/g,' ')
  
    //路径M 5 5 m -4, 0 a 4,4 0 1,0 8,0 a 4,4 0 1,0 -8,0
    //触发{motionOffset:[0,'100%']}
	dom.style['motion-path']="path('"+path+"')"

    // M100,100    ->    以（100，100）坐标点为起点
    // L200,200    ->    从（100，100）向（200，200）画一条直线
    // L200,400    ->    从（200，200）向（200，400）画一条直线
    
    // M = moveto
    // M x y 移动到指定坐标，xy分别为x轴和y轴的坐标点，类似画笔的起点。
    // path中的起点，必须存在（文档中虽然没有提到过，但是path的其他命令都需要依赖一个初始位置，而实际操作过程中也没有需要到可以不使用M的情况，后面发现有例外我再过来补充。
    // L = lineto
    // L x y 在初始位置（M 画的起点）和xy确定的坐标画一条线。
    // 两点一线，直线，绘图中很常见的方式。
    // H = horizontal lineto
    // H x 沿着x轴移动一段位置
    // V = vertical lineto
    // V y 沿着y轴移动一段位置
    // C = curveto
    // C x1 y1 x2 y2 x y
    // 三次贝塞尔曲线
    // 当前点为起点，xy为终点，起点和x1y1控制曲线起始的斜率，终点和x2y2控制结束的斜率。
    // S = smooth curveto
    // S x2 y2 x y
    // 简化的贝塞尔曲线
    // 1.如果S命令跟在一个C命令或者另一个S命令的后面，它的第一个控制点，就会被假设成前一个控制点的对称点。
    // 2.如果S命令单独使用，前面没有C命令或者另一个S命令，那么它的两个控制点就会被假设为同一个点。
    // Q = quadratic Bézier curve
    // Q x1 y1 x y
    // 二次贝塞尔曲线Q
    // 只需要一个控制点，用来确定起点和终点的曲线斜率。因此它需要两组参数，控制点和终点坐标。
    // T = smooth quadratic Bézier curveto
    // Q命令的简写命令。</br>
    // 与S命令相似，T也会通过前一个控制点，推断出一个新的控制点。
    // 1.T命令前面必须是一个Q命令，或者是另一个T命令
    // 2.如果T单独使用，那么控制点就会被认为和终点是同一个点，所以画出来的将是一条直线
    // A = elliptical Arc
    // A rx,ry x-axis-rotation large-arc-flag sweep-flag x,y
    // rx 弧的半长轴长度
    // ry 弧的半短轴长度
    // x-axis-rotation 是此段弧所在的x轴与水平方向的夹角，即x轴的逆时针旋转角度，负数代表顺时针旋转角度。
    // large-arc-flag 为1表示大角度弧线，0表示小角度弧线
    // sweep-flag 为1表示从起点到终点弧线绕中心顺时针方向，0表示逆时针方向。
    // xy 是终点坐标。
    // Z = closepath
    //  从当前位置到起点画一条直线闭合。
}
$M.ani = function (eleAnime,arr,obj={}) 
{
    eleAnime = $M.find(eleAnime)
    var animeKeyframes =arr; 
    var animeOptions = 
    { 
        composite:'add',//动画附加到当前元素，规范默认是replace
        delay: 0, //延迟
        fill: 'none', //forwards代表停留，在动画结束地方。backwards动画开始的地方(默认)
        iterations: 1, //动画播放次数，infinite代表无限
        duration: 1000, //持续时间
        direction: 'normal',//alternate,多次执行时，下一次反向执行动画 
        easing: 'linear' 
        //cubic-bezier(<x1>,<y1>,<x2>,<y2>),控制点在0,1平面坐标范围内
        //linear贝塞尔，cubic-bezier(0,0,1,1) / cubic-bezier(1,1,0,0)
        //ease贝塞尔，cubic-bezier(0.25,0.1,0.25,1)
        //ease-in-out贝塞尔，cubic-bezier(0.5,1,0.5,0)
        //ease-in贝塞尔，即cubic-bezier(0.42,0,1,1)
        //ease-out贝塞尔，即cubic-bezier(0,0,0.58,1)
	}; 

    for (const key in obj) 
    {
        animeOptions[key]=obj[key]
	}
	var animationa
	if(animeOptions.play)
	{
		animationa=eleAnime.animate(animeKeyframes, animeOptions)
	}
	else
	{
		var effect = new KeyframeEffect(eleAnime, animeKeyframes, animeOptions); 
		animationa = new Animation(effect, eleAnime.ownerDocument.timeline);

		
	}
	animationa.dom=eleAnime
    return animationa
}


$M.include=function(url)
{
	return new Promise
	(
		(res,rej)=>
		{
			if($M.find('[src="'+url+'"]'))
			{
				res(true)
				return;
			}
			var dom=document.createElement('script');
			dom.setAttribute('description','来自局部引用，此脚本为全局作用域。');
			dom.src=url;
			dom.onload=function()
			{
				res(true)
			}
			dom.onerror=function()
			{
				res(false)
				$M.removeChild('[src="'+url+'"]');
				$M.info('【js引用】引用失败',url);
			}
			dom.ontimeout=function()
			{
				res(false)
				$M.removeChild('[src="'+url+'"]');
				$M.info('【js引用】引用失败',url);
			}
			$M.find('body').appendChild(dom);
		}
	)

}

$M.eval=async function (d,render,unique) 
{
	render=render||'';
	var du=unique?unique:d;
	try 
	{
		if($M.compile.has(du))
		{
			return $M.compile.get(du)(render);
		}
		else
		{
			var da='async function _exec($Rd){'+d+';};var _str_=_exec($Rd);$M.compile.set($Body,_exec);return _str_;'
			return await (new Function('$Rd','$Body',da))(render,du)
		}	
	} 
	catch (error) 
	{
		$M.info('脚本执行错误：['+d+']',error);
		return error
	}
}

$M.function=function (render,function_body) 
{
	return (new Function('$Rd',function_body))(render)
}

$M.script=function(url,that)
{ 
	$M.get(url,function(d)
	{
		if(d)
		{
			$M.eval(d,that)
		}
		else
		{
			$M.info('获取远程脚本错误：'+url)
		} 
	})  
}

$M.getCookie=function()
{
	try
	{
		var cookie=document.cookie
		cp=cookie.split('; ')
		var ke
		var _val
		var obj={}
		for (ke in cp) 
		{
			_val=cp[ke].split('=')
			obj[_val[0]]=_val[1]
		}
		return obj;		
	}
	catch(e)
	{
		return {};
	}
}

$M.switch=function(eve)
{
	//pc性能比移动端好，所以判断pc时替换。
	if(!$M.isTouch())
	{
		return eve.replace(/^touchstart$/,'mousedown')
				.replace(/^touchmove$/,'mousemove')
				.replace(/^touchend$/,'mouseup')
				.replace(/^touchcancel$/,'mouseleave')
	}
	return eve;
}
$M.unSwitch=function(eve)
{
	//pc性能比移动端好，所以判断pc时替换。
	if(!$M.isTouch())
	{
		return eve.replace(/^mousedown$/,'touchstart')
				.replace(/^mousemove$/,'touchmove')
				.replace(/^mouseup$/,'touchend')
				.replace(/^mouseleave$/,'touchcancel')
	}
	return eve;
}

$M._find=function(eve)
{
	if(eve.on)
	{
		return eve;
	}
	eve._time=0;
	eve._arr_=eve._arr_?eve._arr_:[];

	eve.on=function (even,chi,fun,once)
	{
		//_arr_监听存放数组
		if(!fun)
		{
			fun=fun?fun:chi;
			chi='';
		}
		
		if((typeof fun)!='function') return '';
		//监听事件，真正的回调函数。fun是用户的回调函数
		var _fun_=function(ev)
		{
			//模拟移动端触控
			if(!ev.touches)
			{
				ev.type=$M.unSwitch(ev.type);
				ev.touches=[ev];
				ev.changedTouches=[ev];
			}
			if(even=='tap')
			{
				//判断是否误点
				var _time=new Date();
				_time.getTime();
				if((_time-eve._time)<eve._timeout)
				{
					return false;
				}
				eve._time=_time;
			}
			else if(even=='await')
			{
				if(eve.hasAttribute('await'))
				{
					//判断是否超时
					var _time=new Date();
					_time.getTime();
					if((_time-eve._time)<eve._timeout)
					{
						if(eve.hasAttribute('awaitNotice'))
						{
							fun.call(this,ev,val,true)
						}
						return false;
					}
					eve._time=_time;
				}
				eve.removeAwait=()=>
				{
					eve.removeAttribute('await')
				}
				eve.setAttribute('await','true')
			}
			if(chi)
			{
				//判断是否点击在代理元素上
				var child=eve.querySelectorAll(chi);
				var val;
				var len=child.length;
				for (var i = 0; i < len; i++) 
				{
					val=child[i];
					if(val.tagName && val.contains(ev.target))
					{
						if(once)eve.un(even,fun)
						//第二个为被代理元素
						fun.call(this,ev,val)
						break;
					}
				}
			}
			else
			{
				if(once)eve.un(even,fun)
				//第二个为自身
				fun.call(this,ev,eve);
			}
		}

		if(even=='tap' || even=='await')
		{
			if(even=='tap')eve._timeout=(eve.hasAttribute('time')?eve.getAttribute('time'):500);
			else eve._timeout=(eve.hasAttribute('time')?eve.getAttribute('time'):3000);
			eve.addEventListener('click',_fun_,eve.hasAttribute('useCapture'));
			eve._arr_.push(['click',_fun_,fun]);
		}
		else
		{
			eve.addEventListener($M.switch(even),_fun_,eve.hasAttribute('useCapture'));
			eve._arr_.push([even,_fun_,fun]);
		}
	}

	eve.once=function(even,chi,fun)
	{
		eve.on(even,chi,fun,true)
	}

	eve.un=function(even,fun)
	{
		eve.setAttribute('_un','true')
		var i=0;
		function check(i)
		{
			//如果传入回调函数，则比对用户回调函数，如果相同则取消监听。
			//否则取消所有，该元素上的监听事件。
			if(fun)
			{
				if(fun==eve._arr_[i][2])
				{
					eve.removeEventListener(eve._arr_[i][0],eve._arr_[i][1])
					delete eve._arr_[i];
				}
			}
			else
			{
				eve.removeEventListener(eve._arr_[i][0],eve._arr_[i][1])
				delete eve._arr_[i];
			}
		}
		for (i in eve._arr_) 
		{
			if(even)
			{
				if(even==eve._arr_[i][0])
				{
					check(i)
				}
			}
			else
			{
				check(i)
			}
		}
	}
	return eve;
}

$M._findListener=function(ele)
{
	function make(even,chi,fun,funn,tagType)
	{
		var res=[];
		if(even)
		{
			if(even.indexOf(',')==-1)
			{
				res=[even]
			}
			else
			{
				res=even.split(',')
			}
		}
		else if(tagType===null)
		{
			funn();
			return;
		}
		
		for (var index =0; index < res.length;index++) 
		{
			if(!tagType)
			{
				funn(res[index],chi,fun)
			}
			else
			{
				funn(res[index],fun)
			}
		}
	}
	ele.listener=function(even,chi,fun)
	{
		make(even,chi,fun,ele.on)
	}
	ele.unListener=function(even,fun)
	{
		make(even,chi,fun,ele.un)
	}
	
	ele.rely=function(id,even,fun)
	{
		var _ele=$M.find(id);
		if(!_ele)
		{
			$M.info('[事件派发]未找到元素',id);
			return '';
		}
		ele.setAttribute('_unRely','true');
		make(even,true,fun,_ele.on,true)
		//_rely依赖监听存放数组
		ele._rely=ele._rely?ele._rely:[];
		ele._rely.push({dom:_ele,even:even,fun:fun})
	}

	ele.unRely=function(even,fun)
	{
		if(!ele._rely)
		{
			return;
		}
		function pack(even,fun)
		{
			var index;
			var i;
			for (index = 0; index < ele._rely.length; index++) 
			{
				i=ele._rely[index];
				if(!i)continue;
				if(even)
				{
					if(even==i['even'])
					{
						if(fun==i['fun'])
						{
							i['dom'].un(i['even'],i['fun']);
							ele._rely[index]=undefined;
						}
						else
						{
							i['dom'].un(i['even'],i['fun']);
							ele._rely[index]=undefined;
						}
					}
				}
				else
				{
					i['dom'].un(i['even'],i['fun']);
					ele._rely[index]=undefined;
				}
			}
		}
		make(even,true,fun,pack,null)
	}
}

$M._findListenerFor=function(ele_arr)
{
	function make(fun,arg1,arg2,arg3)
	{
		for (i = 0; i < ele_arr.length; i++) 
		{
			if(fun instanceof Function)
			{
				fun(ele_arr[i])
			}
			else
			{
				ele_arr[i][fun](arg1,arg2,arg3)
			}
		}
	}
	make($M._findListener);
	ele_arr.listener=function(even,chi,fun)
	{
		make('listener',even,chi,fun)
	}
	ele_arr.unListener=function(even,fun)
	{
		make('unListener',even,fun)
	}
	ele_arr.rely=function(id,even,fun)
	{
		make('rely',id,even,fun)
	}
	ele_arr.unRely=function(even,fun)
	{
		make('unRely',even,fun)
	}
}

$M.find=function(param,tag)
{
	var eve;
	if(!param)
	{
		throw Error('find需要參數')
		//$M.info('find需要參數');
	}
	if(tag)
	{
		eve=document.querySelectorAll(param)
		var ele_len=eve.length;
		var ele_arr=[];
		var i;
		for (i = 0; i < ele_len; i++) 
		{
			ele_arr.push($M._find(eve[i]))
		}
		$M._findListenerFor(ele_arr)
		return ele_arr;
	}
	else
	{
		if($M.isDOM(param))
		{
			eve=param
		}
		else
		{
			eve=document.querySelector(param)
		}
		
		if(!eve)
		{
			return '';
		}
		var ele=$M._find(eve)
		$M._findListener(ele)
		return ele;
	}
}
