search
HomeWeb Front-endJS TutorialBaidu space pop-up effect analysis_javascript skills

Since I started using Firefox browser, I have almost developed a habit of using WebDeveloper to download and analyze the JS and CSS of some beautiful websites for learning.

The pop-up windows and drag-and-drop effects of Baidu Space look pretty good. Many well-known websites now use this technology. Below I will send out my down js code. I have analyzed part of it, but there are still many things that I don’t understand. There are no comments. I hope an expert can help me explain it. I am a beginner, so please tell me if I am wrong.
Let me make a statement. This code is for learning purposes only, and the technical copyright belongs to Baidu.
Mainly a file called: popup.js, as follows:
/**//*********************************************** popup.js**************************************************/
//Add a push method to the array Array
//Add a push method to the end of the array Object
if(!Array.prototype.push)
{
Array.prototype.push=function ()
{
var startLength=this.length;
for(var i =0;i {
this[startLength i]=arguments[i];
}
return this.length;
}
};

//Process the parameters of the G function
function G()
{
//Define an array to save the parameters
var elements=new Array();
//Loop to analyze the content of parameters in G
for(var i=0;i {
var element=arguments[i];

//If the parameter type is string, get the object with this parameter as the ID
if(typeof element=='string')
{
element=document.getElementById(element);
}
//If the length of the parameter is 1
if(arguments.length==1)
{
return element;
}
//Add the object to the end of the array
elements.push(element);
};
return elements;
};

Function.prototype.bind=function (object)
{
var __method=this;
return function ()
{
__method.apply(object,arguments);
};
};

//Bind event
Function.prototype.bindAsEventListener=function (object)
{
var __method=this;
return function (event){__method.call(object,event||window.event);};
};


Object.extend=function (destination,source)
{
for(property in source)
{
destination[property]=source[property ];
};
return destination;
};


if(!window.Event)
{
var Event=new Object();
};

Object.extend(
Event,

{
observers:false,
element:function (event)
{
return event.target||event.srcElement;
},

isLeftClick:function (event)
{
return (((event.which)&&(event.which==1) )||((event.button)&&(event.button==1)));
},

pointerX:function (event)
{
return event.pageX| |(event.clientX (document.documentElement.scrollLeft||document.body.scrollLeft));
},

pointerY:function (event)
{
return event.pageY| |(event.clientY (document.documentElement.scrollTop||document.body.scrollTop));
},

stop:function (event)
{
if(event.preventDefault )
{
event.preventDefault();
event.stopPropagation();
}
else
{
event.returnValue=false;
event.cancelBubble =true;
};
},

findElement:function (event,tagName)
{
var element=Event.element(event);
while(element .parentNode&&(!element.tagName||(element.tagName.toUpperCase()!=tagName.toUpperCase())))
element=element.parentNode;
return element;
},

_observeAndCache:function (element,name,observer,useCapture)
{
if(!this.observers)
this.observers=[];
if(element.addEventListener)
{
this.observers.push([element,name,observer,useCapture]);
element.addEventListener(name,observer,useCapture);
}
else if(element.attachEvent)
{
this.observers.push([element,name,observer,useCapture]);
element.attachEvent('on' name,observer);
};
},

unloadCache:function ()
{
if(!Event.observers)
return;
for(var i=0;i {
Event.stopObserving.apply(this,Event.observers[i]);
Event.observers[i][0]=null;
};
Event.observers=false ;
 },

 observe:function (element,name,observer,useCapture)
 {
 var element=G(element);
 useCapture=useCapture||false;
 if(name=='keypress'&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.attachEvent))
 name='keydown';
 this._observeAndCache(element,name,observer,useCapture);
 },

 stopObserving:function (element,name,observer,useCapture)
 {
 var element=G(element);
 useCapture=useCapture||false;
 if(name=='keypress'&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.detachEvent))
 name='keydown';
 if(element.removeEventListener)
 {
 element.removeEventListener(name,observer,useCapture);
 }
 else if(element.detachEvent)
 {
 element.detachEvent('on' name,observer);
 };
 }
 }
);

Event.observe(window,'unload',Event.unloadCache,false);



var Class=function ()
{
 var _class=function ()
 {
 this.initialize.apply(this,arguments);
 };
 for(i=0;i {
 superClass=arguments[i];
 for(member in superClass.prototype)
 {
 _class.prototype[member]=superClass.prototype[member];
 };
 };
 _class.child=function ()
 {
 return new Class(this);
 };
 _class.extend=function (f)
 {
 for(property in f)
 {
 _class.prototype[property]=f[property];
 };
 };
 return _class;
};


//改变百度空间的最顶端和最低端的p的id值
//如果flag为begin,则为弹出状态的id值
//如果flag为end,则为非弹出状态的id值,即原本的id值
function space(flag)
{
 if(flag=="begin")
 {
 var ele=document.getElementById("ft");
 if(typeof(ele)!="#ff0000"&&ele!=null)
 ele.id="ft_popup";
 ele=document.getElementById("usrbar");
 if(typeof(ele)!="undefined"&&ele!=null)
 ele.id="usrbar_popup";
 }
 else if(flag=="end")
 {
 var ele=document.getElementById("ft_popup");
 if(typeof(ele)!="undefined"&&ele!=null)
 ele.id="ft";
 ele=document.getElementById("usrbar_popup");
 if(typeof(ele)!="undefined"&&ele!=null)
 ele.id="usrbar";
 };
 };



//**************************************************Popup类弹出窗口***************************************************************


var Popup=new Class();

Popup.prototype={ 
 //弹出窗口中框架的name名称
 iframeIdName:'ifr_popup',

 initialize:function (config)
 {
 //---------------弹出对话框的配置信息------------------
 //contentType:设置内容区域为什么类型:1为另外一个html文件 | 2为自定义html字符串 | 3为confirm对话框 | 4为alert警告对话框
 //isHaveTitle:是否显示标题栏
 //scrollType:设置或获取对话框中的框架是否可被滚动
 //isBackgroundCanClick:弹出对话框后,是否允许蒙布后的所有元素被点击。也就是如果为false的话,就会有全屏蒙布,如果为true的话,就会去掉全屏蒙布
 //isSupportDraging:是否支持拖拽
 //isShowShadow:是否现实阴影
 //isReloadOnClose:是否刷新页面,并关闭对话框
 //width:宽度
 //height:高度
 this.config=Object.extend({contentType:1,isHaveTitle:true,scrollType:'yes',isBackgroundCanClick:false,isSupportDraging:true,isShowShadow:true,isReloadOnClose:true,width:400,height:300},config||{});

 //----------------对话框的参数值信息------------------------
 //shadowWidth :阴影的宽度
 //contentUrl :html链接页面
 //contentHtml :html内容
 //callBack :回调的函数名
 //parameter :回调的函数名中传的参数
 //confirmCon :对话框内容
 //alertCon :警告框内容
 //someHiddenTag:页面中需要隐藏的元素列表,以逗号分割
//someHiddenEle: ID list of elements that need to be hidden (the difference from someToHidden is: someHiddenEle uses getElementById, while someToHidden uses getElementByTagName, which contains objects)
//overlay:
//coverOpacity: cover Cloth transparency value
this.info={shadowWidth:4,title:"",contentUrl:"",contentHtml:"",callBack:null,parameter:null,confirmCon:"",alertCon:"",someHiddenTag :"select,object,embed",someHiddenEle:"",overlay:0,coverOpacity:40};

//Set the color cColor: the background of the mask, bColor: the background of the content area, tColor: title The color of the column and border, wColor: the background color of the font
this.color={cColor:"#EEEEEE",bColor:"#FFFFFF",tColor:"#709CD2",wColor:"#FFFFFF"};

this.dropClass=null;

//Used to place the hidden object list, the first call in the hiddenTag method
this.someToHidden=[];

//If there is no title bar, dragging is not supported
if(!this.config.isHaveTitle)
{
this.config.isSupportDraging=false;
}
//Initialization
this.iniBuild();
},

//Set configuration information and parameter content
setContent:function (arrt,val)
{
if(val! ='')
{
switch(arrt)
{
case 'width':this.config.width=val;
break;
case 'height':this. config.height=val;
break;
case 'title':this.info.title=val;
break;
case 'contentUrl':this.info.contentUrl=val;
break;
case 'contentHtml':this.info.contentHtml=val;
break;
case 'callBack':this.info.callBack=val;
break;
case ' parameter':this.info.parameter=val;
break;
case 'confirmCon':this.info.confirmCon=val;
break;
case 'alertCon':this.info.alertCon =val;
break;
case 'someHiddenTag':this.info.someHiddenTag=val;
break;
case 'someHiddenEle':this.info.someHiddenEle=val;
break;
case 'overlay':this.info.overlay=val;
};
};
},

iniBuild:function ()
{
G ('dialogCase')?G('dialogCase').parentNode.removeChild(G('dialogCase')):function (){};
var op=document.createElement('span');
op .id='dialogCase';
document.body.appendChild(op);
},

build:function ()
{
//Set the z of the full screen mask -index
var baseZIndex=10001 this.info.overlay*10;
//Set the z-index of the pop-up window on the mask (2 values ​​higher than the z-index of the mask)
var showZIndex=baseZIndex 2;

//Define the frame name
this.iframeIdName='ifr_popup' this.info.overlay;

//Set the main path of the image
var path ="http://img.baidu.com/hi/img/";

//Close button
var close='';

//Use filter settings Transparency of the object
var cB='filter: alpha(opacity=' this.info.coverOpacity ');opacity:' this.info.coverOpacity/100 ';';

//Set full screen Cover
var cover='

';

//Set the pop-up main window settings
var mainBox=' ';

// Set the window title bar
if(this.config.isHaveTitle)
{
 mainBox ='';
 }
 else 
 {
 mainBox ='';
 };

 //设置窗口主内容区域
 mainBox ='
' '' '
' this.info.title ' ' close '
' close '
' '

';

 //如果有蒙布
 if(!this.config.isBackgroundCanClick)
 {
 G('dialogCase').innerHTML=cover mainBox;
 G('dialogBoxBG').style.height=document.body.scrollHeight;
 }
 else
 {
 G('dialogCase').innerHTML=mainBox;
 }

 Event.observe(G('dialogBoxClose'),"click",this.reset.bindAsEventListener(this),false);

 //如果支持拖动,则设置拖动处理
 if(this.config.isSupportDraging)
 {
 dropClass=new Dragdrop(this.config.width,this.config.height,this.info.shadowWidth,this.config.isSupportDraging,this.config.contentType);
 G("dialogBoxTitle").style.cursor="move";
 };

 this.lastBuild();
 },

 
 lastBuild:function ()
 {
 //设置confim对话框的具体内容
 var confirm='

' this.info.confirmCon '

 

';
 //设置alert对话框的具体内容
 var alert='

' this.info.alertCon '

';

 var baseZIndex=10001 this.info.overlay*10;
 var coverIfZIndex=baseZIndex 4;

 //判断内容类型决定窗口的主内容区域应该显示什么
 if(this.config.contentType==1)
 {
 var openIframe="";
 var coverIframe="

";
 G("dialogBody").innerHTML=openIframe coverIframe;
 }
else if(this.config.contentType==2)
{
G("dialogBody").innerHTML=this.info.contentHtml;
}
else if(this.config.contentType= =3)
{
G("dialogBody").innerHTML=confirm;Event.observe(G('dialogOk'),"click",this.forCallback.bindAsEventListener(this),false);
Event.observe(G('dialogCancel'),"click",this.close.bindAsEventListener(this),false);
}
else if(this.config.contentType==4)
{
G("dialogBody").innerHTML=alert;
Event.observe(G('dialogYES'),"click",this.close.bindAsEventListener(this),false);
};
},

//Reload the height and content of the pop-up window
reBuild:function ()
{
G('dialogBody').height=G('dialogBody' ).clientHeight;
this.lastBuild();
},

show:function ()
{
//Hide some elements specified in info
this .hiddenSome();
//Center the pop-up window
this.middle();
//Set the shadow
if(this.config.isShowShadow)
this.shadow();
},

//Set the callback function
forCallback:function ()
{
return this.info.callBack(this.info.parameter);
},

//Set a shadow for the pop-up window
shadow:function ()
{
var oShadow=G('dialogBoxShadow');
var oDialog=G('dialogBox'); oShadow['style']['position']="absolute";
oShadow['style']['background']="#000";
oShadow['style']['display'] ="";
oShadow['style']['opacity']="0.2";
oShadow['style']['filter']="alpha(opacity=20)";
oShadow['style']['top']=oDialog.offsetTop this.info.shadowWidth;
oShadow['style']['left']=oDialog.offsetLeft this.info.shadowWidth;
oShadow[ 'style']['width']=oDialog.offsetWidth;oShadow['style']['height']=oDialog.offsetHeight;
},

// Center the pop-up window
middle:function ()
{
if(!this.config.isBackgroundCanClick)
G('dialogBoxBG').style.display='';
var oDialog=G('dialogBox' );
oDialog['style']['position']="absolute";
oDialog['style']['display']='';
var sClientWidth=document.body.clientWidth ;
var sClientHeight=document.body.clientHeight;
var sScrollTop=document.body.scrollTop;
//alert("document.body.clientWidth = " sClientWidth "ndocument.body.clientHeight" sClientHeight) ;
var sleft=(document.body.clientWidth/2)-(oDialog.offsetWidth/2);
var iTop=-80 (sClientHeight/2 sScrollTop)-(oDialog.offsetHeight/2);
var sTop=iTop>0?iTop:(sClientHeight/2 sScrollTop)-(oDialog.offsetHeight/2);
//alert("var iTop=-80 (sClientHeight/2 sScrollTop)-(oDialog.offsetHeight/ 2);n" "sClientHeight is " sClientHeight "nsScrollTop is " sScrollTop);
//alert("iTop is " iTop);
if(sTop sTop="20";
if(sleft sleft="20";
oDialog['style']['left']=sleft;
oDialog['style']['top']=sTop ;
//alert("sleft is " sleft);
//alert("sTop is " sTop);
},

//Refresh the page and close the current pop-up window
reset:function ()
{
if(this.config.isReloadOnClose)
{
top.location.reload();
};
this.close( );
},

//Close the current pop-up window
close:function ()
{
G('dialogBox').style.display='none';
if(!this.config.isBackgroundCanClick)
G('dialogBoxBG').style.display='none';
if(this.config.isShowShadow)
G('dialogBoxShadow'). style.display='none';
G('dialogBody').innerHTML='';

this.showSome();
},

//Hide someHiddenTag and all elements in someHiddenEle
hiddenSome:function ()
{
//Hide all elements in someHiddenTag
var tag=this.info.someHiddenTag.split(",");
if(tag.length==1&&tag[0]=="")
{
tag.length=0;
}
for(var i=0;i {
this.hiddenTag(tag[i]);
};
//Hide all comma-separated ID elements in someHiddenEle
var ids=this.info.someHiddenEle.split(",");
if(ids.length==1&&ids[ 0]=="")
ids.length=0;
for(var i=0;i {
this.hiddenEle(ids[i]) ;
};
//Change the id value of the top and bottom p to the id value of the pop-up state, see the implementation of space
space("begin");
},

//Hide a group of elements
hiddenTag:function (tagName)
{
var ele=document.getElementsByTagName(tagName);
if(ele!=null)
{
for(var i=0;i {
if(ele[i].style.display!="none"&&ele[i].style.visibility!=' hidden')
{
ele[i].style.visibility='hidden';
this.someToHidden.push(ele[i]);
};
};
};
},

//Hide a single element
hiddenEle:function (id)
{
var ele=document.getElementById(id);
if( typeof(ele)!="undefined"&&ele!=null)
{
ele.style.visibility='hidden';
this.someToHidden.push(ele);
}
},

//Display all hidden elements saved in someToHidden
//And restore the top and bottom p to the original id value
showSome:function ()
{
for(var i=0;i {
this.someToHidden[i].style.visibility='visible';
};
space( "end");
}
};




//************************ *************************************Dragdrop class (drag action)****** *************************************************** ****

var Dragdrop=new Class();

Dragdrop.prototype={
initialize:function (width,height,shadowWidth,showShadow,contentType)
{
this.dragData=null;
this.dragDataIn=null;
this.backData=null;
this.width=width;
this.height=height;
this. shadowWidth=shadowWidth;
this.showShadow=showShadow;
this.contentType=contentType;
this.IsDraging=false;
this.oObj=G('dialogBox');
Event. observe(G('dialogBoxTitle'),"mousedown",this.moveStart.bindAsEventListener(this),false);
},

moveStart:function (event)
{
this .IsDraging=true;
if(this.contentType==1)
{
G("iframeBG").style.display="";
G("iframeBG").style. width=this.width;
G("iframeBG").style.height=this.height;
};
Event.observe(document,"mousemove",this.mousemove.bindAsEventListener(this) ,false);
Event.observe(document,"mouseup",this.mouseup.bindAsEventListener(this),false);
Event.observe(document,"selectstart",this.returnFalse,false);
this.dragData={x:Event.pointerX(event),y:Event.pointerY(event)};
this.backData={x:parseInt(this.oObj.style.left),y:parseInt (this.oObj.style.top)};
},

mousemove:function (event)
{
if(!this.IsDraging)
return ;
var iLeft=Event.pointerX(event)-this.dragData["x"] parseInt(this.oObj.style.left);
var iTop=Event.pointerY(event)-this.dragData["y"] parseInt(this.oObj.style.top);
if(this.dragData["y"] iTop=iTop-12;
else if(this.dragData["y"]>parseInt(this.oObj.style.top) 25)
iTop=iTop 12;
this.oObj.style.left=iLeft;
this. oObj.style.top=iTop;
if(this.showShadow)
{
G('dialogBoxShadow').style.left=iLeft this.shadowWidth;
G('dialogBoxShadow'). style.top=iTop this.shadowWidth;
};
this.dragData={x:Event.pointerX(event),y:Event.pointerY(event)};
document.body.style. cursor="move";
},

mouseup:function (event)
{
if(!this.IsDraging)
return ;
if(this.contentType ==1)
G("iframeBG").style.display="none";
document.onmousemove=null;
document.onmouseup=null;
var mousX=Event.pointerX(event)-(document.documentElement.scrollLeft||document.body.scrollLeft);
var mousY=Event.pointerY(event)-(document. documentElement.scrollTop||document.body.scrollTop);
if(mousXdocument.body.clientWidth||mousY>document.body.clientHeight)
{
this.oObj.style.left=this.backData["x"];
this.oObj.style.top=this.backData["y"];
if(this.showShadow)
{
G('dialogBoxShadow').style.left=this.backData.x this.shadowWidth;
G('dialogBoxShadow').style.top=this.backData.y this.shadowWidth;
};
};
this.IsDraging=false;
document.body.style.cursor="";
Event.stopObserving(document,"selectstart",this.returnFalse,false);
},

returnFalse:function ()
{
return false;
}
};

Do the above to the popup.js file A reference, the following is the code of the html page that tests this js file. You can go back and test it easily.





Untitled page









iframe 프레임 예


html 문자 문자열 예


대화상자 확인

경고 경고 상자 예






html>

코드가 잔뜩 있어요! 그를 끌고 간 사람은 무슨 일이 일어나고 있는지 몰랐나요? 위의 클래스 기능이 어떻게 수행되는지 정확히 모르겠습니다. 의견이 없으면 기본적으로 명확하지 않습니다. 좀 더 자세히 분석해 보는 시간을 갖도록 할게요! 다른 메모도 작성할 시간을 찾으십시오. 이해가 된다면 더 많은 조언을 부탁드립니다. 더 자세히 설명할수록 좋습니다.
Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
JavaScript in Action: Real-World Examples and ProjectsJavaScript in Action: Real-World Examples and ProjectsApr 19, 2025 am 12:13 AM

JavaScript's application in the real world includes front-end and back-end development. 1) Display front-end applications by building a TODO list application, involving DOM operations and event processing. 2) Build RESTfulAPI through Node.js and Express to demonstrate back-end applications.

JavaScript and the Web: Core Functionality and Use CasesJavaScript and the Web: Core Functionality and Use CasesApr 18, 2025 am 12:19 AM

The main uses of JavaScript in web development include client interaction, form verification and asynchronous communication. 1) Dynamic content update and user interaction through DOM operations; 2) Client verification is carried out before the user submits data to improve the user experience; 3) Refreshless communication with the server is achieved through AJAX technology.

Understanding the JavaScript Engine: Implementation DetailsUnderstanding the JavaScript Engine: Implementation DetailsApr 17, 2025 am 12:05 AM

Understanding how JavaScript engine works internally is important to developers because it helps write more efficient code and understand performance bottlenecks and optimization strategies. 1) The engine's workflow includes three stages: parsing, compiling and execution; 2) During the execution process, the engine will perform dynamic optimization, such as inline cache and hidden classes; 3) Best practices include avoiding global variables, optimizing loops, using const and lets, and avoiding excessive use of closures.

Python vs. JavaScript: The Learning Curve and Ease of UsePython vs. JavaScript: The Learning Curve and Ease of UseApr 16, 2025 am 12:12 AM

Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

Python vs. JavaScript: Community, Libraries, and ResourcesPython vs. JavaScript: Community, Libraries, and ResourcesApr 15, 2025 am 12:16 AM

Python and JavaScript have their own advantages and disadvantages in terms of community, libraries and resources. 1) The Python community is friendly and suitable for beginners, but the front-end development resources are not as rich as JavaScript. 2) Python is powerful in data science and machine learning libraries, while JavaScript is better in front-end development libraries and frameworks. 3) Both have rich learning resources, but Python is suitable for starting with official documents, while JavaScript is better with MDNWebDocs. The choice should be based on project needs and personal interests.

From C/C   to JavaScript: How It All WorksFrom C/C to JavaScript: How It All WorksApr 14, 2025 am 12:05 AM

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.

JavaScript Engines: Comparing ImplementationsJavaScript Engines: Comparing ImplementationsApr 13, 2025 am 12:05 AM

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

Beyond the Browser: JavaScript in the Real WorldBeyond the Browser: JavaScript in the Real WorldApr 12, 2025 am 12:06 AM

JavaScript's applications in the real world include server-side programming, mobile application development and Internet of Things control: 1. Server-side programming is realized through Node.js, suitable for high concurrent request processing. 2. Mobile application development is carried out through ReactNative and supports cross-platform deployment. 3. Used for IoT device control through Johnny-Five library, suitable for hardware interaction.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

EditPlus Chinese cracked version

EditPlus Chinese cracked version

Small size, syntax highlighting, does not support code prompt function

PhpStorm Mac version

PhpStorm Mac version

The latest (2018.2.1) professional PHP integrated development tool

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

SublimeText3 English version

SublimeText3 English version

Recommended: Win version, supports code prompts!