资讯专栏INFORMATION COLUMN

慕课网_《如何使用高德云图在线制作属于你的地图》学习总结

k00baa / 1829人阅读

摘要:时间年月日星期日说明本文部分内容均来自慕课网。用户可以在服务器端调用云存储云检索从而构建自己的存储和检索服务,甚至可以制作自己的数据管理台。

时间:2017年08月13日星期日
说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com
教学源码:无
学习源码:https://github.com/zccodere/s...

第一章:云图产品介绍 1-1 云图产品介绍

什么是云图

一款让您,用自己的数据,做想要的地图的服务

使用场景

云图的服务与产品

云图为您提供制作自己地图的方法

方法1:在线制作您的地图
无须开发,用云图数据管理台导入或标注点信息,一键在线发布您的地图
云图数据管理台
方法2:开发您的地图
自主开发,用云图API/SDK服务,自主开发基于您的数据的地图或APP
 云图API、JavaScript云图API、Android/iOS云图SDK

如果用云图产品,做出什么样的地图

课程安排

手工操作:云图数据管理台:存储、编辑、更新您的数据&在线制作您的地图
服务端开发:云图API:云存储API介绍&开发实战(Java)详解
Web开发:JavaScript云图API:
    --如何使用数据图层进行Web应用开发
    --JS云图API开发&开发基于位置的通讯录(简单demo)
Android开发:Android云图SDK:如何在Android端检索及展示云图数据
iOS开发:iOS云图SDK开发:如何在iOS端检索及展示云图数据
第二章:云图数据管理台 2-1 云图数据管理台

云图数据管理台

可视化数据管理
在线发布地图平台
支撑自主开发

可实现功能

存储您的数据:导入excel/csv数据文件;上传图片信息;地图上标注
管理您的数据:编辑、更新、删除数据;点样式设置
在线发布地图:发布一个在线地图网页,多种模版(如附件模版、全量模版,更多敬请期待)
支持自主开发:
    --存储的数据供JavaScript云图API,Android云图SDK,iOS云图SDK调用,
    --自主开发基于自有数据的网站或APP;
    --设置API/SDK(keywords,filter,sortrule)参数生效的字段索引;

云图数据管理台用途

帮助文档

地址:http://lbs.amap.com/api/yuntu/guide/datamanager/datamanager/

在线发布您的地图实例-制作暖暖北京记忆旅游地图

制作步骤:

1.数据准备:

   数据excel和图片。

2.实际操作:

登录云图数据管理台
导入数据
编辑数据
删除数据
上传图片
点样式设置
发布

数据准备

素材请到我的github地址下载。

实际操作

注册、登录云图数据管理台
地址:http://yuntu.amap.com

新建地图

选择批量上传

完成数据导入后,进行图片上传

进行发布

共两种模版:全国模版和地区模版

第三章:Java云图API 3-1 开发讲解及实例

目录

云存储API、云检索API在云图中的定位
云存储API、云检索API的价值
云存储API介绍
云存储API实战

云存储API、云检索API在云图中的定位

云存储API、云检索API的价值

1.云存储API可以进行数据的增删改,用户可以进行批量的数据上传或数据的增删改。
2.云检索API可以对数据进行各种条件查询。
3.用户可以在服务器端调用云存储API、云检索API从而构建自己的存储和检索服务,
  甚至可以制作自己的数据管理台。
4.用户也可以在其它终端上调用云存储API、云检索API。

一般存储数据流程

推荐存储数据流程

云存储API的介绍

云存储API是HTTP型请求API,适用服务端、Web端、移动端实现云图的数据处理
数据读取和展示:通过云图数据管理台或云图API(JSAPI、移动端API、云检索API)
数据上传或存储:通过云图数据管理台或云存储API
JavaScript云图API、Android/iOS云图SDK当前仅提供数据检索功能以及数据的展现

云存储API实战-全国三甲医院在线管理系统

学习使用技术

1.开发语言:Java、Javascript
2.构建环境:Eclipse、Maven
3.开发框架:SpringBoot(后台)、Bootstrap(前台)

到开放平台获取key。

地址:http://lbs.amap.com/
路径:控制台》应用管理》我的应用》创建新应用》添加新key

云存储API接口文档

地址:http://lbs.amap.com/api/yuntu/reference/cloudstorage
创建表 
创建数据(单条) 
创建数据(批量) 
更新数据(单条) 
删除数据(单条/批量) 
批量创建进度查询 

创建名为yuntujava的maven项目pom文件如下


    4.0.0

    com.myimooc
    yuntujava
    0.0.1-SNAPSHOT
    jar

    yuntujava
    http://maven.apache.org

    
        org.springframework.boot
        spring-boot-starter-parent
        1.5.1.RELEASE
         
    

    
        UTF-8
        UTF-8
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.boot
            spring-boot-starter-freemarker
        
        
        
            com.alibaba
            fastjson
            1.2.36
        
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    1.8
                    1.8
                
            
        
    

完成后的项目结构如下

代码演示:

1.编写DemoController类

package com.myimooc.yuntujava.rest;

import java.util.Objects;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSONObject;

/**
 * 云存储API 和 云检索API
 * @author ZhangCheng on 2017-08-13
 */
@RestController
public class DemoController {
    private static final String KEY = "you key";
    private static final String API_CREAT_TABLE = "http://yuntuapi.amap.com/datamanage/table/create";
    private static final String API_DATA_CREATE = "http://yuntuapi.amap.com/datamanage/data/create";
    private static final String API_DATA_UPDATE = "http://yuntuapi.amap.com/datamanage/data/update";
    private static final String API_DATA_DELETE = "http://yuntuapi.amap.com/datamanage/data/delete";
    private static final String API_DATA_SEARCH_LOCAL = "http://yuntuapi.amap.com/datasearch/local";
    
    @Autowired
    private RestTemplate restTemplate;
    
    @GetMapping(value = {"","/","/index"})
    public ModelAndView index(){
        return new ModelAndView("index");
    }
    
    /**
     * 创建表
     */
    @PostMapping("/tablecreate")
    public Object tableCreate(String name){
        MultiValueMap reqParam = new LinkedMultiValueMap<>();
        reqParam.add("key", KEY);
        reqParam.add("name", name);
        JSONObject result = JSONObject.parseObject(restTemplate.postForObject(API_CREAT_TABLE, reqParam, String.class));
        if(Objects.equals("1", result.getString("status"))){
            return result;
        }
        return JSONObject.parseObject(restTemplate.postForObject(API_CREAT_TABLE, reqParam, String.class));
    }
    
    /**
     * 创建数据(单条)
     */
    @PostMapping("/datacreate")
    public Object dataCreate(String tableid,String name,String address){
        MultiValueMap reqParam = new LinkedMultiValueMap<>();
        reqParam.add("key", KEY);
        reqParam.add("loctype", "2");
        reqParam.add("tableid", tableid);
        JSONObject data = new JSONObject();
        data.put("_name", name);
        data.put("_address", address);
        reqParam.add("data", data.toString());
        JSONObject result = JSONObject.parseObject(restTemplate.postForObject(API_DATA_CREATE, reqParam, String.class));
        System.out.println(result);
        return result;
    }
    
    /**
     * 更新数据(单条)
     */
    @PostMapping("/dataupdate")
    public Object dataUpdate(String tableid,String id,String name,String address){
        MultiValueMap reqParam = new LinkedMultiValueMap<>();
        reqParam.add("key", KEY);
        reqParam.add("loctype", "2");
        reqParam.add("tableid", tableid);
        JSONObject data = new JSONObject();
        data.put("_id", id);
        data.put("_name", name);
        data.put("_address", address);
        reqParam.add("data", data.toJSONString());
        JSONObject result = JSONObject.parseObject(restTemplate.postForObject(API_DATA_UPDATE, reqParam, String.class));
        System.out.println(result);
        return result;
    }
    
    /**
     * 删除数据(单条)
     */
    @PostMapping("/datadelete")
    public Object dataDelete(String tableid,String ids){
        MultiValueMap reqParam = new LinkedMultiValueMap<>();
        reqParam.add("key", KEY);
        reqParam.add("tableid", tableid);
        reqParam.add("ids", ids);
        
        return JSONObject.parseObject(restTemplate.postForObject(API_DATA_DELETE, reqParam, String.class));
    }
    
    /**
     * 本地检索
     */
    @PostMapping("/datasearch")
    public Object dataSearch(String tableid,String keywords){
        String url = API_DATA_SEARCH_LOCAL+"?key="+KEY+"&tableid="+tableid+"&city=全国"+"&keywords="+keywords;
        return JSONObject.parseObject(restTemplate.getForObject(url, String.class));
    }
}

2.编写index.html类





云图管理














    

地图名称:

3.编写index.js类

var tableid="";

$(document).ready(function(){

    initTable();
    
    checkTable();
    
    // 查询按钮
    $("#btn_query").click(function(){
        dataSearch();
    });
    // 重置按钮
    $("#btn_reset").click(function(){
        $("#keywords").val(" ");
    });
    
    // 新增按钮
    $("#btn_add").click(function(){
        cleareditmodal();
        $("#edit_modal").modal("show");
    });
    // 修改按钮
    $("#btn_edit").click(function(){
        cleareditmodal();
        var datas = $("#table_data").bootstrapTable("getSelections");
        console.log(datas.length);
        if( datas.length == 0 ){
            showinfo("请选择您要修改的记录");
            return;
        }
        if( datas.length > 1){
            showinfo("修改功能不支持批量操作");
            return;
        }
        $("#edit_modal_id").val(datas[0]._id);
        $("#edit_modal_name").val(datas[0]._name);
        $("#edit_modal_address").val(datas[0]._address);
        $("#edit_modal").modal("show");
    });
    // 删除按钮
    $("#btn_delete").click(function(){
        
        var datas = $("#table_data").bootstrapTable("getSelections");
        console.log(datas.length);
        if( datas.length == 0 ){
            showinfo("请选择您要修改的记录");
            return;
        }
        if( datas.length > 1){
            showinfo("修改功能不支持批量操作");
            return;
        }
        var ids = datas[0]._id;
        datadelete(ids);
        $("#table_data").bootstrapTable("removeByUniqueId",ids);
    });
    // 地图编辑-确定按钮
    $("#table_modal_save").click(function(){
        getTableInfo();
    });
    // 数据编辑-确定按钮
    $("#edit_modal_save").click(function(){
        var id= $("#edit_modal_id").val();
        var name = $("#edit_modal_name").val();
        var address = $("#edit_modal_address").val();
        if(!name){
            showinfo("请输入名称");
            return;
        }
        if(!address){
            showinfo("请输入地址");
            return;
        }
        if(!id){
            datacreate();// 新增
        }else{
            dataupdate();// 修改
        }
        $("#edit_modal").modal("hide");
    });
});
function cleareditmodal(){
    $("#edit_modal_id").val("");
    $("#edit_modal_name").val("");
    $("#edit_modal_address").val("");
}

function showinfo(info){
    $("#info_modal").modal("show");
    $("#info_modal_span").html(info);
    setTimeout(function(){$("#info_modal").modal("hide")},1500);
}

function datacreate(){
    var request_data = {
        "tableid":tableid,
        "name":$("#edit_modal_name").val(),
        "address":$("#edit_modal_address").val()
    }
    console.log(request_data);
    var request_url = "/datacreate";
    $.ajax({
        type: "post",
        url: request_url,
        contentType: "application/x-www-form-urlencoded; charset=utf-8",
        async: true,
        data: request_data,
        crossDomain: true == !(document.all),
        success: function(data) {
            if ("1" == data.status) {
                dataSearch();
            } else {
                showinfo(data.info);
            }
        },
        error: function() {
            showinfo("数据创建Ajax请求失败!");
        }
    });
}

function dataupdate(){
    var request_data = {
        "tableid":tableid,
        "id":$("#edit_modal_id").val(),
        "name":$("#edit_modal_name").val(),
        "address":$("#edit_modal_address").val(),
    };
    var request_url = "/dataupdate";
    $.ajax({
        type: "post",
        url: request_url,
        contentType: "application/x-www-form-urlencoded; charset=utf-8",
        async: true,
        data: request_data,
        crossDomain: true == !(document.all),
        success: function(data) {
            if ("1" == data.status) {
                dataSearch();
            } else {
                showinfo(data.info);
            }
        },
        error: function() {
            showinfo("数据修改Ajax请求失败!");
        }
    });
}

function datadelete(ids){
    var request_data = {
        "tableid":tableid,
        "ids":ids
    };
    var request_url = "/datadelete";
    $.ajax({
        type: "post",
        url: request_url,
        contentType: "application/x-www-form-urlencoded; charset=utf-8",
        async: true,
        data: request_data,
        crossDomain: true == !(document.all),
        success: function(data) {
            if ("1" == data.status) {
                
            } else {
                showinfo(data.info);
            }
        },
        error: function() {
            showinfo("数据删除Ajax请求失败!");
        }
    });
}

/**
 * 地图编辑
 */
function getTableInfo(){
    var table_name = $("#table_modal_name").val();
    if(!table_name){
        showinfo("请输入地图名称");
        return;
    }
    var request_data = {
        "name":table_name,
    };
    var request_url = "/tablecreate";
    $.ajax({
        type: "post",
        url: request_url,
        contentType: "application/x-www-form-urlencoded; charset=utf-8",
        async: true,
        data: request_data,
        dataType: "json",
        crossDomain: true == !(document.all),
        success: function(data) {
            if ("1" == data.status) {
                tableid = data.tableid;
                $("#table_span_id").attr("no",tableid);
                $("#table_span_id").html(table_name);
                $("#table_modal").modal("hide");
            } else {
                showinfo(data.info);
            }
        },
        error: function() {
            showinfo("地图名称Ajax请求失败!");
        }
    });
}

function checkTable(){
    var table_id = $("#table_span_id").attr("no");
    if(!table_id){
        console.log("tableid为空");
        $("#table_modal").modal("show");
    }else{
        tableid = table_id;
        console.log("tableid为:"+table_id);
        dataSearch();
    }
}

/**
 * 数据查询
 */
function dataSearch(){
    var keywords = $("#keywords").val();
    if(!keywords){
        keywords = " ";
    }
    var request_data = {
            "tableid":tableid,
            "keywords":keywords
        }
        console.log(request_data);
        var request_url = "/datasearch";
        $.ajax({
            type: "post",
            url: request_url,
            contentType: "application/x-www-form-urlencoded; charset=utf-8",
            async: true,
            data: request_data,
            crossDomain: true == !(document.all),
            success: function(data) {
                if ("1" == data.status) {
                    console.log(data);
                    $("#table_data").bootstrapTable("load", data.datas);
//                    tableid = data.tableid;
//                    $("#table_span_id").attr("no",tableid);
//                    $("#table_span_id").html(table_name);
//                    $("#table_modal").modal("hide");
                } else {
                    showinfo(data.info);
                }
            },
            error: function() {
                showinfo("数据加载Ajax请求失败!");
            }
        });
}
/**
 * 初始化表格
 */
function initTable() {
    $("#table_data").bootstrapTable({
        toolbar: "#toolbar",                //工具按钮用哪个容器
        cache: false,                       //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)
        pagination: true,                   //是否显示分页(*)
        sortable: false,                     //是否启用排序
        sortOrder: "asc",                   //排序方式
        sidePagination: "client",           //分页方式:client客户端分页,server服务端分页(*)
        pageNumber:1,                       //初始化加载第一页,默认第一页
        pageSize: 10,                       //每页的记录行数(*)
        pageList: [5, 10, 25, 50, 100],        //可供选择的每页的行数(*)
        showColumns: true,                  //是否显示所有的列
        showRefresh: true,                  //是否显示刷新按钮
        clickToSelect: true,                //是否启用点击选中行
        uniqueId: "_id",                     //每一行的唯一标识,一般为主键列
        columns: [{
            checkbox: true
        }, {
            field: "_id",
            title: "ID"
        }, {
            field: "_name",
            title: "名称"
        }, {
            field: "_address",
            title: "地址"
        }, {
            field: "_province",
            title: "省市"
        }, {
            field: "_city",
            title: "城市"
        }, {
            field: "_district",
            title: "地区"
        }, {
            field: "_location",
            title: "坐标"
        }, {
            field: "_createtime",
            title: "创建时间"
        },{
            field: "_updatetime",
            title: "上一次修改时间"
        }]
    });
}

效果图

第四章:JavaScript云图API 4-1 开发知识讲解(上)

如何使用云数据图层进行Web应用开发-目录

何为图层
何为云数据图层
云数据图层接口说明

何为图层

图层为一组绘制的地物(点、线、面),比如常见的有
各种POI图层(点数据)
有实时交通图层(线数据)
行政区划图层(面数据)
基础图层(点线面综合数据)

图层详解

电子地图就是由多个图层组成的图层集合
电子地图包括基础图层和叠加图层两种图层
基础图层通常描述基本的路网信息和基本的地物信息,作为展示电子地图的基础
叠加图层是叠加在基础图层上展示的图层,通常用于某些专题内容的展示
而叠加图层可以相互叠加展示
对某层的操作不会影响其它层,并能增加删除影藏图层

示例图

从数据结构的角度看,图层还会分为栅格图层和矢量图层

栅格图层
栅格结构是地理数据划分成若干行、若干列,成为一个像素阵列,其最小单元为像素
优点:结构简单,易于数据交换,输出快速,成本低廉
缺点:图像识别效果不如矢量,难以表达拓扑关系,图像数据量大
矢量图层
矢量结构是用一系列有序的x、y坐标对表示地理实体的空间位置
优点:结构紧凑,冗余度低,便于描述线和边界,精度高
缺点:数据结构复杂,不便于数据标准化和规范化,数据交换困难,显示与绘制成本较高

示例图

图层的绘制(渲染)流程

预渲染
实时渲染

预渲染

从数据库中取出数据进行批量的离线绘制,制作程栅格瓦片或矢量瓦片存储在缓存服务器上,客户端读取图层数据时从缓存服务器读取事先绘制好的数据。读取熟读快,数据更新缓慢(一般以月或季度为单位更新一次),不能实时反映数据的动态变化。

实时渲染

根据客户端读取数据的条件直接绘制,不进行预先的数据生产,实时反馈最新的数据。读取速度较预渲染会慢(每次都会从库中读物并且重新绘制),但是实时反映数据变化。

云数据图层

云数据图层是高德LBS开放平台API中的一个特殊的图层,属于云图API的一部分
为了快速实时展示用户所设定的海量数据点而设计的
    快速实时:云数据图层利用的实时渲染原理,实时反映用户数据的最新情况
    海量数据点:云数据图层使用的是栅格瓦片技术,能够在服务端快读生成海量最新数据的栅格图像,
    客户端低端配置也可以轻松显示海量数据。同时为了解决栅格数据地物识别困难的问题,
    使用了一种特殊的描述栅格内容的技术,使云数据图层也能够精确地识别所有的地物数据。
    用户设定:由于是实时渲染,所以云数据图层为用户提供了各种过滤数据的条件,
    使用户能得到自己想要的定制数据。

同时云数据图层是高德地图API里的一个图层,所以它可以和API的其他组件和功能结构使用

可以和其它图层叠加展示
可以和覆盖物层结合使用
支持各种交互事件,可以做各种数据的详细展示
可以和其它API结合等等

云数据图层示意图

云数据图层接口说明

4-2 开发知识讲解(下)

云数据图层示例

使用过程演示

1.数据准备

素材可到我的github地址下载

2.数据导入

登录云图数据管理台,创建一个地图,并导入数据。数据导入完成后如下

添加medicalspecialists字段索引

3.效果预览

点击分享,查看效果预览

4.代码编写

在代码里写一个在线的web页面,来做一个小小的查询使用的web应用

源代码如下:





全国三甲医院查询系统






    

全国三甲医院查询系统(数据来源于网络,仅供参考)
全部三甲医院 内科 外科 妇科 眼科 耳鼻喉科 儿科 口腔科 皮肤科 骨科 中医 针灸推拿 心理咨询 肿瘤科 心血管科 消化科 泌尿科 肝肠科 肝病科 性病科 肾病科 呼吸内科

第五章:JavaScript云图API实战 5-1 通讯录实战(上)

课程大纲

云图
    AMap
    CloudDataLayer 云数据图层
    CloudDatatSearch 云数据空间检索服务
建议
    如果没有JS-API开发经验,可以提前了解下JS-API或者学习《JS-API公开课》
    了解云图的原理
接口文档
    地址:http://lbs.amap.com/api/javascript-api/reference/cloudlayer

云图JS-API简介

实战案例-武侠通讯录

武侠通讯录-步骤

1.获取Key

地址:http://lbs.amap.com/dev/key/app

2.创建地图

创建地图,并导入通讯录数据,或标注数据

地址:http://yuntu.amap.com/dataman...

5-2 通讯录实战(下)

代码演示:




    
    
    
    武侠通讯录
    
    
    
    


参考资料

接口文档:http://lbs.amap.com/api/javascript-api/summary
相关示例:http://lbs.amap.com/api/javascript-api/example/map/map-show/

第六章Android云图SDK和第七章iOS云图SDK讲解,因个人开发方向及条件限制,这里就没有内容了。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70190.html

相关文章

  • 课网_如何使用高德云图在线制作属于你的地图学习总结

    摘要:时间年月日星期日说明本文部分内容均来自慕课网。用户可以在服务器端调用云存储云检索从而构建自己的存储和检索服务,甚至可以制作自己的数据管理台。 时间:2017年08月13日星期日说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学源码:无学习源码:https://github.com/zccodere/s... 第一章:云图产品介绍 1-1 云图产品介绍...

    afishhhhh 评论0 收藏0
  • 课网_《一起来做价值百万的Apple Watch App:分歧终端机》学习总结

    摘要:时间年月日星期一说明本文部分内容均来自慕课网。慕课网教学示例源码个人学习源码第一章课程简介下载课程简介制作一个猜拳游戏,剪刀石头布。 时间:2017年05月22日星期一说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学示例源码:https://github.com/zccodere/s...个人学习源码:https://github.com/zcco...

    oysun 评论0 收藏0
  • 课网_《第一个docker化的java应用》学习总结

    摘要:时间年月日星期四说明本文部分内容均来自慕课网。仓库构建镜像的目的是为了在其机器上运行镜像程序。使用参数,冒号前面为主机端口,后面为容器端口。 时间:2017年04月27日星期四说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学示例源码:无个人学习源码:无 第一章:课程介绍 1-1 课程介绍 Docker能火的原因 快速的持续集成 服务的弹性伸缩 部署...

    李涛 评论0 收藏0
  • 课网_《第一个docker化的java应用》学习总结

    摘要:时间年月日星期四说明本文部分内容均来自慕课网。仓库构建镜像的目的是为了在其机器上运行镜像程序。使用参数,冒号前面为主机端口,后面为容器端口。 时间:2017年04月27日星期四说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学示例源码:无个人学习源码:无 第一章:课程介绍 1-1 课程介绍 Docker能火的原因 快速的持续集成 服务的弹性伸缩 部署...

    vvpvvp 评论0 收藏0
  • 课网_《Java生成二维码》学习总结

    摘要:时间年月日星期五说明本文部分内容均来自慕课网。线性堆叠式二维码示意图矩阵式二维码在一个矩形空间通过黑白像素在矩阵中的不同分布进行编码。 时间:2017年06月23日星期五说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学示例源码:无个人学习源码:https://github.com/zccodere/s... 第一章:二维码的概念 1-1 二维码概述...

    QLQ 评论0 收藏0

发表评论

0条评论

k00baa

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<