辰迅云帮助中心

其他类

小编给大家分享一下websocket+node.js如何实现实时聊天系统问题咨询,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1.最近新学习websocket。做了一个实时聊天。用Node.js搭建的服务:serevr.js. 两个相互通信页面:client.html 和server.html但是就是有很多问题,想让知道的人帮我看看哈:我先把代码贴出来:server.js:var ws=require("nodejs-websocket");  console.log("开始建立连接...");  var str1=null,str2=null, clientReady=false,serverReady=false;  var server=ws.createServer(function(conn){    conn.on('text',function(str){      console.log(str);      /**       * 用户小雨第一次连接       */     if(str==="小雨"){        str1=conn;        clientReady=true;        str1.sendText("欢迎"+str);      }     /**      * 用户小乔第一次连接      */     if(str==="小乔"){        str2=conn;        serverReady=true;       str2.sendText("欢迎"+str);     }     /**      * 当有第二个用户连接时。      */      if(clientReady&&serverReady){       str2.sendText(str);       str1.sendText(str);     }    })    conn.on("close",function(code,reason){      console.log("关闭连接");    })    conn.on("error",function(code,reason){      console.log("异常关闭")    });  }).listen(8082);  console.log("websocket连接完毕") client.html:<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <meta http-equiv="X-UA-Compatible" content="ie=edge">  <title>Document</title>  <style>    .kuang{       width: 600px;       min-height: 50px;       max-height:296px;       border:1px solid;       float: left;       display: block;       position:relative;       overflow-y: scroll;     }     .value{        width: 200px;     }     .input{       display:block;       position: absolute;       left:0;       margin-top: 300px;     }   </style></head><body>  <label>连接用户:</label>  <input type="text" id="name" value="小雨" readonly/>  <button id="conn">连接</button>  <button id="close">断开</button><br/><br/>  <div class="kuang" id="mess"></div>  <div class="input">    <input type="text" class="value" id="value1" />  <button id="send">发送</button>  </div>  <script>    var name=document.getElementById("name").value;     var mess=document.getElementById("mess");     var value1=document.getElementById("value1");     var conn= document.getElementById("conn");     var close=document.getElementById("close");     close.disabled=true;     if(window.WebSocket){      conn.onclick=function(){       var ws=new WebSocket('ws://127.0.0.1:8082');       conn.disabled=true;       close.disabled=false;         ws.onopen=function(e){           console.log("连接服务器成功");             ws.send(name);       }      ws.onmessage=function(e){       var time=new Date();       mess.innerHTML+=time.toUTCString()+":"+e.data+"<br>";       document.getElementById("send").onclick=function(e){         ws.send(name+"说:"+value1.value);         value1.value=" ";       }       document.onkeydown = function(e) {         e = e || window.event;         if(e.keyCode == 13) {            document.getElementById("send").onclick();           return false;         }       }       }     /**      * 客户端主动断开连接      *       * **/      close.onclick=function(){       ws.onclose();       conn.disabled=false;       close.disabled=true;      }        ws.onclose = function(e){        console.log("服务器关闭");      }      ws.onerror = function(){       console.log("连接出错");     }     }     }   </script></body></html>server.html 页面和client.html的代码一样,就是用户名字换成小乔啦。接下来就是问题啦:1.运行界面:  client.html  连接以后:本来服务器只需要回传一个欢迎小雨的,然后下面还输出了一个。server.html  小乔连接以后也出来了一个小乔,按理是欢迎小乔。然后告诉小乔小雨在线了。2.两个页面代码一样,但是就是不能只变成一个页面,硬要两个才能聊天。3.server.js那边逻辑有点问题,一直理不清楚。以上是“websocket+node.js如何实现实时聊天系统问题咨询”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...

这篇文章主要为大家展示了“JS如何实现上传图片实时预览功能”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“JS如何实现上传图片实时预览功能”这篇文章吧。前段时间在网络上找的代码,修改了一部分用在了项目里。原博客地址找不到了,如果原作者看到的话留言我,将于第一时间删除。//js本地图片预览,兼容ie[6-9]、火狐、Chrome17+、Opera11+、Maxthon3  function PreviewImage(fileObj) {     //创建dom元素    var divPreviewId = 'divPreview_' + fileObj.name;     var imgPreviewId = 'imgHeadPhoto_' + fileObj.name;     var html='<div id="'+divPreviewId+'">'+           '<img id="'+imgPreviewId+'" src="images/moren.jpg"  />'+          '</div>';     $('#'+divPreviewId).remove();     $(fileObj).after(html);     //进行限制    var allowExtention = ".jpg,.bmp,.gif,.png"; //允许上传文件的后缀名document.getElementById("hfAllowPicSuffix").value;    var extention = fileObj.value.substring(fileObj.value.lastIndexOf(".") + 1).toLowerCase();     var browserVersion = window.navigator.userAgent.toUpperCase();     if (allowExtention.indexOf(extention) > -1) {  //格式正确      if (fileObj.files) {  //HTML5实现预览,兼容chrome、火狐7+等        if (window.FileReader) {           var reader = new FileReader();           reader.onload = function (e) {             document.getElementById(imgPreviewId).setAttribute("src", e.target.result);           }           reader.readAsDataURL(fileObj.files[0]);         } else if (browserVersion.indexOf("SAFARI") > -1) {           $('#'+divPreviewId).remove();           alert("不支持Safari6.0以下浏览器的图片预览!");         }       } else if (browserVersion.indexOf("MSIE") > -1) {         if (browserVersion.indexOf("MSIE 6") > -1) {//ie6          document.getElementById(imgPreviewId).setAttribute("src", fileObj.value);         } else {//ie[7-9]          fileObj.select();           if (browserVersion.indexOf("MSIE 9") > -1)             fileObj.blur(); //不加上document.selection.createRange().text在ie9会拒绝访问          var newPreview = document.getElementById(divPreviewId + "New");           if (newPreview == null) {             newPreview = document.createElement("div");             newPreview.setAttribute("id", divPreviewId + "New");             newPreview.style.width = document.getElementById(imgPreviewId).width + "px";             newPreview.style.height = document.getElementById(imgPreviewId).height + "px";             newPreview.style.border = "solid 1px #d2e2e2";           }           newPreview.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='scale',src='" + document.selection.createRange().text + "')";           var tempDivPreview = document.getElementById(divPreviewId);           tempDivPreview.parentNode.insertBefore(newPreview, tempDivPreview);           tempDivPreview.style.display = "none";         }       } else if (browserVersion.indexOf("FIREFOX") > -1) {//firefox        var firefoxVersion = parseFloat(browserVersion.toLowerCase().match(/firefox\/([\d.]+)/)[1]);         if (firefoxVersion < 7) {//firefox7以下版本          document.getElementById(imgPreviewId).setAttribute("src", fileObj.files[0].getAsDataURL());         } else {//firefox7.0+                    document.getElementById(imgPreviewId).setAttribute("src", window.URL.createObjectURL(fileObj.files[0]));         }       } else {         document.getElementById(imgPreviewId).setAttribute("src", fileObj.value);       }     } else {       $('#'+divPreviewId).remove();       alert("仅支持" + allowExtention + "为后缀名的文件!");       fileObj.value = ""; //清空选中文件      if (browserVersion.indexOf("MSIE") > -1) {         fileObj.select();         document.selection.clear();       }       fileObj.outerHTML = fileObj.outerHTML;     }     return fileObj.value;  //返回路径  }以上是“JS如何实现上传图片实时预览功能”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...

小编给大家分享一下Angular.js怎么实现动态加载组件,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!前言有时候需要根据URL来渲染不同组件,我所指的是在同一个URL地址中根据参数的变化显示不同的组件;这是利用Angular动态加载组件完成的,同时也会设法让这部分动态组件也支持AOT。动态加载组件下面以一个Step组件为示例,完成一个3个步骤的示例展示,并且可以通过URL user?step=step-one 的变化显示第N个步骤的内容。1、resolveComponentFactory首先,还是需要先创建动态加载组件模块。import { Component, Input, ViewContainerRef, ComponentFactoryResolver, OnDestroy, ComponentRef } from '@angular/core';@Component({  selector: 'step',  template: `` })export class Step implements OnDestroy {  private currentComponent: ComponentRef<any>;  constructor(private vcr: ViewContainerRef, private cfr: ComponentFactoryResolver) {}  @Input() set data(data: { component: any, inputs?: { [key: string]: any } } ) {   const compFactory = this.cfr.resolveComponentFactory(data.component);   const component = this.vcr.createComponent(compFactory);   if (data.inputs) {   for (let key in data.inputs) {    component.instance[key] = data.inputs[key];   }   }   this.destroy();   this.currentComponent = component;  }  destroy() {  if (this.currentComponent) {   this.currentComponent.destroy();   this.currentComponent = null;  }  }  ngOnDestroy(): void {  this.destroy();  } }抛开一销毁动作不谈的话,实际就两行代码:let compFactory = this.cfr.resolveComponentFactory(this.comp);利用 ComponentFactoryResolver 查找提供组件的 ComponentFactory,而后利用这个工厂来创建实际的组件。this.compInstance = this.vcr.createComponent(compFactory);这一切都非常简单。而对于一些基本的参数,是直接对组件实例进行赋值。  for (let key in data.inputs) {    component.instance[key] = data.inputs[key];   }最后,还需要告诉Angular AOT编译器为用户动态组件提供工厂注册,否则 ComponentFactoryResolver 会找不到它们,最简单就是利用 NgModule.entryComponents 进行注册。@NgModule({  entryComponents: [ UserOneComponent, UserTwoComponent, UserThirdComponent ] })export class AppModule { }但这样其实还是挺奇怪的,entryComponents 本身可能还会存在其他组件。而动态加载组件本身是一个通用性非常强,因此,把它封装成名曰 StepModule 挺有必要的,这样的话,就可以创建一种看起来更舒服的方式。@NgModule({  declarations: [ Step ],  exports: [ Step ] }) export class StepModule {  static withComponents(components: any) {  return {   ngModule: StepModule,   providers: [   { provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: components, multi: true }   ]  }  } }通过利用 ANALYZE_FOR_ENTRY_COMPONENTS 将多个组件以更友好的方式动态注册至 entryComponents。const COMPONENTS = [ ];@NgModule({  declarations: [ ...COMPONENTS ],  imports: [  StepModule.withComponents([ ...COMPONENTS ]) ] }) export class AppModule { }2、一个示例有3个Step步骤的组件,分别为:// user-one.component.tsimport { Component, OnDestroy, Input, Injector, EventEmitter, Output } from '@angular/core';@Component({  selector: 'step-one',  template: `<h3>Step One Component:params value: {{step}}</h3>`})export class UserOneComponent implements OnDestroy {  private _step: string;  @Input()   set step(str: string) {  console.log('@Input step: ' + str);  this._step = str;  }  get step() {  return this._step;  }  ngOnInit() {  console.log('step one init');  }  ngOnDestroy(): void {  console.log('step one destroy');  } }user-two、user-third 略同,这里组件还需要进行注册:const STEPCOMPONENTS = [ UserOneComponent, UserTwoComponent, UserThirdComponent ];@NgModule({  declarations: [ ...STEPCOMPONENTS ],  imports: [  StepModule.withComponents([ ...STEPCOMPONENTS ]) ] }) export class AppModule { }这里没有 entryComponents 字眼,而是为 StepModule 模块帮助我们动态注册。这样至少看起来更内聚一点,而且并不会与其他 entryComponents 在一起,待东西越多越不舒服。最后,还需要 UserComponent 组件来维护步骤容器,会根据 URL 参数的变化,利用 StepComponent 组件动态加载相应组件。@Component({  selector: 'user',  template: `<step [comp]="stepComp"></step>`})export class UserComponent {  constructor(private route: ActivatedRoute) {}  stepComp: any;  ngOnInit() {  this.route.queryParams.subscribe(params => {   const step = params['step'] || 'step-one';   // 组件与参数对应表  const compMaps = {   'step-one': { component: UserOneComponent, inputs: { step: step } },   'step-two': { component: UserTwoComponent },   'step-third': { component: UserThirdComponent },   };   this.stepComp = compMaps[step];  });  } }非常简单的使用,而且又对AOT比较友好。以上是“Angular.js怎么实现动态加载组件”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...

这篇文章给大家分享的是有关JS如何实现加载和读取XML文件的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。有时在开发时用到 JS 加载和读取XML文件的情况,写下提供参考,这里主要是分两步完成:1. JS加载XML文件步骤一般为(1),建立 XML DOM 对象;(2),设置加载方式,异步(推荐)或同步; (3)提供XML文件URL然后调用 load 方法;大致如下:var xmlFileName="xxFile.xml";var xmlDoc='';if (window.ActiveXObject){ // IE  var activeXNameList=new Array("MSXML2.DOMDocument.6.0","MSXML2.DOMDocument.5.0","MSXML2.DOMDocument.4.0","MSXML2.DOMDocument.3.0","MSXML2.DOMDocument","Microsoft.XMLDOM","MSXML.DOMDocument");   for(var h=0;h<activeXNameList.length;h++)   {     try{       xmlDoc=new ActiveXObject(activeXNameList[h]);     }catch(e){       continue;     }     if(xmlDoc) break;   } }else if(document.implementation && document.implementation.createDocument){ //非 IE  xmlDoc=document.implementation.createDocument("","",null); }else{   alert('can not create XML DOM object, update your browser please...'); } xmlDoc.async=false; //同步,防止后面程序处理时遇到文件还没加载完成出现的错误,故同步等XML文件加载完再做后面处理xmlDoc.load(xmlFileName); //加载XML2. JS读取XML文件节点在加载XML文件之后就是读取XML文件的节点了,可以使用 DOM 相应的方法,对 MS IE 其它浏览器的读法相近,例如:例如下的XML文件结构:<visiter>  <area areaid="shenzhen">    <areaname>shenzhen</areaname>    <user userid="001">      <name>shenzhenNBA</name>      <sex>man</sex>    </user>  </area>  <area areaid="shanghai">    <areaname>shenzhen</areaname>    <user userid="002">      <name>xiaoming</name>      <sex>woman</sex>    </user>    <user userid="003">      <name>zhangsan</name>      <sex>man</sex>    </user>  </area></visiter>//JS读取 XML 文件中的 area 节点的方式如下:var nodeList= xmlDoc.documentElement.getElementsByTagName("area"); // IEfor(var i=0;i<nodeList.length;i++){   //...遍历操作...}var nodeList=xmlDoc.getElementsByTagName("area"); // 非IEfor(var i=0;i<nodeList.length;i++){   //...遍历操作...}还有部分读取节点的方法://MS IEnode.text ;   //读取node节点的文本值node.childNodes[i].text ;  //读取 node 下的第 i 个[直接下一级]子节点的文本node.getAttribute("attributeName") ;   //读取 node 节点的属性名称为 attributeName 的属性值//还有其他的方法等, 可以网上搜索//非 MS IEnode.nodeValue ;   //读取node节点的文本值node.childNodes[i].nodeValue ;  //读取 node 下的第 i 个[直接下一级]子节点的文本node.getAttribute("attributeName") ;   //读取 node 节点的属性名称为 attributeName 的属性值//还有其他的方法等, 可以网上搜索感谢各位的阅读!关于“JS如何实现加载和读取XML文件”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!...

学Linux有什么用处

2021/6/21 14:08:57

本篇内容主要讲解“学Linux有什么用处”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“学Linux有什么用处”吧!当一个人问你关于 Linux 的问题时,他们经常希望你能够给他们一些使用 Linux 的理由。当然,也有例外。从来没有听过“Linux”的人们可能会问一些字面定义。但是当你的朋友或者同事吐露出他们对当前的操作系统有些不满意的时候,解释一下你为什么喜欢 Linux 可能更好,而不是告诉他们为什么 Linux 是一个比专有系统更好的选择。换句话说,你不需要销售演示,你需要的是度假照片(如果你是个书虫的话,也可以是度假时买的一本书)。为了达到这个目的,下面是我喜欢 Linux 的 21 个原因,分别在 21 个不同的场合讲给 21 个不同的人。游戏Gaming on Linux说到玩电脑,最明显的活动之一就是玩游戏,说到玩游戏,我很喜欢。我很高兴花一个晚上玩一个 8 位的益智游戏或者 epic 工作室的一个 AAA 级游戏。其它时候,我还会沉浸在棋盘游戏或者角色扮演游戏(RPG)中。这些我都是在 Linux系统的电脑上做的。办公LibreOffice一种方法并不适合所有人。这对帽子和办公室工作来说都是如此。看到同事们被困在一个不适合他们的单一工作流程中,我感到很痛苦,我喜欢 Linux 鼓励用户找到他们喜欢的工具。我曾使用过的应用大到套件(例如 LibreOffice 和 OpenOffice),小到轻量级文字处理器(如 Abiword),再到最小的文本编辑器(利用 Pandoc 进行转换)。不管我周围的用户被限制在什么范围内,我都可以 自由地使用可以在我的电脑上工作的最好的工具,并且以我希望的方式工作。选择Linux login screen开源最有价值的特性之一是用户在使用这些软件的时候是可以信任它的。这种信任来自于好友网络,他们可以阅读他们所使用的应用程序和操作系统的源代码。也就是说,即使你不知道源代码的好坏,你也可以在 开源社区 中结交一些知道的朋友。这些都是 Linux 用户在探索他们运行的发行版时建立的重要联系。如果你不信任构建和维护的发行版的社区,你可以去找其它的发行版。我们都是这样做的,这是有许多发行版可供选择的优势之一。Linux 提供了可选择的特性。一个强大的社区,充满了真实的人际关系,结合 Linux 提供的选择自由,所有这些都让用户对他们运行的软件有信心。因为我读过一些源码,也因为我信任哪些维护我没读过的代码的人,所以我信任 Linux。预算Skrooge做预算并不有趣,但是很重要。我很早就认识到,在业余时间做一些不起眼的工作,就像我学会了一种 免费 的操作系统(Linux!)一样。预算不是为了追踪你的钱,而是为了追踪你的习惯。这意味着无论你是靠薪水生活,还是正在计划退休,你都应该 保持预算。如果你在美国,你甚至可以用 Linux 来交税。艺术MyPaint不管你是画画还是做像素艺术、编辑视频 还是随性记录,你都可以在 Linux 上创建出色的内容。我所见过的一些最优秀的艺术作品都是使用一些非“行业标准”的工具随意创作出来的,并且你可能会惊讶于你所看到的许多内容都是基于同样的方式创造出来的。Linux 是一个不会被宣扬的引擎,但它是具有强大功能的引擎,驱动着独立艺术家和大型制作人。尝试使用 Linux 来创作一些艺术作品。编程NetBeans听着,用 Linux 来编程几乎是定论。仅次于服务器管理,开源和 Linux 是一个明显的组合。这其中有 许多原因,但我这里给出了一个有趣的原因。我在发明新东西时遇到了很多障碍,所以我最不希望的就是操作系统或者软件工具开发包(SDK)成为失败的原因。在 Linux 上,我可以访问一切,字面意义上的一切。封包Packaging GNOME software当他们在谈编程的时候,没有人谈封包。作为一个开发者,你必须将你的代码提供给您的用户,否则你将没有任何用户。Linux 使得开发人员可以轻松地 发布应用程序,用户也可以轻松地 安装这些应用程序。令很多人感到惊讶的是 Linux 可以像运行本地程序一样运行许多 Windows 应用程序。你不应该期望一个 Windows 应用可以在 Linux 上执行。不过,许多主要的通用应用要么已经在 Linux 上原生存在,要么可以通过名为 Wine 的兼容层运行。技术Data center如果你正在找一份 IT 工作,Linux 是很好的第一步。作为一个曾经为了更快地渲染视频而误入 Linux 的前艺术系学生,我说的是经验之谈。尖端技术发生在 Linux 上。Linux 驱动着大部分的互联网、世界上最快的超级计算机以及云本身。现在,Linux 驱动着 边缘计算,将云数据中心的能力与分散的节点相结合,以实现快速响应。不过,你不需要从最顶层开始。你可以学习在笔记本电脑或者台式机上自动完成任务,并通过一个 好的终端 远程控制系统。Linux 对你的新想法是开放的,并且可以进行定制。分享文件Beach with cloudy sky无论你是一个新手系统管理员,还是仅仅是要将一个将文件分发给室友,Linux 都可以使文件共享变得轻而易举。多媒体Waterfall在所有关于编程和服务器的讨论中,人们有时把 Linux 想象成一个充满绿色的 1 和 0 的黑屏。对于我们这些使用它的人来说,Linux 也能 播放你所有的媒体,这并不令人惊讶。易于安装CentOS installation以前从来没有安装过操作系统吗?Linux 非常简单。一步一步来,Linux 安装程序会手把手带你完成操作系统的安装,让你在一个小时内感觉到自己是个电脑专家。来安装 Linux 吧!试一试 LinuxPorteus如果你还没有准备好安装 Linux,你可以 试一试 Linux。不知道如何开始?它没有你想象的那么吓人。这里给了一些你 一开始需要考虑的事情。然后选择下载一个发行版,并想出你自己使用 Linux 的 21 个理由。到此,相信大家对“学Linux有什么用处”有了更深的了解,不妨来实际操作一番吧!这里是辰讯云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!...

这篇文章主要介绍了js如何实现秒表计时器功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。效果图: 下面贴代码:<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>计时器</title> <script>  var hour,minute,second;//时 分 秒  hour=minute=second=0;//初始化  var millisecond=0;//毫秒  var int;   function Reset()//重置   {    window.clearInterval(int);    millisecond=hour=minute=second=0;    document.getElementById('timetext').value='00时00分00秒000毫秒';   }     function start()//开始   {    int=setInterval(timer,50);   }     function timer()//计时   {    millisecond=millisecond+50;    if(millisecond>=1000)    {     millisecond=0;     second=second+1;    }    if(second>=60)    {     second=0;     minute=minute+1;    }      if(minute>=60)    {     minute=0;     hour=hour+1;    }    document.getElementById('timetext').value=hour+'时'+minute+'分'+second+'秒'+millisecond+'毫秒';     }     function stop()//暂停   {    window.clearInterval(int);   }  </script></head><body><div > <input type="text" id="timetext" value="00时00分00秒" readonly><br> <button type="button" onclick="start()">开始</button> <button type="button" onclick="stop()">暂停</button> <button type="button" onclick="Reset()">重置</button></div></body></html>感谢你能够认真阅读完这篇文章,希望小编分享的“js如何实现秒表计时器功能”这篇文章对大家有帮助,同时也希望大家多多支持辰讯云,关注辰讯云资讯频道,更多相关知识等着你来学习!...

小编给大家分享一下js怎么实现无限循环轮播图效果,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!知识要点1.实现无限循环的原理:以偏移的距离来判断是否跳回第一张和最后一张也可以利用循环判断图片的当前索引值var newLeft=parseInt(list.style.left)+offset;//当前的偏移量+下一次的偏移量=新的偏移量list.style.left=newLeft+"px";//当前的偏移值=新的偏移值//以偏移的距离来判断是否跳回第一张和最后一张if(newLeft>-600){  list.style.left=-3000+"px"; }if (newLeft<-3000){  list.style.left=-600+"px"; }2.当前图片轮播的圆点变色显示:因为每次点击index+1 所以当前的index-1就是button的索引//添加on前先清空onfor(var i=0;i<buttons.length;i++){  if(buttons[i].className=="on"){  buttons[i].className="";  break;  } } buttons[index-1].className="on";3.实现动画滚动效果:原理就是把每次的偏移量分为多次完成比如一次600px那就分为10次每次偏移60px就要用到setTimeout(go,10);//10毫秒再次调用go函数,一直到不满足条件就停var newLeft=parseInt(list.style.left)+offset;//当前的偏移量+下一次的偏移量=新的偏移量var time=300;//位移总时间var interval=10;//位移间隔时间//动画效果自定义公式: 每次位移的距离=单次偏移距离/位移次数var speed=offset/(time/interval);//递归函数 直到不满足条件(跳到辅助图)//递归就是把600偏移量分为多次完成偏移function go(){  //speed<0 并且 当前偏移量>下一次偏移量 就是向左偏移 || 反之向右偏移  if ((speed<0 &&parseInt(list.style.left)>newLeft) || (speed>0 &&parseInt(list.style.left)<newLeft)) {  list.style.left=parseInt(list.style.left)+speed+"px";//每次位移的值 setTimeout(go,interval);//10毫秒再次调用go函数 }else{  animated=false;  list.style.left=newLeft+"px";//当前的偏移值=新的偏移值 if(newLeft>-600){  list.style.left=-3000+"px";  }  if (newLeft<-3000){  list.style.left=-600+"px";  }  } }4.点击圆点按钮执行动画:原理获取当前的按钮位置再获取要点击的按钮的位置用(点击的——当前的)*-600=需要跳转的正负距离(向左或向右)for(var i=0;i<buttons.length;i++){  buttons[i].onclick=function(){  if(this.className=="on"){  return;  }  //要点击的index属性的值 转换为整数 var myIndex=parseInt(this.getAttribute("index"));  //偏移量=-600*(要点击的位置-当前所在的位置),当前的位置就是index循环所得 var os=-600*(myIndex-index);  //切换完成后,把点击的index位置变成当前的index位置  index=myIndex;  showButton();  if(!animated){  animate(os);  }  } }5.自动播放:给外层容器加个onmouseover事件再调用setInterval方法//给方法定义全局变量是因为停止的时候要使用function play(){  timer=setInterval(function(){  next.onclick();  },3000); } clearInterval(timer)完整代码注:图片链接本地替换一下<!DOCTYPE html><html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>demo</title><style>body,h2,h3,h4,h5,h6,h7,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{margin:0;padding:0;}h2,h3,h4,h5,h6,h7{font-size:100%;}address,cite,dfn,em,var{font-style:normal;}code,kbd,pre,samp{font-family:courier new,courier,monospace;}ul,ol{list-style:none;}a{text-decoration:none;}a:hover{text-decoration:none;}sup{vertical-align:text-top;}sub{vertical-align:text-bottom;}legend{color:#000;}fieldset,img{border:0;}button,input,select,textarea{font-size:100%;}table{border-collapse:collapse;border-spacing:0;}.clear{clear: both;float: none;height: 0;overflow: hidden;}#container{width: 600px; height: 400px; overflow: hidden; position: relative; }#list{width: 4200px; height: 400px; position: absolute; z-index: 1;}#list img{float: left;}#buttons { position: absolute; height: 10px; width: 100px; z-index: 2; bottom: 20px; left: 250px;}#buttons span { cursor: pointer; float: left; border: 1px solid #fff; width: 10px; height: 10px; border-radius: 50%; background: #333; margin-right: 5px;}#buttons .on { background: orangered;}.arrow { cursor: pointer; display: none; line-height: 39px; text-align: center; font-size: 36px; font-weight: bold; width: 40px; height: 40px; position: absolute; z-index: 2; top: 180px; background-color: RGBA(0,0,0,.3); color: #fff;}.arrow:hover { background-color: RGBA(0,0,0,.7);}#container:hover .arrow { display: block;}#prev { left: 20px;}#next { right: 20px;}</style> </head> <body> <div id="container"> <div id="list" > <img src="images/5.jpg" alt="5"/>     <img src="images/1.jpg" alt="1"/>  <img src="images/2.jpg" alt="2"/>  <img src="images/3.jpg" alt="3"/>  <img src="images/4.jpg" alt="4"/>  <img src="images/5.jpg" alt="5"/>  <img src="images/1.jpg" alt="1"/> </div> <div id="buttons">  <span index="1" class="on"></span>  <span index="2"></span>  <span index="3"></span>  <span index="4"></span>  <span index="5"></span> </div> <a href="javascript:;" id="prev" class="arrow">&lt;</a> <a href="javascript:;" id="next" class="arrow">&gt;</a> </div> <script type="text/javascript"> //在页面加载完后立即执行多个函数方案。 function addloadEvent(func){  var oldonload=window.onload;  if(typeof window.onload !="function"){   window.onload=func;  }  else{   window.onload=function(){   if(oldonload){    oldonload();    }   func();   }  }  }  //在页面加载完后立即执行多个函数方案结束。 addloadEvent(lbt);  //轮播图动画切换原理 function lbt(){  var container=document.getElementById("container");  var prev=document.getElementById("prev");  var next=document.getElementById("next");  var list=document.getElementById("list");  var buttons=document.getElementById("buttons").getElementsByTagName("span");  var imgs=list.getElementsByTagName("img");  var index=1;  var animated=false;  var timer;  //当前图片轮播的圆点变色显示,原理:index数值是跟随list滑动次数递增的,第一次index=1,所以第一个button的索引值就是0。 //for循环是添加on样式之前要清空之前的on。 function showButton(){  for(var i=0;i<buttons.length;i++){  if(buttons[i].className=="on"){  buttons[i].className="";  break;  }  }  buttons[index-1].className="on";  }  //圆点变色显示 结束。 function animate(offset){  animated=true;  var newLeft=parseInt(list.style.left)+offset;//当前的偏移量+下一次的偏移量=新的偏移量 var time=300;//位移总时间 var interval=10;//位移间隔时间 //动画效果自定义公式: 每次位移的距离=单次偏移距离/位移次数 var speed=offset/(time/interval);  //递归函数 直到不满足条件(跳到辅助图) //递归就是把600偏移量分为多次完成偏移 function go(){  //speed<0 并且 当前偏移量>下一次偏移量 就是向左偏移 || 反之向右偏移  if ((speed<0 &&parseInt(list.style.left)>newLeft) || (speed>0 &&parseInt(list.style.left)<newLeft)) {  list.style.left=parseInt(list.style.left)+speed+"px";//每次位移的值 setTimeout(go,interval);//10毫秒再次调用go函数 }else{  animated=false;  list.style.left=newLeft+"px";//当前的偏移值=新的偏移值 if(newLeft>-600){  list.style.left=-3000+"px";  }  if (newLeft<-3000){  list.style.left=-600+"px";  }  }  }  go();  }  //自动播放3秒执行一次next.onclick function play(){  timer=setInterval(function(){  next.onclick();  },3000);  }  function stop(){  clearInterval(timer);  }  //执行所有函数 next.onclick=function(){  if(index==5){  index=1;  }else{  index+=1;  }  showButton();  if(!animated){  animate(-600);  }  }  //执行所有函数 prev.onclick=function(){  if(index==1){  index=5;  }else{  index-=1;  }  showButton();  if(!animated){  animate(600);  }  }  //点击圆点按钮 偏移 for(var i=0;i<buttons.length;i++){  buttons[i].onclick=function(){  if(this.className=="on"){  return;  }  //要点击的index属性的值 转换为整数 var myIndex=parseInt(this.getAttribute("index"));  //偏移量=-600*(要点击的位置-当前所在的位置),当前的位置就是index循环所得 var os=-600*(myIndex-index);  //切换完成后,把点击的index位置变成当前的index位置  index=myIndex;  showButton();  if(!animated){  animate(os);  }  }  }  container.onmouseover=stop;  container.onmouseout=play;  play();  }  </script></body> </html>以上是“js怎么实现无限循环轮播图效果”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...

这篇文章主要为大家展示了“C++怎么实现超市商品管理系统最新版”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C++怎么实现超市商品管理系统最新版”这篇文章吧。一、问题描述及功能要求1.提供商品系统的添加、删除、编辑、显示等功能。2.同类系统多数使用结构体数组来操作数据,本系统使用链表结构操作数据,提高了数据处理的效率。二、代码实现 带有注释废话不说,直接代码,欢迎指正。大家CV可能有不兼容的情况,可以滴滴,尽可能解决问题地回复。#include <iostream>#include <string.h>#include <fstream>#include <conio.h>//用getch();using namespace std;//以下是类的设计class commodity{public:char name[20];char Id[20];int buy;//进货价;int sale;//卖出价;int amount;//数量;int sum;//利润;commodity * Next;void Input(){cout<<"\t\t请输入商品的名称:"; cin>>name;cout<<"\t\t请输入商品的编号:"; cin>>Id;cout<<"\t\t请输入进货价:"; cin>>buy;cout<<"\t\t请输入售出价:"; cin>>sale;cout<<"\t\t请输入商品数量:"; cin>>amount; sum=(sale-buy)*amount; }void ReadFile(istream & in){ in>>name>>Id>>sale>>buy>>sum; }void Show(){cout<<"商品名"<<name<<endl<<"编号:"<<Id<<endl<<"进货价"<<buy<<"售出价"<<sale<<"商品数量:"<< amount<<"预计总利润:"<<sum<<endl<<endl<<endl; } };//以下是对象或对象数组的定义//﹌﹌﹌﹌﹌﹌﹌﹌﹌Commoditymassage类﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌class Commoditymassage{public: Commoditymassage(); ~Commoditymassage();void ShowMenu();void Find();void Save();void ModifyItem();void RemoveItem();void Swap(commodity *,commodity *);void Sort();int ListCount();void Display(){for(commodity * p=Head->Next;p!=End;p=p->Next) p->Show();cout<<"输入任意字符!继续……"; getch(); }void AddItem(){ End->Input(); End->Next=new commodity; End=End->Next;cout<<"添加成功!"<<endl;cout<<"输入任意字符!继续……"; getch(); }private: commodity * Head,* End; ifstream in; ofstream out;commodity *FindItem(char * name){for(commodity * p=Head;p->Next!=End;p=p->Next)//匹配成功则返回上一个指针,不成功就返回空if(!strcmp(p->Next->name,name))return p;return NULL; }commodity *FindID(char * Id){for(commodity * p=Head;p->Next!=End;p=p->Next)//匹配成功则返回上一个指针,不成功就返回空if(!strcmp(p->Next->Id,Id))return p;return NULL; } };//﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌构造函数﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌Commoditymassage::Commoditymassage() { Head=new commodity; Head->Next=new commodity; End=Head->Next; in.open("sort.txt");if(!in)cout<<"无商品信息。请先输入。"<<endl;else{while(!in.eof()) { End->ReadFile(in);if(End->name[0]=='\0')break; End->Next=new commodity; End=End->Next; } in.close();cout<<"\t\t读取商品信息成功!"<<endl; } }//﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌析构函数﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌Commoditymassage::~Commoditymassage() { Save();for(commodity * temp;Head->Next!=End;) { temp=Head->Next; Head->Next=Head->Next->Next;delete temp; }delete Head,End; }//以下是主函数int main(){int x,i=0;bool quit=false;cout<<"\t\t**************************"<<endl;for(i=0;i<3;i++)cout<<"\t\t*\t\t\t\t\t\t *"<<endl;cout<<"\t\t*****【 欢迎进入超市商品管理系统 】*****"<<endl;for(i=0;i<3;i++)cout<<"\t\t◎\t\t\t\t\t\t ◎"<<endl;cout<<"\t\t**************************\n"<<endl;; Commoditymassage Grade;cout<<"按任意键开始……"; getch();while(!quit) { Grade.ShowMenu();cin>>x;switch(x) {case 0:quit=true;break;case 1:Grade.AddItem();break;case 2:Grade.Display();break;case 3:Grade.Sort();break;case 4:Grade.Find();break;case 5:Grade.RemoveItem();break;case 6:Grade.ModifyItem();break; } }return 0; }void Commoditymassage::ShowMenu(){cout<<"           超 市 商 品 管 理 系 统 "<<endl;cout<<"          ┌────-────┐"<<endl;cout<<"          │  1.增加超市商品 │"<<endl;cout<<"          │  2.显示超市商品 │"<<endl;cout<<"          │  3.排序统计商品 │"<<endl;cout<<"          │  4.查找超市商品 │"<<endl;cout<<"          │  5.删除超市商品 │"<<endl;cout<<"          │  6.修改超市商品 │"<<endl;cout<<"          │  0.安全退出系统 │"<<endl;cout<<"          └────────-┘"<<endl;cout<<"\n\t\t\n\t\t请选择:"; }//﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌查找函数﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌void Commoditymassage::Find(){char name[20] ,Id[10];int x; commodity * p=NULL;cout<<"\n\t\t*********************************\n";cout<<"\t\t※ 1.按商品的名称查找\n\t\t※ 2.按商品编号查找";cout<<"\n\t\t*********************************\n请选择:";cin>>x;switch(x) {case 1:{cout<<"\t\t请输入要查找的商品的名称:";cin>>name;if(p=FindItem(name)) { p->Next->Show();cout<<"输入任意字符!继续……"; getch(); }else{cout<<"\t\t没有找到该名称的商品!"<<'\n'<<endl;cout<<"输入任意字符!继续……"; getch(); } }break;case 2: {cout<<"\t\t请输入要查找的商品的编号:";cin>>Id;if(p=FindID(Id)) { p->Next->Show();cout<<"输入任意字符!继续……"; getch(); }else{cout<<"\t\t没有找到该编号的商品!"<<'\n'<<endl;cout<<"输入任意字符!继续……"; getch(); } }break; } }//﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌修改商品信息﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌void Commoditymassage::ModifyItem() //修改商品信息{char name[20]; commodity * p=NULL;cout<<"\t\t请输入要修改的商品的名称:";cin>>name;if(p=FindItem(name)) {cout<<"\t\t已找到商品的信息,请输入新的信息!"<<endl; p->Next->Input();cout<<"修改成功!"<<endl;cout<<"输入任意字符!继续……"; getch(); }else{cout<<"\t\t没有找到!"<<endl;cout<<"输入任意字符!继续……"; getch(); } }//﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌删除信息﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌void Commoditymassage::RemoveItem() // 删除信息{char name[20]; commodity * p=NULL,*temp=NULL;cout<<"\t\t请输入要删除的商品的名称:"<<endl;cin>>name;if(p=FindItem(name)) { temp=p->Next; p->Next=p->Next->Next;delete temp;cout<<"\t\t删除成功!"<<endl;cout<<"输入任意字符!继续……"; getch(); }else{cout<<"\t\t没有找到!"<<endl;cout<<"输入任意字符!继续……"; getch(); } }//﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌void Commoditymassage::Swap(commodity *p1, commodity *p2)//交换两个combox变量的数据域{ commodity *temp=new commodity;strcpy(temp->name,p1->name);strcpy(temp->Id,p1->Id); temp->sale=p1->sale; temp->buy=p1->buy; temp->sum=p1->sum;strcpy(p1->name,p2->name);strcpy(p1->Id,p2->Id); p1->sale=p2->sale; p1->buy=p2->buy; p1->sum=p2->sum;strcpy(p2->name,temp->name);strcpy(p2->Id,temp->Id); p2->sale=temp->sale; p2->buy=temp->buy; p2->sum=temp->sum; }//﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌int Commoditymassage::ListCount()//统计当前链表的记录总数,返回一个整数{if(! Head)return 0;int n=0;for(commodity * p=Head->Next;p!=End;p=p->Next) { n++; }return n; }//﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌void Commoditymassage::Sort()//对当前链表进行排序{cout <<"Sorting..."<<endl; commodity *p=NULL,*p1=NULL,*k=NULL;int n=Commoditymassage::ListCount();if(n<2)return;for(p=Head->Next;p!=End;p=p->Next)for(k=p->Next;k!=End;k=k->Next) {if(p->sum>k->sum) { Commoditymassage::Swap(p,k); } }cout <<"排序完成!"<<endl; getch();return; }//﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌保存函数﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌void Commoditymassage::Save(){ out.open("sort.txt");for(commodity *p=Head->Next;p!=End;p=p->Next) out<<p->name<<"\t"<<p->Id<<"\t"<<p->sum<<'\n'; out.close(); }以上是“C++怎么实现超市商品管理系统最新版”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...

这篇文章将为大家详细讲解有关js如何实现鼠标左右移动图片也跟着移动的效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。效果:鼠标往左移,图片对应右移,鼠标往右移,图片就左移动。图片距离越远偏移距离越大。思路:首先获取图片原先的距离。设置一个变化值,图片的最终距离等于原先的距离加上变化值布局:大盒子里面是图片,大盒子position:relative;图片position:absolute;<!doctype html><html><head><meta charset="utf-8"><title>无标题文档</title><style>body{margin:0;}#wrap{width:800px;height:500px;margin:30px auto; border:1px solid #000; position:relative;}#wrap img{ position:absolute;}#wrap img:nth-of-type(1){ left:200px;top:200px; z-index:0;}#wrap img:nth-of-type(2){ left:300px;top:180px; z-index:1;}#wrap img:nth-of-type(3){ left:100px;top:100px; z-index:2;}#wrap img:nth-of-type(4){ left:400px;top:110px; z-index:3;}</style></head><body><div id="wrap"> <img src="https://cache.yisu.com/upload/information/20200622/114/77545.jpg.editor.jpg" /> <img src="https://cache.yisu.com/upload/information/20200622/114/77546.jpg.editor.jpg" /> <img src="https://cache.yisu.com/upload/information/20200622/114/77547.jpg.editor.jpg" /> <img src="https://cache.yisu.com/upload/information/20200622/114/77547.jpg.editor.jpg" /></div><script>var oWrap=document.getElementById("wrap");var aImg=oWrap.getElementsByTagName("img");var iMax=4;//获取图片的初始位置for(var i=0;i<aImg.length;i++){  aImg[i].startX=parseInt(getStyle(aImg[i],'left')) } oWrap.onmousemove=function(ev){  ev=ev||window.event;  //获取鼠标的位置与大盒子中心点位置的距离 var iX=ev.clientX-(oWrap.offsetLeft+this.offsetWidth/2)  for(var i=0;i<aImg.length;i++){  //获取每个img的z-index var iZindex=getStyle(aImg[i],'zIndex')  //Zindex越大移动的相对距离越小 var iDisL=-parseInt(iX/iMax*(iMax-iZindex)/5)  //图片的距离等于原先的距离加上计算的距离 aImg[i].style.left=aImg[i].startX+iDisL+'px' } }function getStyle(obj,attr){  if( obj.currentStyle){  return obj.currentStyle[attr];   }  return getComputedStyle(obj)[attr];  }</script></body></html>关于“js如何实现鼠标左右移动图片也跟着移动的效果”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。...

Appium环境搭建详细过程

2021/6/19 21:24:31

这篇文章主要介绍“Appium环境搭建详细过程”,在日常操作中,相信很多人在Appium环境搭建详细过程问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Appium环境搭建详细过程”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!初识Appium的同学一定会被其复杂的环境搭建工作搞得头晕目眩,我相信有不少人因此就直接放弃了!本文我来讲解在Windows10  环境下Appium的环境搭建工作,请大家跟我一步步地下载各个软件(已附链接)并进行安装,相信一定会把Appium环境成功搭建。同时,我在文章中还会告诉大家为什么需要这么多软件,让大家了解其本质原因。安装Java jdk 1.8默认安装即可,https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html安装Android sdk大家可以直接下载android studio最新版本(https://developer.android.google.cn/studio),它同时包括Android IDE和Android  SDK,默认安装即可。完成安装后,会自动安装好Android sdk,默认安装路径是C:\Users\your  user\AppData\Local\Android\Sdk安装nodejs下载nodejs 最新版本http://nodejs.cn/,默认安装即可添加环境变量添加环境变量JAVA_HOME和ANDROID_HOME(注意:不要命名为其他变量名)JAVA_HOME指向jdk根目录ANDROID_HOME指向sdk根目录把下列变量添加到windows系统Path变量中%JAVA_HOME% ,% ANDROID_HOME %\tools, ,%ANDROID_HOME %\platform-tools,安装nodejs下载nodejs 最新版本http://nodejs.cn/,默认安装即可下载IDE所需jar包IDE: Eclipse (也可以使用前面下载的Android Studio)下载自动化测试开发所需的jar包,http://appium.io/downloads.html( 目前是:java-client-7.5.1-all.jar  ),下载完毕后引入到Java工程安装Appium Desktop下载Appium desktop并进行默认安装,下载地址https://github.com/appium/appium-desktop/releases/tag/v1.20.2-4备注:也可以通过npm install的方式进行安装(不推荐)解释说明至此,Appium环境搭建完毕,点击Appium.exe,就可以启动appium server了,如下所示:大家也许会问,为什么安装appium 会这么麻烦,需要安装这么多东东呢,在这里我来一一解释一下:1.因为appium操控android的app 需要使用安卓 sdk中的uiautmator,所以我们需要安装Android SDK;2.Android SDK 依赖于JDK,所以需要安装JDK;3.Appium 是用nodeJS 编写的,自然需要安装NodeJS4.添加变量JAVA_HOME和ANDROID_HOME是因为Appium Server的运行需要这两个变量,如下图所示:5.而java-client-7.5.1-all.jar  则是我们做自动化测试时需要的api,我们利用它就可以进行自动化测试的脚本开发了,如下所示:到此,关于“Appium环境搭建详细过程”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注辰讯云网站,小编会继续努力为大家带来更多实用的文章!...