• [技术干货] 详解npm脚本和package.json
    npm是什么npm是前端开发广泛使用的包管理工具,它让js开发者分享、复用代码更方便。可以重复的框架代码被称为包(package)或者模块(module),一个包可是是一个文件夹里放着几个文件夹,还有一个package.json文件。1、什么是npm脚本  在创建node.js项目如一个vue项目,或一个react项目时,项目都会生成一个描述文件package.json 。比如npm允许在package.json文件里面,使用scripts字段定义脚本命令。1234567891011{//..."scripts": { "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", "start": "npm run dev", "e2e": "node test/e2e/runner.js", "test": "npm run e2e", "lint": "eslint --ext .js,.vue src test/e2e/specs", "build": "node build/build.js" },}  上面代码是package.json文件的一个片段,里面的scripts字段是一个对象。它的每一个属性,对应一段脚本。比如,build命令对应的脚本是node build.js 。  命令行下使用npm run 命令,就可以执行这段脚本。$ npm run build  等同于执行:$ node build/build.js  同理,上面的那段scripts中, npm run test 等同于 npm run e2e , 等同于 node test/e2e/runner.js  这些定义在package.json里面的脚本,就称为npm脚本。项目的相关脚本,可以集中在一个地方;不同项目的脚本命令,只要功能相同,就可以有同样的对外接口。比如用户不需要知道怎么测试你的项目,只要运行 npm run dev 即可  查看当前项目的所有npm脚本命令,可以使用不带任何参数的 npm run 命令。$ npm run2、npm原理  npm脚本的原理非常简单。每当执行 npm run ,就会自动创建一个shell脚本, 在这个shell里面执行指定的脚本命令。因此,只需要是shell (一般是bash) 可以运行的命令,就可以写在npm脚本里面。  比较特别的是,npm run 新建的这个shell, 会将当前目录的node_modules/.bin 子目录加入PATH 变量,执行结束后,再将PATH变量恢复原样。还意味着,当前目录的node_modules/.bin 子目录里面的所有脚本,都可以直接用脚本名调用,而不必加上路径。比如,当前项目的依赖里面有Mocha, 只要直接写 mocha test 就可以了。"test": "mocha test"  而不用写成下面这样。"test": "./node_modules/.bin/mocha test"  由于npm脚本的唯一要求就是可以在shell中执行,因此它不一定是Node脚本,任何可执行文件都可以写在里面。npm脚本的退出码,也遵守shell脚本规则。如果退出码不是0,npm 就认为这个脚本执行失败。3、通配符  由于npm脚本就是shell脚本,因此可以使用shell通配符。12"lint": "jshint *.js""lint": "jshint **/*.js"  上面代码中,* 表示任意文件名,**表示任意一层子目录。如果要将通配符传入原始命令,防止被shell转义,要将*号转义。"test": "tap test/\*.js"4、传参  向npm脚本传入参数,要使用 -- 标明。"lint": "jshint **.js"  向上面的 npm run lint 命令传入参数,必须写成下面这样。1$ npm run lint -- --reporter checkstyle > checkstyle.xml 也可以再package.json里面封装一个命令。12"lint": "jshint **.js","lint:checkstyle": "npm run lint -- --reporter checkstyle > checkstyle.xml"5、执行顺序  如果npm脚本里面需要执行多个任务,那么需要明确它们的执行顺序。如果是并行执行(即同时的平行执行),可以使用 & 符号。$ npm run script1.js & npm run script2.js  如果是继发执行(即只有前一个任务成功,才能执行下一个任务),可以使用 && 符号。$ npm run script1.js && npm run script2.js6、默认值  一般来说,npm脚本由用户提供。但是,npm对两个脚本提供了默认值。也就是说,这两个脚本不用定义,就可以直接使用。12"start": "node server.js","install": "node-gyp rebuild"  上面代码中,npm run start 的默认值是 node server.js, 前提是项目根目录下有server.js这个脚本;npm run install 的默认值是node-gyp rebuild, 前提是项目根目录下有binding.gyp文件。7、钩子  npm脚本有pre何post两个钩子。举例来说,build脚本命令的钩子就是prebuild和postbuild。123"prebuild": "echo I run before the build script","build": "cross-env NODE_ENV=production webpack","postbuild": "echo I run after the build script"  用户执行npm run build的时候,会自动按照下面的顺序执行。1npm run prebuild && npm run build && npm run postbuild  因此,可以在这两个钩子里面,完成一些准备工作和清理工作。下面是一个例子:123"clean": "rimraf ./dist && mkdir dist","prebuild": "npm run clean","build": "cross-env NODE_ENV=production webpack" npm默认提供下面的这些钩子:12345678prepublish,postpublishpreinstall,postinstallpreuninstall,postuninstallpreversion,postversionpretest,posttestprestop,poststopprestart,poststartprerestart,postrestart  自定义的脚本命令也可以加上pre和post钩子。比如,myscript这个脚本命令,也有premyscript和postmyscript钩子。不过,双重的pre和post无效,比如prepretest和postposttest是无效的。  npm提供一个npm_lifecycle_event变量,返回当前正在运行的脚本命令,比如pretest、test、posttest等等。所以,可以利用这个变量,在同一个脚本文件里面,为不同的npm scripts命令编写代码。请看下面的例子:12345678910111213const TARGET = process.env.npm_lifecycle_event; if (TARGET === 'test') { console.log(`Running the test task!`);} if (TARGET === 'pretest') { console.log(`Running the pretest task!`);} if (TARGET === 'posttest') { console.log(`Running the posttest task!`);}  注意,prepublish这个钩子不仅会在npm publish 命令之前运行,还会在npm install (不带任何参数)命令之前运行。这种行为很容易让用户感到困惑,所以npm 4引入了一个新的钩子prepare, 行为等同于prepublish, 而从npm 5开始,prepublish 将只在npm publish命令之前运行。8、简写形式  四个常用的npm脚本有简写形式。npm start 是 npm run start 的简写 npm stop 是 npm run stop 的简写 npm test 是 npm run test 的简写 npm restart 是 npm run stop && npm run restart && npm run start 的简写  npm start 、npm stop、npm restart都比较好理解,而npm restart 是一个复合命令,实际上会执行三个脚本命令:stop、restart、start 。具体的执行顺序如下:prerestart prestop stop poststop restart prestart start poststart postrestart9、变量  npm脚本有一个非常强大的功能,就是可以使用npm的内部变量。首先,通过npm_package_ 前缀,npm脚本可以拿到package.json里面的字段。比如,下面是一个package.json。1234567{ "name": "foo",  "version": "1.2.5", "scripts": { "view": "node view.js" }}那么,变量npm_package_name返回foo, 变量npm_package_version返回 1.2.5 。123// view.jsconsole.log(process.env.npm_package_name); // fooconsole.log(process.env.npm_package_version); // 1.2.5  上面代码中,我们通过环境变量process.env 对象,拿到package.json 的字段值。如果是bash脚本,可以用$npm_package_name和$npm_package_version娶到这两个值。npm_package_ 前缀也支持嵌套的package.json字段。1234567"repository": {"type": "git","url": "xxx"},scripts: {"view": "echo $npm_package_repository_type"}  上面代码中,repository字段的type属性,可以通过 npm_package_repository_type取到。下面是另外一个例子:123"scripts": { "install": "foo.js"}  上面代码中,npm_package_scripts_install变量的值等于foo.js 。  然后,npm 脚本还可以通过npm_config_ 前缀,拿到npm的配置变量,即npm config get xxx 命令返回的值。比如,当前模块的发行标签,可以通过npm_config_tag取到。"view": "echo $npm_config_tag",  注意,package.json里面的config对象,可以被环境变量覆盖。12345{  "name" : "foo", "config" : { "port" : "8080" }, "scripts" : { "start" : "node server.js" }}  上面代码中,npm_package_config_port 变量返回的是8080。这个值可以用下面的方法覆盖。$ npm config set foo:port 80  最后,env命令可以列出所有环境变量。"env": "env"10、常用脚本示例1234567891011121314151617181920212223242526// 删除目录"clean": "rimraf dist/*", // 本地搭建一个 HTTP 服务"serve": "http-server -p 9090 dist/", // 打开浏览器"open:dev": "opener http://localhost:9090", // 实时刷新 "livereload": "live-reload --port 9091 dist/", // 构建 HTML 文件"build:html": "jade index.jade > dist/index.html", // 只要 CSS 文件有变动,就重新执行构建"watch:css": "watch 'npm run build:css' assets/styles/", // 只要 HTML 文件有变动,就重新执行构建"watch:html": "watch 'npm run build:html' assets/html", // 部署到 Amazon S3"deploy:prod": "s3-cli sync ./dist/ s3://example-com/prod-site/", // 构建 favicon"build:favicon": "node scripts/favicon.js",11、package.json其他配置项说明对于dependencies和devDependencies的一些说明:  使用npm安装依赖时,如果使用--save安装的依赖,会被写到dependencies模块里面去;  而使用--save-dev安装的依赖,则会被写到devDependencies模块里面去;如果什么都不写,则默认安装到dependencies里面去。  比如我们使用的一些构建工具例如glup、webpack这些只在开发环境中才用到的包,则只需要写到devDependencies中即可。  对于两种环境的指定方式,则是通过配置文件中的 process.env.NODE_ENV = 'development' 或 process.env.NODE_ENV = 'production' 来指定是开发还是生产环境。12、package.json中的bin属性  package.json中的bin是命令名和本地文件的映射。如果是全局安装,则会把文件映射到全局的bin里面去,安装后,在任意地方打开终端使用命令行执行该文件;如果是本地安装,则会把文件映射到本项目的./node_modules/.bin文件夹里面,安装后,在本工程目录里面使用命令行执行该文件。  举例说明:新建一个文件夹,打开终端,进入该文件夹,通过命令 npm init -y 创建一个package.json文件。然后在package.json文件同级目录下新建一个index.js文件,加上测试数据。注意,index.js文件的头部必须有这个 #!/usr/bin/env node 节点。在package.json中增加bin属性,设置命令名和index.js的映射关系。在终端当前目录中进行全局安装: npm install -g 安装成功后,则在电脑任意文件夹打开终端,执行package.json中bin中设置的命令,都会执行对应的index.js中的代码。 如下图
  • [干货汇总] 聊聊如何在华为云IoT平台进行产品开发
    本文分享自华为云社区《[如何基于华为云IoT物联网平台进行产品开发](https://bbs.huaweicloud.com/blogs/349684?utm_source=csdn&utm_medium=bbs-ex&utm_campaign=iot&utm_content=content)》,作者: Super.雯 。 华为云物联网平台承载着南北向数据互通的功能职责。在华为云物联网平台基础上实现端到端物联网业务的过程中,开发者需要基于该平台进行二次开发。本文先跟大家一起聊一聊产品开发。 # 产品开发 在物联网平台集成解决方案中,物联网平台作为承上启下的中间部分,向应用服务器开放API接口,向各种协议的设备提供API对接。为了提供更加丰富的设备管理能力,物联网平台需要理解接入设备具备的能力以及设备上报数据的消息格式,因此,用户需要在控制台上完成产品模型和编解码插件的开发。基于IoT平台去实现一个物联网解决方案时,需完成的详细操作如下表所示: ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/29/1651195992473808566.png) 开通设备接入服务后,使用设备接入服务的完整流程主要分为产品开发、应用侧开发、设备侧开发和日常管理。 **产品开发**:开发者在进行设备接入前,基于控制台进行相应的开发工作,包括创建产品、创建设备、在线开发产品模型、在线开发插件、在线调试、自助测试和发布产品。 **设备侧开发**:设备侧可以通过集成SDK、模组或者原生协议接入物联网平台。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/29/1651196014489389532.png) **应用侧开发**:通过API的形式对外开放物联网平台丰富的设备管理能力,应用开发人员基于API接口开发所需的行业应用,如智慧城市、智慧园区、智慧工业、车联网等行业应用,满足不同行业的需求。 日常管理:真实设备接入后,基于控制台或者API接口,进行日常的设备管理。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/29/1651196033909397518.png) # 产品模型介绍 产品模型又称Profile,用于定义一款接入设备所具备的属性(如颜色、大小、采集的数据、可识别的指令或者设备上报的事件等信息),然后通过厂家、设备类型和设备型号,唯一标识一款设备,便于平台识别。产品模型可以在设备接入控制台进行无码化开发。 产品模型是用来描述一款设备“是什么”、“能做什么”以及“如何控制该设备”的文件。开发者通过定义产品模型,在物联网平台构建一款设备的抽象模型,使平台理解该款设备支持的服务、属性、命令等信息,如颜色、开关等。当定义完一款产品模型后,在进行注册设备时,就可以使用在控制台上定义的产品模型。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/29/1651196061747233784.png) 在华为云物联网平台中,产品模型是设备接入的关键内容,里面包含了这个设备所提供的能力与服务,同时还包含了设备上下行的数据格式。例如,在设备上报数据到平台时,平台会根据上报数据的关键字进行产品模型匹配,并将数据格式与匹配上的产品模型文件进行校验,只有匹配成功的数据才会在平台上保存。如果匹配不成功,物联网平台会将上报的数据作为非法数据进行抛弃。 **产品信息**:描述一款设备的基本信息,包括厂商ID、厂商名称、设备类型、协议类型。例如:水表的厂商名称为“HZYB”,厂商ID为“TestUtf8ManuId”,设备类型为“WaterMeter”,协议类型为“CoAP”。 **服务能力**:描述设备具备的业务能力。将设备业务能力拆分成若干个服务后,再定义每个服务具备的属性、命令以及命令的参数。以水表为例,水表具有多种能力,如上报水流、告警、电量、连接等各种数据,并且能够接受服务器下发的各种命令。产品模型文件在描述水表的能力时,可以将水表的能力划分五个服务,每个服务都需要定义各自的上报属性或命令。 **产品模型案例:智能水表** ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/29/1651196111245341758.png) ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/29/1651196120523811661.png) 华为云物联网平台提供了多种定义产品模型的方法,开发者可以根据自己需求,选择对应的方法定义产品模型: - 导入库模型(平台预置产品模型) - 上传模型文件(离线开发) - Excel导入 - 自定义功能(在线开发) # 设备编解码插件 ## 编解码插件简介 什么是编解码插件? 编解码插件能够将终端上报的数据(二进制格式)解码为应用服务器所能“阅读”的数据(JSON格式),将服务器端下行命令数据(JSON格式)编码为终端设备所能“理解执行”的数据(二进制格式)。 为什么要使用编解码插件? NB-IoT设备采用二进制格式或者tlv格式数据。 NB-IoT设备和IoT平台之间采用的是CoAP协议通讯,CoAP消息的payload为应用层协议数据,应用层数据的格式由设备自行定义。鉴于NB-IoT设备一般对省电要求较高,所以应用层数据一般不采用JSON格式数据。 应用服务器端并不理解二进制格式或者tlv格式数据。 如何开发编解码插件? 编解码插件的开发手段有图形化开发、离线开发和脚本化开发三种,由于插件离线开发较为复杂,且耗时比较长,推荐使用图形化开发编解码插件。 图形化开发是指在设备接入控制台,通过可视化的方式快速开发一款产品的编解码插件。 离线开发是指使用编解码插件的Java代码Demo进行二次开发,实现编解码功能、完成插件打包和质检等。 脚本化开发是指使用JavaScript脚本实现编解码的功能。 华为云物联网平台图形化编解码插件开发采用了将原有的插件开发代码进行抽象封装技术,开发者无需了解java编程语言,只需在开发界面将设备码流的格式完成定义,并将码流与profile中的属性关系通过拖拽的方式完成映射,点击部署后Portal会根据开发者的设计自动生成插件并打包部署到物联网平台。 对于设备发来的上行消息,首先解析CoAP报文得到应用层数据,然后调用设备厂商提供的插件解码,从而将消息发送到应用平台;对于来自应用平台的下行消息,需要调用设备厂商提供的编解码插件,组装CoAP消息发送到设备,如下图所示。此外编解码插件还负责对平台下发命令和对上报数据的响应进行编码。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/29/1651196167669498388.png) **数据上报** 消息处理流程包括数据上报处理流程和命令下发处理流程,数据上报处理流程如下图所示。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/29/1651196181000651919.png) 当设备和物联网平台完成对接后,一旦设备上电,设备基于在设备上定义的业务逻辑进行数据采集和上报,可以是基于周期或者事件触发。设备可通过以下方式发送数据到物联网平台: **设备消息上报**:设备可以通过消息上报接口将设备的自定义数据上报到平台,平台对设备上报的消息不进行解析和存储,通过数据转发规则转发到华为云其他云服务上进行存储和处理,然后通过其他云服务的控制台或者API接口进行进一步的数据处理。 **设备原始数据(二进制)上报**:设备可以通过二进制上报接口上报设备的原始码流,平台通过编解码插件将设备原始数据解析为产品模型定义的JSON格式,解析后的数据上报给设备接入服务进行相关业务处理。 **设备属性上报**:设备通过属性上报接口,将产品模型中定义的属性数据上报给平台,平台解析后的数据上报给设备接入服务进行相关业务处理。 **网关批量属性上报**:网关设备将批量设备的数据一次性上报到平台,平台解析后的数据上报给设备接入服务进行相关业务处理。 在数据上报处理流程中,有两处需要用到编解码插件。 1. 将设备上报的二进制码流的数据解码成JSON格式的数据,发送给应用服务器。 2. 将应用服务器响应的JSON格式数据编码成二进制码流格式的数据,下发给设备。 **命令下发** 命令下发是指平台将命令下发到设备,设备响应并执行命令,从而达到平台到设备远程控制的效果。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/29/1651196226205730612.png) ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/29/1651196238080734258.png) 这里分别列举了LwM2M/CoAP和MQTT这两种协议的立即下发和缓存下发的流程,如图所示。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/29/1651196249676371979.png) 应用下发命令到物联网平台,平台会根据对应的产品信息找到对应的编解码插件,对命令请求进行编码,将命令下发给设备;下发命令成功或失败,会根据下发结果更新命令状态,若设备对命令做出了响应,会将命令状态更新为“执行成功”或“执行失败”。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/29/1651196258122705049.png) 由于使用MQTT是不需要编解码插件的,直接使用透传的形式,当命令立即下发时,应用下发命令到物联网平台,平台将命令下发至设备,返回执行结果,消息执行结果通知。 应用缓存下发命令,当设备不在线时,将命令写入缓存队列,更新消息状态,直到设备上报数据,设备上线,订阅消息下发Topic,消息下发,更新消息状态。 设备编解码插件示例: ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/29/1651196268445426714.png)
  • [数据加载及处理] 【MindSpore易点通】MindSpore怎么用?第二期:数据加载和处理
    概述本帖的内容包括跟随官方初级课程内容,复现数据集的加载过程。实现了数据集对象的初始化,并定义了对象的成员函数对数据内容进行了批处理。另外通过对coco数据集json文件的解析,理清了数据集的内容,写了一个切分数据集的小脚本,分享给大家。本次学习的课程是 MindSpore手把手安装与体验,视频讲解的非常细致,将常用的公开数据集Cifar10, VOC, COCO等都涉及到了。跟着视频非常轻松就可以使用MindSpore完成数据集的加载。贴一下视频链接:数据加载和处理1 数据集准备使用coco数据为例,基于官网下载数据集的图片(jpg格式)使用官网地址下载annotation文件(json格式)下载完成后,coco数据集的目录结构如下2 数据集对象的初始化所有的数据集对象的初始化都需要用到dataset这个接口,dataset接口内提供了几乎所有常用数据集的生成器(MnistDataset, CocoDataset, Cifar10Dataset,...),如果需要对不常见或自定义的数据集,还可以使用GeneratorDataset进行补充。下面是对coco2017数据集对象的初始化使用了验证集图片和不同的json文件进行实例化,可以用于不同分支的任务3 定义成员函数,内容批处理因为是自定义的内容,所以用到了上面提及的GeneratorDataset接口应用成员函数后的效果如下,列表内每个元素都做了+2的操作4 拓展部分不知道小伙伴有没有遇到过这样的情况,使用coco数据集进行训练或推理的过程,因为网络结果较为复杂,以及coco数据集的精度计算过程本就比较耗时。在前期的调试阶段每次完整的跑完整个训练/验证集,往往大半天就过去了。这让调参数的过程变得异常痛苦,会想要对coco数据集进行裁剪。另一方面,coco数据集的图片文件名并不是连续的,其精度计算过程也和json文件密切相关,单纯的提取出部分图片,后处理的逻辑就不完整了。借着本次学习数据集加载接口的机会,我仔细阅读了一下json文件的内容,发现coco数据用于目标检测的annotation文件(instances_val2017.json)主要包含了以下几个方面内容['info', 'license', 'images', 'annotation', 'categories']其中'images'和‘annotations’和数据集图片关系最为密切'images'内包含有['license', 'file_name', 'coco_url', 'height', 'width', 'date_captured', 'flickr_url', 'id']'annotations'内包含有['segmentation', 'area', 'iscrowd', 'image_id', 'bbox', 'category_id', 'id']只要对这两部分内容进行切分,就可实现json文件的分割,然后用分割后的json文件取提取相应的图片。下面附上我的切分代码import sys import argparse import json parser = argparse.ArgumentParser(description = "json split for cocodataset") parser.add_argument("--start", type=int, default=0) parser.add_argument("--end", type=int, default=500) parser.add_argument("--ann_file", type=str, default='instances_val2017.json') args_opt = parser.parse_args() start_ids = args_opt.start end_ids = args_opt.end if end_ids < start_ids: print("the index of image end < start.") sys.exit(1) file = open(args_opt.ann_file, encoding='utf-8') js_image_full = json.load(file) images = js_image_full['images'][start_ids:end_ids] annotations = js_image_full['annotations'] image_id_list = [] for image in images: image_id_list.append(image['id']) ann_new_list = [] for ann in annotations: if ann['image_id'] in image_id_list: ann_new_list.append(ann) dict_new = js_image_full dict_new['images'] = images dict_new['annotations'] = ann_new_list print(f"image lengh: {len(dict_new['images'])}, annotations lengh: {len(dict_new['annotations'])}") json_name = args_opt.ann_file json_name = json_name.split('.')[0] json_name = json_name + '_' + str(start_ids) + '_to_' + str(end_ids) + '_image.json' print("file name is ", json_name) with open(json_name, 'w') as file_obj: json.dump(dict_new, file_obj)import os, shutil import argparse import json parser = argparse.ArgumentParser(description = "json split for cocodataset") parser.add_argument("--dataset_path", type=str, default='val2017') parser.add_argument("--ann_file", type=str, default='instances_val2017.json') args_opt = parser.parse_args() file = open(args_opt.ann_file, encoding='utf-8') js_image = json.load(file) images = js_image['images'] new_dataset_dir = os.path.join(os.getcwd(), "dataset_collected") os.mkdir(new_dataset_dir) name_list = [] for image in images: file_name = image['file_name'] name_list.append(file_name) file_path = os.path.join(args_opt.dataset_path, file_name) assert os.path.exists(file_path) shutil.copyfile(file_path, os.path.join(new_dataset_dir, file_name))
  • [问题求助] 小程序发布出来未找到sitemap,json文件,怎么处理
  • [技术干货] 解析policy.json-原创
    openstack 通过 keystone 用来完成 authenticate 和 authorize 是在每一个模板都要做的,具体的每个模板中都有policy文件也都定义了rules 角色权限“Context is_admin":"role:admin",policy.json 有行和列的俩种写的方法在行的写法中每一行:前都四action 也就是用户执行的操作是什么冒号后面的叫rule 角色用来根据当前上下文来判断当前的 action 是否能让当前的用户执行policv的工作就是来解析rule的要把这个rule解析为相应的对象obiect在外部调用权限认证时根据action 映射到rule中判断是否执行 action role在这里是权限的集合将role中的权限赋予特定的用户拥有特定的权限也方便用户管理但是咱们第一行context_is_admin:role:admin设置的默认角色只有admin 若需其他用户需要自行创建这样就不难理解了其实 policy 就是来控制用户的权限的含义如代码中的含义:{ "context_is_admin":  "role:admin",      上下文为一个用户分配一个admin角色(一个用户可以有多个角色)    "default": "role:admin",                   默认为admin角色     "add_image": "",                            允许创建镜像    "delete_image": "",                          允许删除镜像    "get_image": "",                             允许获取镜像    "get_images": "",                            允许获取多个镜像    "modify_image": "",                          允许修改镜像    "publicize_image": "role:admin",                仅admin角色的用户才能传输镜像    "communitize_image": "",                      允许公开镜像    "copy_from": "",                             允许拷贝从某个地方     "download_image": "",                        允许下载镜像    "upload_image": "",                           允许上传镜像     "delete_image_location": "",                    允许删除特定位置的镜像    "get_image_location": "",                       允许获取特定位置的镜像    "set_image_location": "",                       允许设置特定位置的镜像     "add_member": "",                            允许增加成员    "delete_member": "",                          允许删除成员    "get_member": "",                             允许获取成员    "get_members": "",                            允许获取多个成员    "modify_member": "",                          允许修改成员 "manage_image_cache": "role:admin",  #只有admin角色的用户管理员才可以管理镜像缓存     "get_task": "role:admin",               只有admin角色的用户才可以获取任务    "get_tasks": "role:admin",             只有admin角色的用户才可以获取多个任务    "add_task": "role:admin",             只有admin角色的用户才可以增加任务    "modify_task": "role:admin",        只有admin角色的用户才可以修改任务     "deactivate": "",                            允许关闭所有     "reactivate": "",                             允许激活所有     "get_metadef_namespace": "",         允许获取元数据命名空间    "get_metadef_namespaces":"",        允许获取元数据多个命名空间    "modify_metadef_namespace":"",      允许修改元数据命名空间    "add_metadef_namespace":"",         允许增加元数据命名空间     "get_metadef_object":"",                  允许获取元数据对象    "get_metadef_objects":"",                允许获取元数据多个对象    "modify_metadef_object":"",              允许修改元数据对象    "add_metadef_object":"",                 允许增加元数据对象     "list_metadef_resource_types":"",    允许列出元数据资源类型     "get_metadef_resource_type":"",     允许获取元数据资源类型    "add_metadef_resource_type_association":"",       允许增加元数据资源类型关联     "get_metadef_property":"",             允许获取元数据属性    "get_metadef_properties":"",          允许获取元数据多个属性    "modify_metadef_property":"",       允许修改元数据属性    "add_metadef_property":"",            允许增加元数据属性     "get_metadef_tag":"",                      允许获取元数据标签    "get_metadef_tags":"",                    允许获取元数据多个标签    "modify_metadef_tag":"",                允许修改元数据标签    "add_metadef_tag":"",                     允许增加元数据标签    "add_metadef_tags":""                    允许增加元数据多个标签 }
  • [技术干货] 缓动动画函数的封装方法
    这篇文章主要为大家详细介绍了JavaScript缓动动画函数的封装方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下本文实例为大家分享了JavaScript缓动动画函数的封装代码,供大家参考,具体内容如下本文将从封装缓动动画的以下几个部分进行封装(1、单个属性,2、多个属性,3、缓动框架之回调函数,4、缓动框架之层级与透明度)首先:获取元素样式的兼容方式123456function getStyle(ele,attr){      //获取任意类型的CSS样式的属性值  if(window.getComputedStyle){        return window.getComputedStyle(ele,null)[attr];  }  return ele.currentStyle[attr];}封装单个属性123456789101112131415function animate(ele,attr,target){   //元素(box) 样式(left) 目标值(400)  clearInterval(ele.timer);     //使用定时器时,先清除定时器,防止多个定时器并行  ele.timer = setInterval(function(){    //先定义一个当前值    var leader = parseInt(getStyle(ele,attr)) || 0;   //当这个样式为空时设置为0,获取来的样式值要取整。    var step = (target - leader)/10;    step = step > 0 ? Math.ceil(step) : Math.floor(step);    leader = leader + step;    ele.style[attr] = leader + "px";     //注意设置元素样式,注意加单位    if(Math.abs(target-leader) <= Math.abs(step)){      ele.style[attr] = target + "px";      clearInterval(ele.timer);    }  },25);}封装多个属性12345678910111213141516171819202122232425262728293031function animate(ele,json){   //把样式和目标值放在json中,如:var json = {"left":10,"top":200,"width":300,"height":200}    clearInterval(ele.timer);  ele.timer = setInterval(function(){    //开闭原则,目的保证所有样式都到达目标值    var bool = true;    // 分别单独处理json;    for(k in json){      var attr = k;  //这里的k即上文中的样式      var target = json[k];  //这里的json[k]即上文中的目标值,熟练后直接写k,json[k]。      var leader = parseInt(getStyle(ele,attr)) || 0;      var step = (target - leader) / 10;      step = step > 0 ? Math.ceil(step) : Math.floor(step);      leader = leader + step;      ele.style[attr] = leader + "px";       //如果使用上文中清除定时器的方式,则完成了一个json内容就清除了定时器,显然不能这么做      // if(Math.abs(target - leader) <= Math.abs(step)){        // ele.style[attr] = target + "px";        // clearInterval(ele.timer);      // }      if(target !== leader){  //依据上文定义的bool,遍历json时当有一个样式未完成,则bool值依旧为false。        bool = false;      }    }     //只有所有属性样式都到了指定位置,bool值才变成true    if(bool){        clearInterval(ele.timer);    }  },25);       }缓动框架之回调函数1234567891011121314151617181920212223242526272829function animate(ele,json,fn){    clearInterval(ele.timer);    ele.timer = setInterval(function(){        var bool = true;        for(k in json){                   var leader = parseInt(getStyle(ele,k)) || 0;              var step = (json[k] - leader) / 10;            step = step > 0 ? Math.ceil(step) : Math.floor(step);            leader = leader + step;            ele.style[k] = leader + "px";            if(json[k] !== leader){                bool = false;            }        }        if(bool){            clearInterval(ele.timer);            if(fn){     //此处如果有函数,则掉用,如果没有则自动不执行,当然也可加个判断,if(typeof fn == "function"),当fn类型为函数时。                fn();            }        }    },25);} //调用animate(box,json,function(){      //这里的function是一整个函数体,所以上文中的fn要加();    animate(box,json1,function(){     //当执行完第一个缓动动画时,有function则继续执行。        animate(box,json);    });});缓动框架之层级与透明度123456789101112131415161718192021222324252627282930313233343536function animate(ele,json,fn){  clearInterval(ele.timer);  ele.timer = setInterval(function(){    var bool = true;    for(k in json){      var leader;      if(k === "opacity"){   //如果属性为opacity        leader = getStyle(ele,k) * 100 || 1;  //不能取整,先把它乘100      }else{        leader = parseInt(getStyle(ele,k)) || 0;        }                var step = (json[k] - leader) / 10;       step = step > 0 ? Math.ceil(step) : Math.floor(step);      leader = leader + step;      if(k === "opacity"){         ele.style[k] = leader/100;   //如果是opacity,赋值时在除以100        ele.style.filter = "alpha(opacity="+leader+")";   //兼容IE      }else if(k === "zIndex"){        ele.style[k] = leader;   //直接赋值就是了,不用加单位      }else{        ele.style[k] = leader + "px";      }      if(json[k] !== leader){        bool = false;        console.log(leader);      }    }    if(bool){      clearInterval(ele.timer);      if(fn){        fn();      }    }  },30);}**//注意这里赋值的opacity要乘以100,如:30,100等**以上就是本文的全部内容,希望对大家的学习有所帮助转载自https://www.jb51.net/article/200603.htm
  • [技术干货] VUE package.json属性说明详解
    属性介绍description字符串。用来描述当前项目的大致功能。name此项目包的名称。在不确定自己的包名能否使用之前,请先npm registry 一下,看看当前你喜欢的包名是否已经被占用。version当前项目包的版本号。每一次项目改动时,在即将发布时,都要同步的去更改项目的版本号。一般格式为:x.y.z。意思是:大版本.中版本.小版本keywords放简介,字符串。方便屌丝们在 npm search中搜索homepage项目官网的urlbugs你项目的提交问题的url和(或)邮件地址。这对遇到问题的屌丝很有帮助。{ "url" : "http://github.com/owner/project/issues" , "email" : "project@hostname.com" }你可以指定一个或者指定两个。如果你只想提供一个url,那就不用对象了,字符串就行。如果提供了url,它会被npm bugs命令使用。license你应该要指定一个许可证,让人知道使用的权利和限制的。最简单的方法是,假如你用一个像BSD或者MIT这样通用的许可证,就只需要指定一个许可证的名字,像这样:{ "license" : "BSD" }author项目作者。可以指定name,email,url字段信息。也可以单独使用字符串来表示。{“ author ”: { "name" : "Barney Rubble" , "email" : "b@rubble.com" , "url" : "http://barnyrubble.tumblr.com/" } }contributors项目相关贡献者。是数组。用于罗列对应的贡献人。可以是单独的字符串,也可以分别指定name,email,url等属性。{"contributors ":[ { "name" : "Barney Rubble" , "email" : "b@rubble.com" , "url" : "http://barnyrubble.tumblr.com/" } ]}filesfiles是一个包含项目中的文件的数组。如果命名了一个文件夹,那也会包含文件夹中的文件。(除非被其他条件忽略了)你也可以提供一个.npmignore文件,让即使被包含在files字段中得文件被留下。其实就像.gitignore一样。{ "files": [ "bin/", "templates/", "test/" ]}mainmain字段是一个模块ID,它是一个指向你程序的主要项目。就是说,如果你包的名字叫foo,然后用户安装它,然后require("foo"),然后你的main模块的exports对象会被返回。这应该是一个相对于根目录的模块ID。对于大多数模块,它是非常有意义的,其他的都没啥。{ "main": "bin/index.js"}bin很多包都有一个或多个可执行的文件希望被放到PATH中。(实际上,就是这个功能让npm可执行的)。要用这个功能,给package.json中的bin字段一个命令名到文件位置的map。初始化的时候npm会将他链接到prefix/bin(全局初始化)或者./node_modules/.bin/(本地初始化)。{ "bin" : { "npm" : "./cli.js" } }当你初始化npm,它会创建一个符号链接到cli.js脚本到/usr/local/bin/npm。如果你只有一个可执行文件,并且名字和包名一样。那么你可以只用一个字符串,比如{ "name": "my-program" , "version": "1.2.5" , "bin": "./path/to/program" }// 等价于{ "name": "my-program" , "version": "1.2.5" , "bin" : { "my-program" : "./path/to/program" } }man指定一个单一的文件或者一个文件数组供man程序使用。如果只提供一个单一的文件,那么它初始化后就是man 的结果,而不管实际的文件名是神马,比如:{ "name" : "foo" , "version" : "1.2.3" , "description" : "A packaged foo fooer for fooing foos" , "main" : "foo.js" , "man" : "./man/doc.1" }这样man foo就可以用到./man/doc.1文件了。如果文件名不是以包名开头,那么它会被冠以前缀,下面的:{ "name" : "foo" , "version" : "1.2.3" , "description" : "A packaged foo fooer for fooing foos" , "main" : "foo.js" , "man" : [ "./man/foo.1", "./man/bar.1" ] }会为man foo和man foo-bar创建文件。man文件需要以数字结束,然后可选地压缩后以.gz为后缀。{ "name" : "foo" , "version" : "1.2.3" , "description" : "A packaged foo fooer for fooing foos" , "main" : "foo.js" , "man" : [ "./man/foo.1", "./man/foo.2" ] }会为man foo和man 2 foo创建。repository指定你的代码存放的地方。这个对希望贡献的人有帮助。如果git仓库在github上,那么npm docs命令能找到你。scripts“scripts”是一个由脚本命令组成的hash对象,他们在包不同的生命周期中被执行。key是生命周期事件,value是要运行的命令。config"config" hash可以用来配置用于包脚本中的跨版本参数。在实例中,如果一个包有下面的配置{ "name" : "foo" , "config" : { "port" : "8080" } }然后有一个“start”命令引用了npm_package_config_port环境变量,用户可以通过npm config set foo:port 8001来重写他。dependencies依赖是给一组包名指定版本范围的一个hash。这个版本范围是一个由一个或多个空格分隔的字符串。依赖还可以用tarball或者git URL。请不要将测试或过渡性的依赖放在dependencies。对于引用包的版本号格式,以下都是合法的:{ "dependencies" :   { "foo" : "1.0.0 - 2.9999.9999"   , "bar" : ">=1.0.2 <2.1.2"   , "baz" : ">1.0.2 <=2.3.4"   , "boo" : "2.0.1"   , "qux" : "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0"   , "asd" : "http://asdf.com/asdf.tar.gz"   , "til" : "~1.2"   , "elf" : "~1.2.3"   , "two" : "2.x"   , "thr" : "3.3.x"  ,"vue":"*", "element-ui":"" } }devDependencies如果有人要用你的模块,但他们可能不需要你开发所使用的外部测试或者文档框架。在这种情况下,最好将这些附属的项目列在devDependencies中。这些东西会在根目录执行npm link或者npm install的时候初始化,并可以像其他npm配置参数一样管理。peerDependencies你的模块可能要暴露一个特定的接口,并由host文档来预期和指定。比如:{   "name": "tea-latte",   "version": "1.3.5"   "peerDependencies": {     "tea": "2.x"   } }这能保证你的package可以只和tea的2.x版本一起初始化。试图初始化另一个有会冲突的依赖的插件将导致一个错误。因此,确保你的插件的需求约束越弱越好,而不要去把它锁定到一个特定的版本。此属性尽量避免使用bundledDependencies一组包名,他们会在发布的时候被打包进去engines指定项目工作的环境。除非用户设置engine-strict标记,这个字段只是建议值。{ "engines" : { "node" : ">=0.10.3 <0.12", "npm" : "~1.0.20" } }engineStrict如果你确定你的模块一定不会运行在你指定版本之外的node或者npm上,你可以在package.json文件中设置"engineStrict":true。它会重写用户的engine-strict设置。除非你非常非常确定,否则不要这样做。如果你的engines hash过度地限制,很可能轻易让自己陷入窘境。慎重地考虑这个选择。如果大家滥用它,它会再以后的npm版本中被删除。os可以指定你的模块要运行在哪些操作系统中"os" : [ "darwin", "linux" ]你也可以用黑名单代替白名单,在名字前面加上“!”就可以了:"os" : [ "!win32" ]操作系统用process.platform来探测。虽然没有很好地理由,但它是同时支持黑名单和白名单的。cpu如果你的代码只能运行在特定的cpu架构下,你可以指定一个"cpu" : [ "x64", "ia32" ]就像os选项,你也可以黑一个架构:"cpu" : [ "!arm", "!mips" ]cpu架构用process.arch探测。preferGlobal如果包主要是需要全局安装的命令行程序,就设置它为true来提供一个warning给只在局部安装的人。它不会真正的防止用户在局部安装,但如果它没有按预期工作它会帮助防止产生误会。{" preferGlobal ":true}private如果你设置"private": true,npm就不会发布它。这是一个防止意外发布私有库的方式。如果你要确定给定的包是只发布在特定registry(如内部registry)的,用publishConfighash的描述来重写registry的publish-time配置参数。publishConfig这是一个在publish-time使用的配置集合。当你想设置tag或者registry的时候它非常有用,所以你可以确定一个给定的包没有打上“lastest”的tag或者被默认发布到全局的公开registry。任何配置都可以被重写,但当然可能只有“tag”和“registry”与发布的意图有关。
  • [问题求助] AppCube标准页面-组件-上传,文件存储在obs,上传成功后用预置库XLSX转Json 报错?
    【功能模块】【操作步骤&问题现象】1、上传excel文件,上传成功后用预置库XLSX转json报错,上传组件返回的数据不满足XLSX方法的入参要求?2、之前发过贴在,按照反馈更改后,还是报错!麻烦再看下【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [问题求助] atlas200dk profiling导致Init失败
    如题,当做profiling时,aclInit()初始化会失败;aclInit() 的config参数是json文件,正常内容为空: {}; 运行没有问题;用msprof工具和acl.json做profiling会出现同样的问题;用msprof工具如下,报错:100000/usr/local/Ascend/driver/tools/msprof --output=./profile --application="/usr/local/atlas/main /usr/local/atlas/models"   --sys-hardware-mem=on --environment="LD_LIBRARY_PATH=/usr/local/atlas/lib/:$LD_LIBRARY_PATH直接运行没有问题:/usr/local/Ascend/driver/tools/msprof --output=./profile --sys-devices=0 --sys-period=100 --sys-hardware-mem=on在acl.json中配置如下时,报同样的错误100000:设备信息如下,cann版本5.0.3alpha002:
  • [问题求助] 训练数据集的标签txt格式文件如何转换成json格式
  • [技术干货] JS 获取焦点失去焦点时修改输入框的样式【不写代码浑身难受】
    随着大数据的时代,用户体验让我们对操作本身简答逻辑不在陌生,而一些特效让操作元素更加直观,当然对直观的就是输入框的一些特效。简直是玩花了,为了让用户更加清除自己输入的是那一项,我们可以在获取焦点和失去焦点时添加一些样式。核心代码 const enter = document.querySelector('.enter') const fCss = enter.getAttribute("data-fCss") const bCss = enter.getAttribute('data-bCss') const bClass = enter.getAttribute('data-bClass') const fClass = enter.getAttribute('data-fClass') //getAttribute() 返回的是指定属性的值 //console.log(bCss, bCss, bClass, fClass); {"backgroundColor":"blue"} {"backgroundColor":"pink"} bborder footer //将字符串转化为JSON对象 function strToJson(str) { //JSON.parse方法用于将JSON字符串转化成对象:这种方式能将字符串解析成json对象 return typeof str == 'object' ? JSON.parse(str) : (new Function('return' + str))(); } //设置样式 function setCss(_this, Cssoption) { if (!_this || _this.nodeType === 3 || _this.nodeType === 8 || !_this.style) { return } for (let cs in Cssoption) { _this.style[cs] = Cssoption[cs] console.log(Cssoption, cs); } return _this } //获取焦点添加样式 function foceshandle() { fCss && setCss(this, strToJson(fCss)) fClass && (this.className = fClass) } //失去焦点添加样式 function blurhandle() { bCss && setCss(this, strToJson(bCss)) bClass && (this.className = bClass) } enter.addEventListener('focus', foceshandle) enter.addEventListener('blur', blurhandle)逻辑说明:getAttribute() 返回的是指定属性的值console.log(bCss, bCss, bClass, fClass);    {"backgroundColor":"blue"} {"backgroundColor":"pink"} bborder footer 代码可以通过  fCss && setCss(this, strToJson(fCss))   and     fClass && (this.className = fClass)   实现修改元素的行内样式与class的修改通过逻辑 ’与‘ 来判断 fCss   与  setCss(this, strToJson(fCss))  是否为空 ,代码理解比较简单,但是代码逻辑时很好模板。
  • [数据处理] 【modelArts平台MindSpore产品】【如何将json数据转化mindrecord】
    【功能模块】【操作步骤&问题现象】我在modelarts平台上执行如下代码import osimport requestsimport tarfileimport zipfilefrom mindspore.mindrecord import FileWriterdata_record_path = 'test4.mindrecord'writer = FileWriter(file_name=data_record_path, shard_num=4)# 定义schemadata_schema = {"label":{"type":"int32"},"data":{"type":"float64",'shape':[-1]}}writer.add_schema(data_schema,"test_schema")data = [{"label":targetNum[0], "data":dataaaa.iloc[0]}]indexes = ["label","data"]writer.add_index(indexes)# 数据写入writer.write_raw_data(data)# 生成本地数据writer.commit()然后报了这样的错误,请问如何解决?【截图信息】这是data数据,这是报错截图【日志信息】(可选,上传日志内容或者附件)
  • [活动体验] 实现一个端云联邦的图像分类应用(x86)
    联邦学习可分为云云联邦学习(cross-silo)和端云联邦学习(cross-device)。在云云联邦学习场景中,参与联邦学习的客户是不同的组织(例如,医疗或金融)或地理分布的数据中心,即在多个数据孤岛上训练模型。而在端云联邦学习场景中参与的客户为大量的移动或物联网设备。本框架将介绍如何在MindSpore端云联邦框架上使用网络LeNet实现一个图片分类应用。首先要下载数据集:该数据集包含62个不同类别的手写数字和字母(数字0~9、26个小写字母、26个大写字母),图像大小为28 x 28像素,数据集包含3500个用户的手写数字和字母(最多可模拟3500个客户端参与联邦学习),总数据量为805263,平均每个用户包含数据量为226.83,所有用户数据量的方差为88.94。下载数据集前的环境要求。代码如下:numpy==1.16.4scipy # conda install scipytensorflow==1.13.1 # pip install tensorflowPillow # pip install Pillowmatplotlib # pip install matplotlibjupyter # conda install jupyter notebook==5.7.8 tornado==4.5.3pandas # pip install pandas使用git下载官方数据集生成脚本。git clone https://github.com/TalwalkarLab/leaf.git目录结构如下:leaf/data/femnist├── data # 用来存放指令生成的数据集├── preprocess # 存放数据预处理的相关代码├── preprocess.sh # femnist数据集生成shell脚本└── README.md # 官方数据集下载指导文档以femnist数据集为例,运行以下指令进入指定路径。cd leaf/data/femnist在终端输入指令即可下载对应数据集。运行./preprocess.sh具有以下标签的选择:-s:’iid’以iid方式采样,或’niid’以非iid方式采样。--iu:用户数(如果进行iid采样);表示为用户总数的分数;默认值为0.01。--sf:要采样的数据部分,用十进制表示;默认值为0.1。-k:每个用户的最小样本数。-t:’user’将用户划分为训练测试组,或’sample’将每个用户的样本划分为训练测试组。--tf:训练集中的数据部分,用小数表示;默认值为0.9。--smplseed:随机抽样数据之前要使用的种子。--spltseed:随机分割数据之前要使用的种子。用指令./preprocess.sh -s niid --sf 1.0 -k 0 -t sample生成的数据集包含3500个用户,且按照9:1对每个用户的数据划分训练和测试集。运行之后目录结构如下:leaf/data/femnist/35_client_sf1_data/├── all_data # 所有数据集混合在一起,不区分训练测试集,共包含35个json文件,每个json文件包含100个用户的数据├── test # 按照9:1对每个用户的数据划分训练和测试集后的测试集,共包含35个json文件,每个json文件包含100个用户的数据├── train # 按照9:1对每个用户的数据划分训练和测试集后的训练集,共包含35个json文件,每个json文件包含100个用户的数据└── ... # 其他文件,暂不需要用到,不作介绍其中每个json文件包含以下三个部分:1. users: 用户列表。2. num_samples: 每个用户的样本数量列表。3. user_data: 一个以用户名为key,以它们各自的数据为value的字典对象;对于每个用户,数据表示为图像列表,每张图像表示为大小为784的整数列表(将28 x 28图像数组展平所得)。5个json文件划分为3500个json文件代码如下:import osimport jsondef mkdir(path):if not os.path.exists(path):os.mkdir(path)def partition_json(root_path, new_root_path):"""partition 35 json files to 3500 json fileEach raw .json file is an object with 3 keys:1. 'users', a list of users2. 'num_samples', a list of the number of samples for each user3. 'user_data', an object with user names as keys and their respective data as values; for each user, data is represented as a list of images, with each image represented as a size-784 integer list (flattened from 28 by 28)Each new .json file is an object with 3 keys:1. 'user_name', the name of user2. 'num_samples', the number of samples for the user3. 'user_data', an dict object with 'x' as keys and their respective data as values; with 'y' as keys and their respective label as values;Args:root_path (str): raw root path of 35 json filesnew_root_path (str): new root path of 3500 json files"""paths = os.listdir(root_path)count = 0file_num = 0for i in paths:file_num += 1file_path = os.path.join(root_path, i)print('======== process ' + str(file_num) + ' file: ' + str(file_path) + '======================')with open(file_path, 'r') as load_f:load_dict = json.load(load_f)users = load_dict['users']num_users = len(users)num_samples = load_dict['num_samples']for j in range(num_users):count += 1print('---processing user: ' + str(count) + '---')cur_out = {'user_name': None, 'num_samples': None, 'user_data': {}}cur_user_id = users[j]cur_data_num = num_samples[j]cur_user_path = os.path.join(new_root_path, cur_user_id + '.json')cur_out['user_name'] = cur_user_idcur_out['num_samples'] = cur_data_numcur_out['user_data'].update(load_dict['user_data'][cur_user_id])with open(cur_user_path, 'w') as f:json.dump(cur_out, f)f = os.listdir(new_root_path)print(len(f), ' users have been processed!')# partition train json filespartition_json("leaf/data/femnist/35_client_sf1_data/train", "leaf/data/femnist/3500_client_json/train")# partition test json filespartition_json("leaf/data/femnist/35_client_sf1_data/test", "leaf/data/femnist/3500_client_json/test")其中root_path为leaf/data/femnist/35_client_sf1_data/{train,test},new_root_path自行设置,用于存放生成的3500个用户json文件,需分别对训练和测试文件夹进行处理。新生成的3500个用户json文件,每个文件均包含以下三个部分:4. user_name: 用户名。5. num_samples: 用户的样本数。6. user_data: 一个以’x’为key,以用户数据为value的字典对象; 以’y’为key,以用户数据对应的标签为value。运行该脚本打印如下,代表运行成功:代码如下:======== process 1 file: /leaf/data/femnist/35_client_sf1_data/train/all_data_16_niid_0_keep_0_train_9.json======================---processing user: 1------processing user: 2------processing user: 3------processing user: 4------processing user: 5------processing user: 6------processing user: 7------processing user: 8------processing user: 9------processing user: 10------processing user: 11------processing user: 12------processing user: 13------processing user: 14---..将json文件转换为图片文件。代码如下:import osimport jsonimport numpy as npfrom PIL import Imagename_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9','A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U','V', 'W', 'X', 'Y', 'Z','a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u','v', 'w', 'x', 'y', 'z']def mkdir(path):if not os.path.exists(path):os.mkdir(path)def json_2_numpy(img_size, file_path):"""read json file to numpyArgs:img_size (list): contain three elements: the height, width, channel of imagefile_path (str): root path of 3500 json filesreturn:image_numpy (numpy)label_numpy (numpy)"""# open json filewith open(file_path, 'r') as load_f_train:load_dict = json.load(load_f_train)num_samples = load_dict['num_samples']x = load_dict['user_data']['x']y = load_dict['user_data']['y']size = (num_samples, img_size[0], img_size[1], img_size[2])image_numpy = np.array(x, dtype=np.float32).reshape(size) # mindspore doesn't support float64 and int64label_numpy = np.array(y, dtype=np.int32)return image_numpy, label_numpydef json_2_img(json_path, save_path):"""transform single json file to imagesArgs:json_path (str): the path json filesave_path (str): the root path to save images"""data, label = json_2_numpy([28, 28, 1], json_path)for i in range(data.shape[0]):img = data[i] * 255 # PIL don't support the 0/1 image ,need convert to 0~255 imageim = Image.fromarray(np.squeeze(img))im = im.convert('L')img_name = str(label[i]) + '_' + name_list[label[i]] + '_' + str(i) + '.png'path1 = os.path.join(save_path, str(label[i]))mkdir(path1)img_path = os.path.join(path1, img_name)im.save(img_path)print('-----', i, '-----')def all_json_2_img(root_path, save_root_path):"""transform json files to imagesArgs:json_path (str): the root path of 3500 json filessave_path (str): the root path to save images"""usage = ['train', 'test']for i in range(2):x = usage[i]files_path = os.path.join(root_path, x)files = os.listdir(files_path)for name in files:user_name = name.split('.')[0]json_path = os.path.join(files_path, name)save_path1 = os.path.join(save_root_path, user_name)mkdir(save_path1)save_path = os.path.join(save_path1, x)mkdir(save_path)print('=============================' + name + '=======================')json_2_img(json_path, save_path)all_json_2_img("leaf/data/femnist/3500_client_json/", "leaf/data/femnist/3500_client_img/")运行成功获得如下结果过将图片数据集转换为联邦学习框架可用的bin文件格式。代码如下:import numpy as npimport osimport mindspore.dataset as dsimport mindspore.dataset.transforms.c_transforms as tCimport mindspore.dataset.vision.py_transforms as PVimport mindspore.dataset.transforms.py_transforms as PTimport mindsporedef mkdir(path):if not os.path.exists(path):os.mkdir(path)def count_id(path):files = os.listdir(path)ids = {}for i in files:ids[i] = int(i)return idsdef create_dataset_from_folder(data_path, img_size, batch_size=32, repeat_size=1, num_parallel_workers=1, shuffle=False):""" create dataset for train or testArgs:data_path: Data pathbatch_size: The number of data records in each grouprepeat_size: The number of replicated data recordsnum_parallel_workers: The number of parallel workers"""# define datasetids = count_id(data_path)mnist_ds = ds.ImageFolderDataset(dataset_dir=data_path, decode=False, class_indexing=ids)# define operation parametersresize_height, resize_width = img_size[0], img_size[1] # 32transform = [PV.Decode(),PV.Grayscale(1),PV.Resize(size=(resize_height, resize_width)),PV.Grayscale(3),PV.ToTensor(),]compose = PT.Compose(transform)# apply map operations on imagesmnist_ds = mnist_ds.map(input_columns="label", operations=tC.TypeCast(mindspore.int32))mnist_ds = mnist_ds.map(input_columns="image", operations=compose)# apply DatasetOpsbuffer_size = 10000if shuffle:mnist_ds = mnist_ds.shuffle(buffer_size=buffer_size) # 10000 as in LeNet train scriptmnist_ds = mnist_ds.batch(batch_size, drop_remainder=True)mnist_ds = mnist_ds.repeat(repeat_size)return mnist_dsdef img2bin(root_path, root_save):"""transform images to bin filesArgs:root_path: the root path of 3500 images filesroot_save: the root path to save bin files"""use_list = []train_batch_num = []test_batch_num = []mkdir(root_save)users = os.listdir(root_path)for user in users:use_list.append(user)user_path = os.path.join(root_path, user)train_test = os.listdir(user_path)for tag in train_test:data_path = os.path.join(user_path, tag)dataset = create_dataset_from_folder(data_path, (32, 32, 1), 32)batch_num = 0img_list = []label_list = []for data in dataset.create_dict_iterator():batch_x_tensor = data['image']batch_y_tensor = data['label']trans_img = np.transpose(batch_x_tensor.asnumpy(), [0, 2, 3, 1])img_list.append(trans_img)label_list.append(batch_y_tensor.asnumpy())batch_num += 1if tag == "train":train_batch_num.append(batch_num)elif tag == "test":test_batch_num.append(batch_num)imgs = np.array(img_list) # (batch_num, 32,3,32,32)labels = np.array(label_list)path1 = os.path.join(root_save, user)mkdir(path1)image_path = os.path.join(path1, user + "_" + "bn_" + str(batch_num) + "_" + tag + "_data.bin")label_path = os.path.join(path1, user + "_" + "bn_" + str(batch_num) + "_" + tag + "_label.bin")imgs.tofile(image_path)labels.tofile(label_path)print("user: " + user + " " + tag + "_batch_num: " + str(batch_num))print("total " + str(len(use_list)) + " users finished!")root_path = "leaf/data/femnist/3500_client_img/"root_save = "leaf/data/femnist/3500_clients_bin"img2bin(root_path, root_save)若结果如下,则表示运行成功:生成3500_clients_bin文件夹内共包含3500个用户文件夹,其目录结构如下:leaf/data/femnist/3500_clients_bin├── f0000_14 # 用户编号│ ├── f0000_14_bn_10_train_data.bin # 用户f0000_14的训练数据 (bn_后面的数字10代表batch number)│ ├── f0000_14_bn_10_train_label.bin # 用户f0000_14的训练标签│ ├── f0000_14_bn_1_test_data.bin # 用户f0000_14的测试数据 (bn_后面的数字1代表batch number)│ └── f0000_14_bn_1_test_label.bin # 用户f0000_14的测试标签├── f0001_41 # 用户编号│ ├── f0001_41_bn_11_train_data.bin # 用户f0001_41的训练数据 (bn_后面的数字11代表batch number)│ ├── f0001_41_bn_11_train_label.bin # 用户f0001_41的训练标签│ ├── f0001_41_bn_1_test_data.bin # 用户f0001_41的测试数据 (bn_后面的数字1代表batch number)│ └── f0001_41_bn_1_test_label.bin # 用户f0001_41的测试标签│ ...└── f4099_10 # 用户编号├── f4099_10_bn_4_train_data.bin # 用户f4099_10的训练数据 (bn_后面的数字4代表batch number)├── f4099_10_bn_4_train_label.bin # 用户f4099_10的训练标签├── f4099_10_bn_1_test_data.bin # 用户f4099_10的测试数据 (bn_后面的数字1代表batch number)└── f4099_10_bn_1_test_label.bin # 用户f4099_10的测试标签
  • [服务构建器] 【华为云Stack ManageOne 服务构建器】服务构建验证过程脚本修改后快速验证方法总结
    总结一:修改脚本后快速更新模板1. 背景说明在初始服务构建阶段,必然会有调测过程,比如脚本执行失败,或脚本执行完成但并没有到想要的效果,需要修改脚本后再次进行编排验证,这样就涉及到修改脚本、修改模板操作。在portal创建模板并引用脚本资源过程中,整个脚本内容是经过格式化、字符转义后,作为JSON格式模板体源码中一段字符串格式存在的。通过标准方式,即在脚本界面修改脚本,完了在模板界面修改模板并更新图元可以完成修改,但需要在多个界面编辑,且如果原来脚本图元引用了模板中其他资源的输入或输出参数的话,更新图元后这些引用关系也得重新在图形化设计器界面重新再关联,参数分组内容也需要重新编辑修改,这样导致整个脚本修改、再验证的过程效率比较低。如果脚本修改后,能快速通过工具完成格式化、字符转义等操作把脚本转换成界面修改对等的字符串,直接在模板中替换掉原来的脚本字符串,则可以提高效率。2. 格式化脚本操作说明2.1 通过在线JSON编辑工具,先进行转义处理。主要处理脚本文件中双引号、嵌套转义的字符。说明:• 在线JSON编辑工具比较普遍,上网即可搜索。如果有类似功能的本地工具,也可以使用。• 虽然手工也可以编辑,但本着工具优先的原则,及考虑待转义的字符数量、嵌套转义规则要求等,还是优先使用工具比较好。2.2 在notepad++中,将换行效果替换为 \n具体操作如下图。操作完成后,脚本内容就被转换为一行字符串,其中原来的换行被替换成了 \n说明:• 上图查找目标项的具体内容,目的是为了以正则方式匹配回车换行,需要留意当前编辑的脚本具体是那种编码方式,以实际编码情况设置正确的值。Linux系统下是\n,Windows下是 \r\n。2.3 修改模板在图形化设计器界面打开代码区,直接替换脚本图元对应的源码中关键字“template”对应的value值。注意:value值是字符串格式,替换后的脚本内容前后有双引号,保证基本的JSON格式正确。3. 补充说明• 以上操作,适合提前单独验证好脚本基本功能,在最后服务申请验证阶段发现脚本相关问题后,快速更新模板进行调测验证。考虑到模板源码中脚本相应入参还有前后引用及关联,如果验证过程发现脚本要新增入参的情况,还是建议在portal上通过可视化方式来修改脚本、修改模板,避免手动修改引入其他的问题。• 如果使用IDEA开发工具,以上2.1和2.2小节操作过程,则可以快速完成:1),创建一个空的JSON文件(文件扩展名为*.json);2),输入一对双引号(英文格式);3),复制脚本文件内容直接粘贴到JSON文件中两个双引号之间,则IDEA工具会自动完成转义及多行合并效果(即2.1和2.2小节达到的效果);4),复制JSON文件中两端带双引号的全部内容去替换模板源码中的目标内容。总结二:在编排实施创建的资源节点上验证脚本1. 应用说明申请构建的服务后编排实施过程,资源创建成功,脚本执行报错或执行正常但没有达成目标效果,此时,只要资源(比如ECS资源)还在,就可以远程登录ECS后直接手动触发脚本执行,查看执行效果并及时修改再验证。2. 操作说明2.1 登录ManageOne,打开弹性云服务器列表,找到目标资源远程登录,连接到目标系统中。登录用户及认证信息,即申请资源时使用的镜像的默认用户及认证信息。2.2 进入脚本存放目录cd /var/lib/cloud/instance/scripts2.3 手动执行脚本sh -x part-001实际操作中将“part-001”替换为当前目录下真实存在的脚本文件名称。及时查看执行脚本的回显信息,示例:3. 补充说明脚本需要提前单独做好必要的验证,避免遗留较多问题在申请服务、编排实施过程验证,影响构建服务效率,所以以上验证方法只是建议在最终服务申请过程遇到问题时来用。
  • [技术干货] [设计器]RobotInputJs:the json value must be string type
    脚本运行时,提示RobotInputJsonError:the json value must be string type原因分析:此时脚本刚启动尚未运行到控件,所以此类报错大多是当前的xml脚本有异常导致。解决方法:新建一个脚本或者工程,将新的控件action放到此画布里。