summaryrefslogtreecommitdiff
path: root/src/views/menuSysManagement
diff options
context:
space:
mode:
Diffstat (limited to 'src/views/menuSysManagement')
-rw-r--r--src/views/menuSysManagement/index.vue414
-rw-r--r--src/views/menuSysManagement/mock.js135
-rw-r--r--src/views/menuSysManagement/module/Header.vue54
-rw-r--r--src/views/menuSysManagement/module/UserForm.vue245
4 files changed, 848 insertions, 0 deletions
diff --git a/src/views/menuSysManagement/index.vue b/src/views/menuSysManagement/index.vue
new file mode 100644
index 0000000..a729ad8
--- /dev/null
+++ b/src/views/menuSysManagement/index.vue
@@ -0,0 +1,414 @@
+<template>
+ <div class="range-config-manage" ref="appRef">
+ <div class="show">
+ <Header
+ @addRole="addRole"
+ ></Header>
+ <div>
+ <span style="font-size: 20px;margin-bottom: 1%;margin-top: 0.5%;float: left;margin-left: 3%;color: #00C0FF">默认创建的用户具有管理员权限</span>
+ </div>
+ <div class="list" >
+ <el-table
+ class="custom-table"
+ ref="multipleTable"
+ v-loading="loading"
+ element-loading-text="加载中..."
+ height="100%"
+ style="width: 100%;"
+ :data="tableData"
+ tooltip-effect="dark"
+ highlight-current-row
+ >
+ <el-table-column
+ align="center"
+ type="index"
+ label="序号"
+ width="150"/>
+ <el-table-column
+ align="center"
+ prop="account"
+ label="账号"
+ width="280"/>
+ <el-table-column
+ align="center"
+ prop="username"
+ label="姓名"
+ width="250"/>
+ <el-table-column
+ align="center"
+ prop="time"
+ label="创建时间"
+ width="280"/>
+ <el-table-column
+ align="center"
+ prop="created_by"
+ label="创建人"
+ width="280"/>
+ <el-table-column
+ align="center"
+ prop="group"
+ label="权限组"
+ width="280"/>
+ <el-table-column
+ align="center"
+ label="操作"
+ width="250"
+ >
+ <template slot-scope="scope">
+ <el-button type="text" size="small" :loading="scope.row.delLoading" @click="del(scope.row)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+ <el-pagination
+ background
+ :current-page="page"
+ :page-sizes="[10, 20, 30, 40]"
+ :page-size="10"
+ :total="total"
+ layout="total, sizes, prev, pager, next, jumper"
+ @size-change="handleSizeChange"
+ @current-change="handleCurrentChange"
+ >
+ </el-pagination>
+ <div class="mask"></div>
+ <UserForm
+ ref="userForm"
+ :is-add="isAdd"
+ :permission-dict="permissionDict"
+ @refresh="init">
+ </UserForm>
+ </div>
+ </div>
+</template>
+<script>
+import Header from './module/Header.vue'
+import UserForm from './module/UserForm.vue'
+import { getTargetsResponse } from './mock.js'
+export default {
+ name: "RangeConfigManage",
+ components:{ Header, UserForm },
+ data(){
+ return{
+ page: 1,
+ size: 10,
+ total: 0,
+ isAdd: false,
+ loading: false,
+ target_id: '',
+ tableData: [],
+ permissionDict: []
+ }
+ },
+ mounted() {
+
+ },
+ watch: {},
+ created() {
+ this.init()
+ },
+ methods:{
+ init(params={}) {
+ // TODO: 暂时注释接口
+ const reqParams = {
+ "page": this.page,
+ "per_page": this.size,
+ }
+ this.loading = true
+ this.$axios.get(this.$http.api.user, reqParams).then(res => {
+ if (res.code == 200) {
+ this.total = res?.total
+ this.tableData = res?.data
+ this.tableData.map(item => {
+ item.permissions.map(permi => {
+ this.$set(permi, 'delLoading', false)
+ return permi
+ })
+ return item
+ })
+ }
+ }).catch(err => {
+ console.log(err)
+ }).finally(() => {
+ this.loading = false
+ })
+ },
+ query(params) {
+ this.init(params)
+ },
+ // 打开添加角色dialog
+ addRole() {
+ this.isAdd = true
+ // this.$refs.userForm.title = '新增角色'
+ document.querySelector('.mask').style.display = 'block'
+ this.$refs.userForm.visible = true
+ },
+ // 删除权限
+ delPermission(permission, role_id) {
+ const url = this.$http.api.delPermission + '/' + role_id
+ permission.delLoading = true
+ this.$axios.put(url, {}, {permission_id: permission.id}).then(res => {
+ if (res.code == 200 || res.code == "OK") {
+ this.$notify({
+ title: '删除权限成功',
+ type: 'success',
+ duration: 2500
+ })
+ this.init()
+ }
+ }).catch(err => {
+ console.log(err)
+ }).finally(() => {
+ permission.delLoading = false
+ })
+ },
+ // 删除
+ del(row) {
+ this.$confirm('此操作将永久删除该任务, 是否继续?', '确认删除', {
+ confirmButtonText: '确认删除',
+ cancelButtonText: '取消',
+ type: 'info'
+ }).then(() => {
+ this.delUser(row)
+ }).catch(() => {
+ this.$notify({
+ type: 'info',
+ message: '已取消删除'
+ })
+ })
+ },
+ delUser(row) {
+ const url = this.$http.api.delRole + '/' + row.id
+ row.delLoading = true
+ this.$axios.delete(url, {}).then(res => {
+ if (res.code == 200 || res.code == "OK") {
+ this.$notify({
+ title: '删除成功',
+ type: 'success',
+ duration: 2500
+ })
+ this.init()
+ }
+ }).catch(err => {
+ console.log(err)
+ }).finally(() => {
+ row.delLoading = false
+ })
+ },
+ // 详情
+ taskInfo(val) {
+ this.$router.push({ path: 'menuTaskInfo', query: { row: val } });
+ },
+ // 获取权限字典
+ getPermissionDict() {
+ const params = {
+ page: 1,
+ size: 99
+ }
+ this.$axios.get(this.$http.api.getPermissionList, params).then(res => {
+ if (res.code == 200 || res.code == "OK") {
+ this.permissionDict = res?.result?.items.map(item => {
+ return {
+ label: item.permission_name,
+ value: item.id
+ }
+ })
+ }
+ }).catch(err => {
+ console.log(err)
+ })
+ },
+ // 修改每页数据条数
+ handleSizeChange(val) {
+ console.log(`每页 ${val} 条`)
+ this.page=1
+ this.size=val
+ this.query()
+ },
+ // 修改页数
+ handleCurrentChange(val) {
+ console.log(`当前页: ${val}`)
+ this.page=val
+ this.query()
+ }
+ }
+}
+
+</script>
+
+<style lang='less' scoped="scoped">
+ .popup{
+ z-index: 997;
+ width: 40%;
+ height: 70%;
+ position: absolute; /* 绝对定位 */
+ top: 50%; /* 向下偏移50% */
+ left: 50%; /* 向右偏移50% */
+ transform: translate(-50%, -50%); /* 回移50% */
+ background-image:url('../../img/tjpz.svg');
+ background-repeat: no-repeat; /* 可选,防止图像重复 */
+ background-size: 100% 100%; /* 宽度为100%,高度自适应保持宽高比 */
+ .tag{
+ margin-left: 9%;
+ .tags{
+ margin-right: 5%;
+ margin-top: 2%;
+ font-size: 23px;
+ border: none;
+ background-color: transparent !important;
+ color: #565e6e;
+ }
+ }
+ .jbpz{
+ margin-top: 10%;
+ margin-left: 23%;
+ height: 100%;
+ position:relative;
+ .project{
+ display: inline-block;
+ width: 100%;
+ margin-top: 3%;
+ text-align: center;
+ padding-right: 10%;
+
+ }
+ .tar{
+ display: flex;
+ margin-left: 23%;
+ width: 100%;
+ text-align: center;
+ ::v-deep .el-upload-list {
+ margin: 0;
+ list-style: none;
+ width: 300px !important;
+ padding-left: 20%;
+ }
+ .uploadBgImg{
+ margin-top: 5%;
+ width: 300px;
+ height: 40px;
+ background-image: url("../../img/shangchuan.png");
+ background-repeat: no-repeat; /* 可选,防止图像重复 */
+ background-size: 100% auto; /* 宽度为100%,高度自适应保持宽高比 */
+ text-align: right;
+ padding-right: 10%;
+ padding-top: 2%;
+ font-size:0;
+ color: rgba(81, 84, 102, 0.84);
+ }
+ .uploadBgImg::file-selector-button{
+ padding: 0;
+ background-color: transparent;
+ cursor: pointer;
+ font-size: 0;
+ }
+ }
+ .srkType{
+ width: 100%;
+ float: left;
+ margin-top: 2%;
+ text-align: center;
+ .srk{
+ width: 40%;
+ margin-left: 2%;
+ background-color: #0c295b;
+ display: inline-block;
+ border: none;
+ }
+ }
+ .radioType{
+ width: 100%;
+ float: left;
+ margin-top: 2%;
+ text-align: center;
+ }
+ .anType{
+ height: 10%;
+ position:absolute;
+ bottom:4%;
+ left: 50%;
+ transform: translateX(-50%);
+ .glBut{
+ width: 90px;
+ height: 30px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background-color: rgba(24, 133, 234, 0.2);
+ color: #1b7cc4;
+ }
+
+ }
+ }
+ }
+.custom-table {
+ width: 100%;
+ height: 100%;
+ .permission-btn {
+ display: inline-block;
+ margin: 6px;
+ padding: 5px 8px;
+ border-radius: 3px;
+ color:rgba(0, 0, 0, 0.90);
+ background: #02DDEA;
+ }
+}
+.range-config-manage{
+ width: 100%;
+ height: 100%;
+ /*background-color: #010f4e;*/
+ // background-color: rgba(255, 25, 49, 0.4);
+ float: right;
+ position: relative; /* 确保相对定位生效 */
+
+ .show{
+ width: 95%;
+ height: 95%;
+ /*background-color: #67c23a;*/
+ position: absolute; /* 绝对定位 */
+ top: 50%; /* 向下偏移50% */
+ left: 50%; /* 向右偏移50% */
+ transform: translate(-50%, -50%); /* 回移50% */
+ background-image:url('../../img/backgroundFourCorner.png');
+ background-repeat: no-repeat; /* 可选,防止图像重复 */
+ background-size: 100% 100%; /* 宽度为100%,高度自适应保持宽高比 */
+ /*background-size: cover; !* 宽度为100%,高度自适应保持宽高比 *!*/
+
+ /*display: flex; !* 将容器设置为 Flex 容器 *!*/
+ /*justify-content: center; !* 水平居中子元素 *!*/
+ /*align-items: center; !* 垂直居中子元素 *!*/
+
+ .list{
+ width: 95%;
+ height: 77%;
+ margin-left: 2.5%;
+ overflow-y: auto;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ border: none;
+ }
+ .list::-webkit-scrollbar {
+ width: 0px; /* 隐藏滚动条 */
+ height: 0px;
+ background-color: transparent; /* 让背景透明 */
+
+ }
+ /* 隐藏火狐浏览器滚动条 */
+ @-moz-document url-prefix() {
+ .trackSource {
+ scrollbar-width: none;
+ }
+ }
+ // 遮罩层
+ .mask{
+ position: fixed; /*将元素设置为固定定位*/
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ background-color: rgba(0,0,0,0.5); /*通过rgba函数来控制遮罩层的透明度*/
+ display: none; /*将元素隐藏*/
+ }
+ }
+}
+</style>
diff --git a/src/views/menuSysManagement/mock.js b/src/views/menuSysManagement/mock.js
new file mode 100644
index 0000000..667bb35
--- /dev/null
+++ b/src/views/menuSysManagement/mock.js
@@ -0,0 +1,135 @@
+const getTargetsResponse = {
+ "code": 200,
+ "message": "success",
+ "result": {
+ "items": [
+ {
+ "role_name": "admin",
+ "id": 1,
+ "create_time": "2024-01-31T10:22:45",
+ "permissions": [
+ {
+ "permission_name": "靶场配置管理",
+ "id": 1,
+ "create_time": "2024-01-30T10:03:03"
+ },
+ {
+ "permission_name": "靶场节点管理",
+ "id": 2,
+ "create_time": "2024-01-30T10:03:48"
+ },
+ {
+ "permission_name": "个人管理",
+ "id": 3,
+ "create_time": "2024-01-30T10:04:18"
+ },
+ {
+ "permission_name": "国家网络管理",
+ "id": 4,
+ "create_time": "2024-01-30T10:04:50"
+ },
+ {
+ "permission_name": "镜像管理",
+ "id": 5,
+ "create_time": "2024-01-30T10:05:07"
+ },
+ {
+ "permission_name": "用户管理",
+ "id": 6,
+ "create_time": "2024-01-30T10:05:30"
+ },
+ {
+ "permission_name": "角色管理",
+ "id": 7,
+ "create_time": "2024-01-30T10:06:22"
+ },
+ {
+ "permission_name": "首页",
+ "id": 8,
+ "create_time": "2024-01-30T10:07:01"
+ }
+ ]
+ },
+ {
+ "role_name": "developer",
+ "id": 2,
+ "create_time": "2024-01-31T11:29:17",
+ "permissions": [
+ {
+ "permission_name": "靶场配置管理",
+ "id": 1,
+ "create_time": "2024-01-30T10:03:03"
+ },
+ {
+ "permission_name": "靶场节点管理",
+ "id": 2,
+ "create_time": "2024-01-30T10:03:48"
+ },
+ {
+ "permission_name": "个人管理",
+ "id": 3,
+ "create_time": "2024-01-30T10:04:18"
+ },
+ {
+ "permission_name": "国家网络管理",
+ "id": 4,
+ "create_time": "2024-01-30T10:04:50"
+ },
+ {
+ "permission_name": "镜像管理",
+ "id": 5,
+ "create_time": "2024-01-30T10:05:07"
+ },
+ {
+ "permission_name": "用户管理",
+ "id": 6,
+ "create_time": "2024-01-30T10:05:30"
+ },
+ {
+ "permission_name": "角色管理",
+ "id": 7,
+ "create_time": "2024-01-30T10:06:22"
+ },
+ {
+ "permission_name": "首页",
+ "id": 8,
+ "create_time": "2024-01-30T10:07:01"
+ }
+ ]
+ },
+ {
+ "role_name": "experimenter",
+ "id": 3,
+ "create_time": "2024-01-31T11:33:05",
+ "permissions": [
+ {
+ "permission_name": "靶场配置管理",
+ "id": 1,
+ "create_time": "2024-01-30T10:03:03"
+ },
+ {
+ "permission_name": "靶场节点管理",
+ "id": 2,
+ "create_time": "2024-01-30T10:03:48"
+ },
+ {
+ "permission_name": "个人管理",
+ "id": 3,
+ "create_time": "2024-01-30T10:04:18"
+ },
+ {
+ "permission_name": "镜像管理",
+ "id": 5,
+ "create_time": "2024-01-30T10:05:07"
+ }
+ ]
+ }
+ ],
+ "total": 3,
+ "page": 1,
+ "size": 10,
+ "pages": 1
+ }
+}
+
+export { getTargetsResponse } \ No newline at end of file
diff --git a/src/views/menuSysManagement/module/Header.vue b/src/views/menuSysManagement/module/Header.vue
new file mode 100644
index 0000000..186eabf
--- /dev/null
+++ b/src/views/menuSysManagement/module/Header.vue
@@ -0,0 +1,54 @@
+<template>
+<div class="head">
+ <div class="target-select">
+ <span style="font-size: 30px;float: left;padding-top: 1%">用户列表</span>
+ </div>
+<!-- <img class="add-btn" src="../../../img/btn/addRoleBtn.svg" @click="addRole">-->
+ <el-row>
+ <el-button type="primary" plain @click="addRole">新建用户</el-button>
+ </el-row>
+</div>
+</template>
+
+<script>
+export default {
+ name: 'Header',
+ props: [],
+ data() {
+ return {
+ role_name: ''
+ }
+ },
+ watch: {},
+ methods: {
+ // 新增
+ addRole() {
+ this.$emit('addRole')
+ }
+ }
+}
+</script>
+
+<style lang="less" scoped>
+.head{
+ width: 95%;
+ height: 7%;
+ margin-top: 1%;
+ margin-left: 2.5%;
+ text-align: right;
+ .target-select{
+ font-size: 10px;
+ float: left;
+ margin-top: 0.5%;
+ display: inline-block;
+ height: 60%;
+ width: 10%;
+ margin-left: 0.5%;
+ }
+ .add-btn {
+ height: 70%;
+ width: 10%;
+ color: #ffffff;
+ }
+}
+</style> \ No newline at end of file
diff --git a/src/views/menuSysManagement/module/UserForm.vue b/src/views/menuSysManagement/module/UserForm.vue
new file mode 100644
index 0000000..7628749
--- /dev/null
+++ b/src/views/menuSysManagement/module/UserForm.vue
@@ -0,0 +1,245 @@
+<template>
+ <div
+ class="user-dialog"
+ v-if="visible"
+ >
+<!-- <span class="dialog-title">{{ title }}</span>-->
+ <span class="dialog-title">用户创建</span>
+ <!-- 在此处指定弹窗的样式和内容 -->
+ <i class="el-icon-close" style="float: right; padding-right: 8%;padding-top: 3%" @click="close"></i>
+ <el-form
+ ref="userForm"
+ :model="form"
+ :rules="rules"
+ label-width="180px"
+ class="user-form"
+ >
+ <el-row style="margin-left: 5%;margin-top: 8%">
+ <el-col :span="19">
+ <el-form-item label="姓名" prop="username">
+ <el-input v-model="form.username" placeholder="请输入姓名"></el-input>
+ </el-form-item>
+ <el-form-item label="账号" prop="domain">
+ <el-input v-model="form.account" placeholder="请输入账号"></el-input>
+ </el-form-item>
+ <el-form-item label="密码" prop="inject">
+ <el-input v-model="form.pwd" placeholder="请输入密码"></el-input>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <div class="submit-footer" style="margin-top: 10%">
+ <div>
+ <el-button class="glBut" type="primary" @click="close">取消</el-button>
+ <el-button class="glBut but-color" type="primary" @click="submit" :loading="loading">确认创建</el-button>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+export default {
+ name: 'UserForm',
+ // props: ['isAdd', 'permissionDict'],
+ data() {
+ return {
+ agencyLabel:false,
+ visible: false,
+ loading: false,
+ title: '任务创建',
+ form: {
+ account:"", //代理名称
+ cur_user:"", //任务目标
+ pwd:"", //执行代理
+ username:"", //目标域名
+ },
+ role_id: '',
+ rules: {
+ account: [
+ // { required: true, message: '请输入任务名称', trigger: 'blur' },
+ { message: '请输入任务名称', trigger: 'blur' },
+ { max: 50, message: '任务名称长度不能超过50个字符', trigger: 'blur' }
+ ],
+ pwd: [
+ // { required: true, message: '请输入任务名称', trigger: 'blur' },
+ { message: '请输入任务名称', trigger: 'blur' },
+ { max: 50, message: '任务名称长度不能超过50个字符', trigger: 'blur' }
+ ],
+ username: [
+ // { required: true, message: '请输入任务名称', trigger: 'blur' },
+ { message: '请输入任务名称', trigger: 'blur' },
+ { max: 50, message: '任务名称长度不能超过50个字符', trigger: 'blur' }
+ ],
+ permissions: [
+ { required: true, message: '请选择权限', trigger: 'change' }
+ ],
+
+ },
+ roleDict:[],
+ strategy:[
+ { value: 'auto', label: '自动选择', type: 'success' },
+ { value: 'ddos', label: '拒绝服务', type: 'warning' },
+ { value: 'sjqp', label: '数据欺骗', type: 'warning' },
+ ],
+ agencyChange:[
+ { value: '中国北京', label: '中国北京', type: 'success' },
+ { value: '美国纽约', label: '美国纽约', type: 'warning' },
+ ],
+ stateAwareMode:[
+ { value: 'auto', label: '自动选择', type: 'success' },
+ { value: 'tcp', label: 'TCP时延', type: 'warning' },
+ { value: 'icmp', label: 'ICMP/v6', type: 'danger' },
+ { value: 'dns', label: 'DNS解析时延', type: 'danger' },
+ { value: 'record', label: '记录正确性验证', type: 'danger' },
+ ],
+ operationalConfiguration:[
+ { value: 'now', label: '立刻执行', type: 'success' },
+ { value: 'man', label: '手动执行', type: 'warning' },
+ ]
+
+
+ }
+ },
+ methods: {
+ getTagsByIP(val){
+ let data={
+ "ip":val?val:'1.1.1.1'
+ }
+ this.$axios.get(this.$http.api.targetQueryList,data).then(res=>{
+ if(res.code===200){
+ this.roleDict=res?.data[0]?.protect
+ }
+ }).catch(err=>{
+ console.log(err)
+ })
+
+
+ },
+ close() {
+ this.resetForm()
+ document.querySelector('.mask').style.display = 'none'
+ this.visible = false
+ },
+ submit() {
+ let data={
+ "account":this.form.account,
+ "cur_user":"获取当前用户",
+ "pwd":this.form.pwd,
+ "username":this.form.username,
+ }
+ this.$axios.post(this.$http.api.user,data).then(res=>{
+ if(res.code===200){
+ this.$message.success('创建成功!')
+ }else {
+ this.$message.error(res.msg)
+ }
+ }).catch(err=>{
+ console.log(err)
+ })
+
+ },
+ add () {
+ this.loading = true
+ const url = this.$http.api.addRole
+ this.$axios.post(url, this.form).then(res => {
+ if (res.code == 200 || res.code == "OK") {
+ this.resetForm()
+ this.close()
+ this.$emit('refresh')
+ this.$notify({
+ title: '创建角色成功',
+ type: 'success',
+ duration: 2500
+ })
+ }
+ }).catch(err => {
+ console.log(err)
+ }).finally(() => {
+ this.loading = false
+ })
+ },
+ edit() {
+ this.loading = true
+ const url = this.$http.api.editRole + `/${this.role_id}`
+ this.$axios.put(url, this.form.permissions).then(res => {
+ if (res.code == 200 || res.code == "OK") {
+ this.resetForm()
+ this.close()
+ this.$emit('refresh')
+ this.$notify({
+ title: '编辑角色成功',
+ type: 'success',
+ duration: 2500
+ })
+ }
+ }).catch(err => {
+ console.log(err)
+ }).finally(() => {
+ this.loading = false
+ })
+ },
+ resetForm() {
+ this.agencyLabel=false,
+ this.roleDict=[],
+ this.form = {
+ name:"", //代理名称
+ ip:"", //任务目标
+ agencyChange:"", //执行代理
+ domain:"", //目标域名
+ inject:"", //期望注入记录
+ strategy:"",//策略
+ stateAwareMode:"",//状态感知方式
+ switchoverTime:"", //策略切换时限
+ executeTime:"", //任务执行时限
+ operationalConfiguration:"",//运行配置
+ }
+ }
+ }
+}
+</script>
+
+<style lang="less" scoped>
+ .user-dialog{
+ width: 563px;
+ height: 463px;
+ position: absolute; /* 绝对定位 */
+ top: 50%; /* 向下偏移50% */
+ left: 50%; /* 向右偏移50% */
+ transform: translate(-50%, -50%); /* 回移50% */
+ /*background-image:url('../../../img/background/dialog520-363.svg');*/
+ background-image:url('../../../img/tjpz.svg');
+ background-repeat: no-repeat; /* 可选,防止图像重复 */
+ background-size: 100% 100%; /* 宽度为100%,高度自适应保持宽高比 */
+ .dialog-title {
+ font-size: 20px;
+ float: left;
+ margin: 11px 0 11px 35px;
+ }
+ .user-form {
+ margin-top: 70px;
+ text-align: left;
+ ::v-deep .el-form-item__content {
+ line-height: 15px;
+ }
+ }
+ .submit-footer{
+ width: 100%;
+ float: left;
+ margin-top: 50px;
+ text-align: center;
+ .glBut{
+ width: 90px;
+ height: 30px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ margin-left: 2%;
+ background-color: rgba(24, 133, 234, 0.2);
+ color: #1b7cc4;
+ }
+ .but-color {
+ background-color: #02DDEA;
+ }
+ }
+ }
+</style> \ No newline at end of file