nodejs项目周
nodejs前端框架 一般做中间层 和操作数据库
传统模式和前后端分离最大的区别就是seo优化
HTTP常见的服务器软件
Apache Nginx (iis)微软的服务器现在已经不怎么用了
node服务器 可以自己编写服务
个人练习
nodejs依赖安装
Express框架 提供一系列强大特性帮助你创建各种web应用
框架安装
cnpm install --save express
依赖安装
npm init 配制文件
npm install -g supervisor node自启动工具
启动命令 supervisor 文件名 自启工具命令
npm install --save ejs 摸板引擎安装
npm install body-parser --save 安装post接收的第三方模块
服务器
•服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。 •常见的HTTP服务器软件:Apache、Nginx、IIS。 •Node服务器:如果我们使用 PHP 来编写后端的代码时,需要 Apache 或者 Nginx 的 HTTP 服务器, 来处理客户端的请求响应。不过对 Node.js 来说,概念完全不一样了。使用 Node.js 时, 我们不仅仅在实现一个应用,同时还实现了整个 HTTP 服务器。
•1、引入 http 模块
var http=require("http"); •2、创建服务器 接下来我们使用 http.createServer() 方法创建服务器,并使用 listen 方法绑定 8888 端口。 函数通过 request, response 参数来接收和响应数据。
/* req(request):返回url信息 res(response):浏览器返回相应信息 */
http.createServer(function(req,res){//如果状态是200,文件类html,字符集是utf-8
res.writeHead(200,{"Content-Type":"text/html;charset=utf8"});
res.write("http://localhost:8888");
res.end();
}).listen(8888);
Express框架
Express是一个简洁而灵活的 node.js Web应用框架, 提供一系列强大特性帮助你创建各种Web应用
npm install --save express
淘宝镜像
$ npm install -g
$ npm install -g
cnpm --registry=https://registry.npm.taobao.org npm install //安装依赖
自启动工具 supervisor
1、首先安装 supervisor npm install -g supervisor
2、使用 supervisor 代替 node 命令启动应用 supervisor app.js
//引入express var express=require("express");
//实例化 var app=new express();
var host="localhost";
var port=8888;
app.get("/",function (req,res) { res.send("首页"); }); app.get("/news",function (req,res) { res.send("新闻"); }); //在控制台打印信息 console.log("http://"+host+":"+port); //监听 app.listen(port,host);
ejs
安装ejs npm install --save ejs
//引入express
var express=require("express");
var ejs = require('ejs'); //实例化
var app=new express();
var host="localhost";
var port=8888; //设置view层的目录 app.set("views",__dirname+"/pages"); //配置ejs模板扩展名 app.engine("html",ejs.__express); /*配置ejs模板引擎*/ app.set("view engine","html");
//配置静态资源库 app.use("/",express.static("static")); app.get("/",function (req,res) { res.render("index"); }); //在控制台打印信息 console.log("http://"+host+":"+port); //监听 app.listen(port,host);
//配置静态资源库 app.use("/",express.static("static")); app.get("/",function (req,res) { res.render("index"); }); //在控制台打印信息 console.log("http://"+host+":"+port); //监听 app.listen(port,host);
Express 是一个自身功能极简,完全是由路由和中间件构成一个的 web 开发框架:从 本质上来说,一个 Express 应用就是在调用各种中间件。
中间件的功能包括 :
1.执行任何代码。
2.修改请求和响应对象。
3.终结请求-响应循环。
4. 调用堆栈中的下一个中间件。
Express 中间件有以下几种:
1.应用级中间件
2.路由级中间件
3.错误处理中间件
4.内置中间件
5.第三方中间件
应用级中间件 : app.use(function (req,res,next) {//可以匹配任何路由 next();//继续往下执行 });
路由中间件 : //首页 app.get("/",function (req,res,next) { console.log(11); next(); });
内置中间件 : app.use("/",express.static("static"));
错误处理中间件 : app.use(function (req,res,next) { res.status(404).render('404',{}); });
第三方中间件 : //安装中间件 npm install body-parser –save //设置中间件 var bodyParser = require('body-parser') //支持request 中 body的 urlencoded字符,extended为false的时候,键值对中的值就为'String'或'Array'形式,为true的时候,则可为任何数据类型。 app.use(bodyParser.urlencoded({ extended: false })) //返回一个只解析json的中间件 app.use(bodyParser.json()) 最后用req.body 获取数据
•GET 请求的参数在 URL 中,在 Express 中,可以直接使用 req.query 对象。 •POST 请求在 express 中不能直接获得,可以使用 body-parser 模块。使用后,将可以用 req.body 得到参数。
•All 可以请求get和post
1、安装body-parser npm install --save body-parser
2、引用body-parser var bodyParser=require("body-parser");
3、设置body-parser //设置body模式为x-www-form-urlencoded模式 //当extended为false的时候,键值对中的值就为'String'或'Array'形式,为true的时候,则可为任何数据类型。为了安全性最好为extended=false app.use(bodyParser.urlencoded({extended:false})); app.use(bodyParser.json());//设置成json格式
req.query.id req.body.username接收
常用标签:
<%%>:流程控制标签
<%=%> :输出标签(原文输出HTML标签)
<%-%> :输出标签(HTML会被浏览器解析)
<%#%> :代码注释
<%- include ../public/left%> 相同标签内容的配置引用 后面是相对入径
<ul>
<% for(var i = 0 ; i < news.length ; i++){
%>
<li>
<%= news[i]
%></li>
<%
}
%>
</ul>
<%if type==1 %>
vip会员
<%else if type==0%>
普通会员 <%/if%>
Mongodb数据库
非关系型数据库是键和值对应的存储方式
关系型数据库的代表作品 sql
非关系型数据库代表作品 mongodb
复杂结构的逻辑基本都是sql免费开源
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,类似json格式,因此可以存储比较复杂的数据类型。
官网:https://www.mongodb.com/what-is-mongodb
手动启动:
1、mongod --dbpath="c:\mongodb\data"
2、mongo
关系型数据库与非关系型数据库的区别
NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是 SQL”,它指的是非关系型的数据库,是以 key-value 形式存储,和传统的关系型数据库不一样,不一定遵循传统数据库的一些基本要求,比如说遵循 SQL 标准 、表结构。它没有sql语句。
代表作:Redis、memcached、mongodb
什么时候建议使用 NoSql ?
1、对数据库高并发读写的需求
2、对海量数据的高效率存储和访问的需求
3、对数据库的高扩展性和高可用性的需求
NoSql 和传统数据库简单对比。
1. 非结构型数据库。没有行、列的概念。用 JSON 来存储数据。
2. 集合就相当于“表 ”,文档就相当于“行”。
1、Help 查看命令提示
db.help()
2、创建/切换数据库
use user
3、查询数据库
show dbs
4、查看当前数据库名
db
5、显示当前 DB 状态
db.stats()
6、查看当前 DB 版本
db.version()
7、查看当前 DB 的链接机器地址
db.getMongo()
8、删除数据库
db.dropDatabase()
1、创建一个聚集集合
db.createCollection(”name",{capped:false,size:100000000,max:5})
参数:
name:集合的名字
capped:是否启用集合限制,如果开启需要制定一个限制条件,默认为不启用,如果开启不能删除数据
size:限制集合使用空间的大小,默认为没有限制,size的优先级比max要高
max:集合中最大条数限制,默认为没有限制
autoIndexId:是否使用_id作为索引,默认为使用(true或false)
2、得到指定名称的聚集集合
db.getCollection("user")
3、得到当前 DB 的所有聚集集合
show tables
4、删除集合
db.user.drop()
1、插入文档 (可以直接创建集合相当于db.createCollection)
db.user.insert({name:”zhangsan",age:30})
2、获得当前 db 的所有文档
db.user.find()
3、更新文档
db.user.update({name:”zhangsan"},{$set:{name:”lisi",gender:'男'}});
4、删除文档
db.user.remove({name:”zhagnsan"})
5、条件查询
db.user.find({name:”zhagnsan”},{age:1,name:1})
第一个参数:条件查询。第二个参数:显示哪些字段,1:显示,0:不显示
6、模糊查询
db.user.find({name:/zhagnsan/}) //模糊查询,相当于sql的like '%user1%'
db.user.find({name:/^zhagnsan/}) //开头查询,相当于sql的like '%user1'
db.user.find({name:/zhagnsan$/}) //结尾查询,相当于sql的like 'user1%'
7、条件操作符
db.user.find({age:{$gt:5}}) 大于5数据就出来了
db.user.find({age:{$lt:5}});小于5的数据出来
db.user.find({age:{$lte:5}});小于等于5的数据
db.user.find({age:{$gte:5}});大于等于5的数据
db.user.find({age:{$ne:5}});不等于5的数据
db.user.find({_id:{$gt:5}}).limit(8); 大于5且只显示8条
2、 Limit 与 Skip 方法
db.user.find().limit(8);只显示8条数据
db.user.find().skip(8);跳过前面的8条数据
db.user.find().skip(1).limit(8);从第一条开始,每页显示8条数据,如果skip(9)且limt(8)则从第9条数据显示,每页显示8条数据,可以做分页。
3、排序
db.user.find().sort({age:1});升序
db.user.find().sort({age:-1});降序
4、索引
索引是做优化,让数据读取速度更快。一般条件查询频繁的字段设置索引。比如:_id,还有咱们刚才的age。
创建索引
db.user.createIndex({age:1});在age上建立索引1(升序),-1(降序),索引升序、降序和你的sort排序相关,如果升序和降序都要支持索引,那么就分别创建{age:1},{age:-1}
db.user.createIndex({age:1},{background:true});
当系统已有大量数据时,创建索引非常耗时,需在后台执行,只需指定“background:true”即可。
查看详细索引信息
db.user.getIndexes();
查看简单索引信息
db.user.getIndexKeys();
删除所有索引
db.user.dropIndexes()
删除指定索引
db.user.dropIndex({age:1})
导出:
使用mongodb自带导出工具mongoexport,在bin目录下面
mongoexport -d dbname -c collectionname -o file --type json/csv -f field
参数说明:
-d :数据库名
-c :collection名
-o :输出的文件名
--type : 输出的格式,默认为json
-f :输出的字段,如果-type为csv,则需要加上-f "字段名"
导入:
使用mongodb自带导入工具mongoimport ,在bin目录下面
mongoimport -d dbname -c collectionname --file filename --headerline --type json/csv -f field --jsonArray
参数说明:
-d :数据库名
-c :collection名
--file :要导入的文件
--type : 导入的格式,默认为json
-f :输出的字段,如果-type为csv,则需要加上-f "字段名"
--jsonArray:支持数组,如果出现Failed: error unmarshaling bytes on document #0: JSON decoder out of sync - data changing underfoot?使用这个参数试试
可视化工具robo3t
下载地址:https://robomongo.org/download
mongoose中间件
npm install --save mongoose
数据库连接状态
// 1、引入mongoose
var db=require(“mongoose”);
//2、 连接数据库
//useNewUrlParser:会在url里识别验证用户所需的db,未升级前不需要指定,升级一定要指定。
db.connect(“mongodb://localhost:27017/demodb”,{ useNewUrlParser: true });
//创建账号和密码连接
//db.connect(“mongodb://admin:123456@localhost:27017/demodb",{ useNewUrlParser: true });
// 连接失败
db.connection.on("error",function (err) {
console.error("数据库链接失败:"+ err);
});
//连接成功
db.connection.on("open",function () {
console.log("数据库连接成功");
});
//断开数据库
db.connection.on("disconnected",function () {
console.log("断开连接");
});
3、创建模型
var userSchema=new db. Schema({
name:{
type: String,//字段类型
trim:true //可以去除空格
},
age:{
type:Number ,
default:1
}
})
//字段名称必须和数据库里集合的字段一致
var userModel= db.model(”User",userSchema,”user");
第一个参数:User,第一个字母大写,数据库集合名必须是users,注意最后一个字母必须有个s,否则找不到集合。
第二个参数:传入Schema
第三个参数:如果数据库的集合没有后面的s,那么可以传入第三个参数必须和表名一致,比如表名为user,那么第三个参数是user
添加数据(比较特殊)
1、先实例化model
var um=new userModel({
name:”李四”,
age:30
});
um.save(function(err,data){
console.log(err,data);
})
查询数据
userModel.find({_id:111111},{_id:0,name:1,age:1},function(err,data){
console.log(err,data);
})
第一个参数查询的条件
第二个参数自定义显示字段,1:显示,0:不显示
删除数据
userModel.deleteOne({_id:111111},function(err,data){
console.log(err,data);
})
修改数据
userModel.updateOne({_id:111111},{name:”王五”,age:20},function(err,data){
console.log(err,data);
})
第一个参数:是要修改数据的条件
第二个参数:是修改的数据
使用multiparty实现文件上传
//配置文件上传的静态资源
app.use("/uploadfiles",express.static("uploadfiles"));
<form action="/reg/save" method="post" enctype="multipart/form-data">
头像上传:<input type="file" name="image" />
<button type="submit">注册</button>
</form>
支持文件上传:
1、form里面必须设置:enctype=”multipart/form-data”
2、input类型type=”file”
1、安装multiparty
npm install –save multiparty
2、引用multiparty
var multiparty=require('multiparty');
3、实例化multiparty并调用Form方法
var form=new multiparty.Form();
//设置文件存放目录
form.uploadDir=“uploadfiles”;
/*
err:是否有错误
fields:获取post字段名称
files:获取文件信息
*/
form.parse(req, function(err,fields,files){
console.log(err,fields,files);
});
1、安装express-session
npm install --save express-session
2、引入express-session
var session = require("express-session");
3、配置session
//配置中间件 固定格式
app.use(session({
secret: '1q2w3e4r',//secret是必需的选项,这是用于签名会话ID cookie的密钥,自己随便写。
resave: false,//resave是指每次请求都重新设置session cookie,如果为false:假设你的cookie是10分钟过期,每次请求都会再设置10分钟
saveUninitialized: true,//saveUninitialized是指无论有没有session cookie,每次请求都设置个session cookie
cookie: {
maxAge:1000*60*30//单位为毫秒,30分钟过期
},
rolling:true//强制在每一个response中都发送session标识符的cookie。
}));
设置session
req.session.username=”zhagnsan”;
获取session
req.session.username
安装:
npm install --save md5-node
使用:
1、引入md5-node
var md5=require("md5-node");
2、调用
md5('123456')
安装
npm install --save jsonwebtoken
JSON WEB TOKEN 简称JWT 标准的 Token 有三个部分:
header(头部)
{ "alg": "HS256", "typ": "JWT"}
alg:意思是这个 JWT 用的算法是 HS256
typ:类型是jwt
payload(数据)
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022}
signature(签名)
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload),secret )
中间用点分隔开,并且都会使用 Base64 编码,所以真正的 Token 看起来像这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
v
ar jwt=require(“jsonwebtoken”);
会员登录时创建token:
//token数据
var payload={
"iss":"demo.com",
"username":username};
//设置密钥
var token=jwt.sign(payload, ”123456”, {expiresIn:"1day"});//1day表示1天,如果设置30表示30秒
req.session.auth_token=token;
app.use(function (req,res,next) {
//将session缓存,存入到全局变量,可以让每个ejs模板使用
req.app.locals['isLogin']=req.session.isLogin;
req.app.locals['userInfo']=req.session.userInfo;
var search=req._parsedUrl.search?req._parsedUrl.search:"";//获取问号和参数
//用req.url获取当前页面的url路径,确定会员认证的页面
if(req.url=="/profile" || req.url=="/user"+search){
jwt.verify(req.session.auth_token,config.secret, function (err,dec) {
if (!err && req.session.isLogin){
next();
} else{
res.redirect(‘/login’);
}
});
}else{
next();
}
});
Restful接口是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
接口示例:
http://127.0.0.1/user/1 1代表id=1
特点:没有?和参数直接用/做分割传参
科大讯飞人脸识别接口:
http://tupapi.xfyun.cn/v1/face_score? image_url=xxxx&image_name=bbbbb
微信支付订单查询接口:
https://api.mch.weixin.qq.com/pay/orderquery?appid=wxd678efh567hg6787
Restful接口共性(所谓的标准):
1、让用接口的人看到url的地址就能猜到是干什么用的。
2、没有编程语言的扩展名,不知道使用什么编程语言开发,做了url重写,方便接口名称的统一性,后端更换开发语言,接口名称不变。
一、版本控制
https://api.example.com/v{n}
1、应该将API的版本号放入URL。
2、采用多版本并存,增量发布的方式。
3、n代表版本号,分为整型和浮点型
整型: 大功能版本, 如v1、v2、v3 ...
浮点型: 补充功能版本, 如v1.1、v1.2、v2.1、v2.2 ...
4、对于一个 API 或服务,应在生产中最多保留 3 个最详细的版本
保留 3 个最详细的版本说明
比如:jquery的版本号:1.7.2,1.12.4
第一个:重大版本更新,重构或改版,程序的功能和设计的板式重构。
第二个:补充升级,新增了一些功能。
第三个:bug修复
二、响应参数
{
status: 200, // 详见【status】
data: {
code: 1, // 详见【code】
data: {} || [], // 数据
message: '成功', // 存放响应信息提示,显示给客户端用户【须语义化中文提示】
sysMessage: 'success' // 存放响应信息提示,调试使用,中英文都行
... // 其它参数,如 total【总记录数】等
},
msg: '成功', // 存放响应信息提示,显示给客户端用户【须语义化中文提示】
sysMsg: 'success' // 存放响应信息提示,调试使用,中英文都行
}
【status】:
200: OK 400: Bad Request 500:Internal Server Error
401:Unauthorized
403:Forbidden
404:Not Found
面试必会状态码预览:http://www.lucklnk.com/godaddy/details/aid/148465578
【code】:
1: 获取数据成功 | 操作成功 0:获取数据失败 | 操作失败
Postman下载地址: https://www.getpostman.com/downloads/
json格式化校验地址:http://www.bejson.com/
cdn引入网址:https://cdnjs.com/
什么是跨域?
不符合同源策略就会出现跨域。常见跨域就是用ajax请求服务端接口。
什么是不符合同源策略?
1、协议不同(http or https等)
2、域名或ip地址不同
3、端口不同
解决跨域的方案:
1、使用jsonp解决
优点:暴力,简单。
缺点:不安全,只支持get,需要后端大量配合,无
法做到接口统一性,开发成本大。
应用场景:流量统计,比如第三方的百度统计
2、使用webpack做代理(vue、react等)
优点:不需要后端配合就可以跨域请求数据,做vue和react开发时必须配置。
缺点:只能在测试环境(开发者环境development)下跨域,正式环境(生成环境production)下面不能跨域。
应用场景:比如咱们在做开发,接口需要在测试环境下使用,等开发完成后正式上线前端和接口符合同源策略。这样的情况下后端是不会给你开启跨域功能。所以需要配置代理解决。
3、后端解决(最终解决方案)
方法一:
在路由拦截钩子函数中
app.use(function(req, res, next) {
//解决跨域
//*所有地址,指定地址:http:localhost:111
//指定多个地址:['http://localhost','http://localhost:111','http://www.baidu.com']
res.header(“Access-Control-Allow-Origin”, “*”);
next();
});
方法二:
cors解决跨域
1、引入cors
var cors = require('cors');
2、启用cors
app.use(cors(
{
origin:“*”, //指定接收的地址 ‘*’:所有地址,指定地址:[‘http:localhost:111’]
optionsSuccessStatus: 200 }
));
1、安装multiparty
npm install –save multiparty
2、引用multiparty
var multiparty=require('multiparty');
3、实例化multiparty
var form=new multiparty.Form();
//设置文件存放目录form.uploadDir=“uploadfiles”;
/*
err:是否有错误
fields:获取post字段名称
files:获取文件信息
*/
form.parse(req, function(err,fields,files){
console.log(err,fields,files);
});
1、引用jquery和jquery.form
<script src="../static/js/jquery.js"></script><script src="../static/js/jquery.form.js"></script>
var submitUrl=”http://localhost:3003/v1/product/upload";//服务端接口地址
var showImg=$("#show-img"),image=$("#image");
$("#form1").ajaxSubmit({
url:submitUrl,
type:"post",
dataType:"json",
beforeSend:function () {
console.log("上传中");
},
success:function (data) {
showImg.attr("src",data.data.showImg);
image.val(data.data.filePath);
}
})
SEO(Search Engine Optimization):汉译为搜索引擎优化。是一种方式:利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名。
什么是服务端渲染?
服务端渲染是先向后端服务器请求数据,然后生成完整html返回给浏览器。
优点:
1、更利于SEO
不同爬虫工作原理类似,只会爬取源码,不会执行网站的任何脚本(Google除外,据说Googlebot可以运行javaScript)。
2、更利于首屏渲染
首屏的渲染是node或php服务端发送过来的html字符串,并不依赖于js文件了,这就会使用户更快的看到页面的内容。尤其是针对大型单页应用,打包后文件体积比较大,普通客户端渲染加载所有所需文件时间较长,首页就会有一个很长的白屏等待时间。
缺点:
1、服务端压力较大
本来是通过客户端完成渲染,现在统一到服务端node服务去做。尤其是高并发访问的情况,会大量占用服务端CPU资源。
2、前后端不分离(传统模式开发)
由于前后端不分离,学习成本比较大,后端人员需要懂一些html+css+javascript。前端也要懂一些后端语言比如:php、java、node等。
1、title包含要优化的关键词,比如我要优化:网站建设
<title>北京网站制作|网站设计公司|高端网站建设-尚品中国</title>
|:作为关键词分隔符
-:后面是品牌词
2、keywords(关键词)和 description(描述)
<meta name=“keywords” content=“企业建站,互动网站建设,做网站,网站制作,网站建设,网站设计,北京网站建设,北京网站制作,北京网站设计,网站建设公司,网站制作公司,网站设计公司,企业网站建设,企业网站制作,公司网站建设” />
重点:包含你要优化的关键词,关键词要包含title的关键词。
<meta name=“description” content=“尚品中国隶属于恒久尚品网络科技(北京)有限公司,专注于网站制作、网站设计、高端网站建设、以企业建站、互动网站建设、做网站、北京网站建设公司、北京网站制作公司、北京网站设计公司、移动应用、创新技术、VI视觉设计为核心业务,成立于北京,是国内十佳品牌网站建设公司,以专业技术成就了数千精品网站成功案例供您赏析。” />
重点:描述里面包含title关键词和keywords关键词。
3、语义化标签
<header>:头部
<footer>:页脚
<nav>:导航
<aside>:标签一般使用在页面、文章的侧边栏、广告、友情链接等区域。
<article>:文章内容标签。包括标题、正文和脚注。
<strong>:加粗。强调标签。用于文章强调关键词。
<h1>:标题。用于定义文章的标题。(一个页面只能有一个h1标签)
npm install --save socket.io
const express = require(‘express’)
var app = express();
var server = require(‘http’).createServer(app);
//创建socket
var io = require('socket.io')(server);//链接
io.on('connection', function(socket){
//断开连接
socket.on("disconnect",function(data){
console.log("client disconnect",data);
});
//接收和发送数据
socket.on('all', function(data){
console.log(data);
io.emit('message', data)
})
})
server.listen(8000, function(){
console.log('服务器已启动:ws://localhost:8000')
})
1、引入socket.io.js
<script src="js/socket.io.js"></script>
2、链接服务端
var socket = io(“ws://localhost:8000”);
3、接收服务端数据
socket.on("message",function(data){
console.log(data);
})
4、发送数据到服务端
socket.emit('all', ”你好”);
5、断开socket
socket.close();
npm install --save node-httpclient
1、引入node-httpclient
var $=require(“node-httpclient”);
2、使用node-httpclient
$.ajax({
url: 'http://www.yourdomain.com/api',
type: 'GET',
success: function(data, status){
console.log(data, status);
}
});