npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vsoft_liu/vsoft-emr

v1.0.159

Published

Vue 3 电子病历编辑器组件,基于 ThinkEditor SDK

Readme

@vsoft_liu/vsoft-emr — ThinkEditor Vue3 组件

基于 ThinkEditor SDK 封装的 Vue3 电子病历编辑器组件,提供完整的电子病历编辑功能。

文件结构

VsoftEmr/
├── index.ts              # 入口文件,导出组件、类型和枚举
├── VsoftEmr.vue          # 主组件文件(SDK 封装层)
├── types.ts              # TypeScript 类型定义
├── enums.ts              # 枚举定义(统一 re-export @vsoft_liu/vsoft-editor 的 VS_ENUM_* 枚举)
├── config/               # 配置系统
│   ├── EmrEditorConfig.ts  # 主配置接口(含字段类型接口和映射函数)
│   ├── EmrServiceProviders.ts # 服务提供者接口
│   ├── rolePresets.ts      # 角色预设配置
│   ├── (mock 服务已移至 demo 层 src/mock/,组件库不包含 mock)
│   ├── utils.ts            # 配置工具函数(deepMerge 等)
│   └── injectionKeys.ts    # Vue provide/inject 键
├── full/                 # 完整编辑器 UI
│   ├── FullEditor.vue      # 主文件(工具栏 + 侧边面板 + 状态栏)
│   ├── EditorToolBar.vue   # 主工具栏
│   ├── DocToolBar.vue      # 文档工具栏(由 VsoftEditor 提供)
│   ├── StatusBar.vue       # 底部状态栏
│   ├── DocTabsBar.vue      # 多文档标签栏
│   ├── panels/             # 面板组件
│   │   ├── LeftPanel.vue     # 左侧面板(独占手风琴)
│   │   ├── RightPanel.vue    # 右侧面板(属性面板)
│   │   ├── FieldGroup.vue    # 字段分类递归渲染组件
│   │   ├── OutlineTreeNode.vue # 大纲树节点组件
│   │   └── content/         # 右侧面板内容组件
│   ├── toolbars/           # 工具栏子组件
│   ├── composables/        # useTheme.ts 等
│   ├── hooks/              # 组合式函数
│   ├── dialogs/            # 对话框组件
│   ├── styles/             # CSS 样式
│   └── icons.ts            # SVG 图标
└── README.md             # 说明文档

快速开始

1. 安装

pnpm add @vsoft_liu/vsoft-emr
# 或
npm install @vsoft_liu/vsoft-emr

@vsoft_liu/vsoft-emr 内部通过 @vsoft_liu/vsoft-editor 依赖自动管理 SDK 运行时(含 .wasm 文件)。

2. 引入组件

import { VsoftEmr, VS_ENUM_VIEW_MODE, VS_ENUM_DOC_TYPE, VS_ENUM_DOC_FORMAT } from '@vsoft_liu/vsoft-emr'
import '@vsoft_liu/vsoft-emr/styles'

3. 使用组件

<template>
  <VsoftEmr
    ref="emrRef"
    :lib-path="libPath"
    :font-path="fontPath"
    width="100%"
    height="100%"
    :view-mode="VS_ENUM_VIEW_MODE.Edit"
    @ready="onReady"
    @doc-modified="onModified"
  />
</template>

<script setup>
import { ref } from 'vue'
import { VsoftEmr, VS_ENUM_VIEW_MODE, VS_ENUM_DOC_TYPE, VS_ENUM_DOC_FORMAT } from '@vsoft_liu/vsoft-emr'
import '@vsoft_liu/vsoft-emr/styles'

const emrRef = ref(null)
const libPath = '/think-editor-sdk/'
const fontPath = '/fonts/'

const onReady = (editor) => {
  console.log('编辑器就绪', editor)
  // 新建文档
  emrRef.value.newDoc('myDoc', VS_ENUM_DOC_TYPE.Template)
}

const saveDoc = () => {
  const xml = emrRef.value.getDoc(VS_ENUM_DOC_FORMAT.XML, VS_ENUM_DOC_TYPE.Entity)
  console.log('文档数据:', xml)
}
</script>

组件 Props

| 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | libPath | string | '' | SDK库文件路径 | | fontPath | string | '' | 字体文件路径 | | width | number/string | '100%' | 容器宽度 | | height | number/string | '100%' | 容器高度 | | viewMode | VS_ENUM_VIEW_MODE | VS_ENUM_VIEW_MODE.Edit | 视图模式 | | displayScale | number | 1 | 显示缩放比例 | | pagesLayoutMode | number | 1 | 页面布局模式 | | docName | string | '' | 文档名称 | | docType | VS_ENUM_DOC_TYPE | VS_ENUM_DOC_TYPE.Template | 文档类型 | | editable | boolean | true | 是否可编辑 | | docOpenMode | 'single' | 'multi' | 'single' | 文档打开模式(单文档/多文档) | | showToolbar | boolean | false | 已废弃,请使用 FullEditor 组件 | | showStatusBar | boolean | false | 是否显示内置状态栏 | | enableContextMenu | boolean | false | 是否启用右键菜单 | | enableShortcutKeys | boolean | false | 是否启用快捷键 |

组件 Events

| 事件名 | 参数 | 说明 | |--------|------|------| | ready | vsEditor: VSEditor | null | 编辑器就绪(多文档模式为 null) | | load | data: any | 文档加载完成 | | unload | - | 文档卸载 | | focus | - | 获得焦点 | | blur | - | 失去焦点 | | error | error: Error | 错误事件 | | docChange | docName: string | 文档切换 | | docModified | modified: boolean | 文档修改状态改变 | | focusChange | properties: FocusProperties | 焦点属性改变 | | elementChange | data: any | 元素改变 | | undoCountChange | count: number | 撤销次数改变 | | redoCountChange | count: number | 重做次数改变 | | viewModeChange | mode: VS_ENUM_VIEW_MODE | 视图模式改变 | | scaleChange | scale: number | 缩放比例改变 | | fontFormatChange | data: any | 字体格式改变 | | paragraphStyleChange | data: any | 段落样式改变 | | printDoc | data: any | 打印文档 | | closeDoc | docName: string | 关闭文档 | | requestSources | data: any | 请求源 | | requestFont | data: any | 请求字体 | | shortcut | keyCombo: string, event: KeyboardEvent | 快捷键触发(由 FullEditor 处理) | | saveDoc | docName: string | 保存文档(Ctrl+S) |

内置 UI 功能

VsoftEmr 组件支持内置工具栏、状态栏、右键菜单和快捷键功能,可通过 props 开启。

FullEditor 内置 UI

通过 FullEditor 组件可获得完整编辑器体验:菜单栏 + 工具栏 + 左右侧边面板 + 状态栏。

工具栏/菜单栏禁用状态:按钮受 isReady(SDK 初始化)和 hasDoc(有文档打开)双重控制。无文档时,除新建/打开/面板切换/主题外的按钮全部 disabled。元素库内容在无文档时也禁用。

两侧面板:LeftPanel 为独占手风琴模式(同一时间只展开一个面板,展开的面板占据剩余空间,内部滚动)。RightPanel 为手风琴模式。宽度可通过拖拽分隔条调整(150~600px)。拖到最小宽度后持续向内拉 1.5 秒自动关闭面板。

菜单栏右侧:显示当前用户名称和科室铭牌(1px 焦点色边框 + 渐变背景),数据来自 config 的 user.userName 和 user.department。

左侧面板:包含任务、模板、患者文档、文档大纲、元素库、部件库、快速短语等手风琴面板(按角色配置可见性)。面板顺序和可见性由配置文件的 PanelTabConfig.order 字段驱动(动态渲染,非硬编码顺序)。"模板"和"患者文档"的数据通过不同渠道注入:

// services(后端服务,含模板/字段数据)
services: {
  onLoadTemplateList: async () => [...],         // 返回 TemplateTreeNode[]
  onLoadTemplate: async (id) => `<xml>...</xml>`, // 返回模板 XML
  onLoadFieldScenarios: async () => [...],        // 返回 FieldScenario[]
  onLoadFieldData: async (scenarioId?) => [...],  // 返回 FieldDataCategory[]
}
// providers(仅 tasks——静态/响应式数据)
providers: {
  tasks: TaskItem[],                                // 任务列表数据(响应式)
}
// panelProviders(面板特定数据——仅 patientDocs)
panelProviders: {
  patientDocs: async (type, ...args) => {...},    // 患者文档树数据
}

单击节点选中,双击触发 open-template / open-patient-doc 事件。右键树节点弹出各自独立的上下文菜单(新建/重命名/删除),通过 template-menu-action / patient-doc-menu-action 事件传出。Mock 数据在 src/mock/mockServices.ts。

患者管理(HIS Shell 层):患者列表侧边栏在 App.vue 管理(非编辑器组件内部),仅 Doctor/Nurse/Director 角色可见。点击患者自动切换到患者文档面板(switchLeftTab('patientDocs')),患者信息卡片显示在患者文档面板顶部(床号/姓名/诊断/护理级别/住院天数/出院标记)。

菜单栏:单行强制不换行,每个下拉菜单项显示 SVG 图标(圆角 + 填充形状风格),约 80 个菜单项通过 MENU_ICON_MAP 映射。

任务列表面板:标题带角标显示任务数量(0 显示"无"),数据通过 providers.tasks 注入,响应式更新。点击任务触发 task-click 事件。

快速短语面板:按分类显示常用短语(主诉、体格检查等),支持拖拽和点击插入。数据通过 services.onLoadQuickPhrases 懒加载,展开面板时自动加载。仅 Doctor/Nurse 角色可见。

多视图标签页:中部主体区域支持编辑器文档和自定义视图共存。通过 registerTab API 注册自定义标签(如影像查看器、检验面板),通过 #custom-view slot 渲染自定义内容。DocTabsBar 根据 tab.type 显示不同样式(自定义标签支持自定义图标和颜色)。

// 注册自定义视图
fullRef.registerTab({
  key: 'exam:ct-001',
  title: '胸部CT报告',
  type: 'custom',
  icon: '🔬',
  color: '#e67e22',
})

配置上下文层级:

{
  user: { userId, userName, department, title, licenseNumber, signatureUrl, ... },  // 归属科室
  organization: { orgId, orgName },    // 部署级
  department: { department, ward },    // 会话级(工作科室)
  consultation: { consultationId, type, role },  // 会诊时
  patient: { patientId, name, department, bedNo, nursingLevel, status },  // 就诊级
}

FullEditor 额外暴露的 API:

  • switchLeftTab(tabId: string) — 展开左侧面板的指定 tab(同时更新 activeTab 和 expandedSections),用于患者切换时自动跳转
  • registerTab / unregisterTab / switchToTab — 多视图标签页管理

开启内置 UI

<VsoftEmr
  :show-toolbar="true"
  :show-status-bar="true"
  :enable-context-menu="true"
  :enable-shortcut-keys="true"
  @shortcut="onShortcut"
  @save-doc="onSaveDoc"
/>

内置工具栏按钮

| 分组 | 按钮 | |------|------| | 文件 | 新建、打开、保存、打印 | | 剪贴板 | 撤销、重做、复制、剪切、粘贴 | | 格式 | 加粗(B)、倾斜(I)、下划线(U)、删除线(S) | | 段落 | 左对齐、居中、右对齐 | | 插入 | 表格、图片、公式 | | 视图 | 放大、缩小、缩放显示 |

快捷键支持

| 快捷键 | 功能 | |--------|------| | Ctrl+Z | 撤销 | | Ctrl+Y / Ctrl+Shift+Z | 重做 | | Ctrl+C | 复制 | | Ctrl+X | 剪切 | | Ctrl+V | 粘贴 | | Ctrl+A | 全选 | | Ctrl+B | 加粗 | | Ctrl+I | 倾斜 | | Ctrl+U | 下划线 | | Ctrl+S | 保存(触发 saveDoc 事件) | | Ctrl+P | 打印 | | Ctrl+= | 放大 | | Ctrl+- | 缩小 | | Delete/Backspace | 删除选中内容 |

右键菜单

  • 撤销、重做
  • 分隔线
  • 复制、剪切、粘贴、删除、全选
  • 分隔线
  • 格式子菜单(加粗、倾斜、下划线)
  • 插入子菜单(表格、图片)

状态栏显示

  • 文档名 / 文档数量(多文档模式)
  • 修改状态(已修改/未修改)
  • 撤销/重做计数
  • 视图模式
  • 缩放比例

暴露的 API 方法

组件通过 defineExpose 暴露以下方法,可通过 ref 调用:

文档操作

// 新建空文档
newDoc(docName: string, docType?: E_DOC_TYPE): boolean

// 创建文档
createDoc(docName: string): any

// 解析文档
parseDoc(docName: string, xml: string | ArrayBuffer, jsonCfg?: object): boolean

// 获取文档数据
getDoc(docFormat?: E_DOC_FORMAT, docType?: E_DOC_TYPE, jsonCfg?: object): string

// 获取PDF
getPDF(jsonCfg?: object): Promise<any>

// 获取页影像
getPagesImage(imageType?: E_IMAGE_TYPE, startIndex?: number, pagesCount?: number, scale?: number): any

// 关闭文档
closeDoc(docName: string): void

// 选择文档
selectDoc(docName: string, jsonCfg?: object): any

// 显示文档
visibleDoc(docName: string): any

编辑操作

// 撤销/重做
undo(count?: number): void
redo(count?: number): void

// 复制/剪切/粘贴
copy(): void
cut(): void
paste(pasteType?: E_PASTE_TYPE): Promise<void>
deleteSelection(): void
selectAll(): any

// 格式刷
setFormatBrush(brushState: E_BRUSH_STATE): void
clearFormat(): void

字体格式

setFontType(fontName: string): void
setFontSize(fontSize: number): void
setFontSizeItem(fontItem: string): any
setFontColor(color: string | number): void
setFontBackColor(color: string | number): void
setFontBold(bold: boolean): void
setFontItalic(italic: boolean): void
setFontUnderline(underline: boolean): void
setFontStrikethrough(strikethrough: boolean): void
setFontScript(scriptMode: E_SCRIPT_MODE): void
setFontFerrule(mode: E_FERRULE_MODE): void
displayFontSetWindow(displayMode: E_DISPLAY_MODE): void

段落操作

insertParagraph(jsonCfg?: object): boolean
deleteParagraph(jsonCfg: object): boolean
setParagraphConfig(identity: object, config: object): boolean
setParagraphContent(id: string, content: string, jsonCfg?: object): any
setParagraphAlignContent(alignmentHorizontalMode: E_ALIGN_HORIZONTAL_MODE): void
setParagraphListMode(listMode: E_LIST_MODE): any
setParagraphListLevel(listLevel: E_LIST_LEVEL): void
setParagraphLeftIndent(indent: number): void
setParagraphRightIndent(indent: number): void
setParagraphSpaceBefore(space: number): void
setParagraphSpaceAfter(space: number): void
setParagraphLineSpacingRule(rule: number): void
setParagraphLineSpacingValue(value: number): void

表格操作

insertTable(jsonCfg: TableConfig): boolean
deleteTable(identity: object): boolean
getTableProperties(identity: object, jsonCfg?: object): any
setTableConfig(id: string, jsonCfg: object): boolean
setTableData(identity: object, tableXml: string | ArrayBuffer, config?: object): boolean
setCellContent(param: object): boolean
tableInsertOpt(insertMode: E_TABLE_INSERT_MODE): void
tableDeleteOpt(deleteMode: E_TABLE_DELETE_MODE): void
cellOpt(mode: E_CELL_OPT_MODE): void

元素操作

insertElement(jsonCfg: ElementConfig): boolean
deleteElement(id: string, jsonCfg?: object): boolean
setElementConfig(identity: object, config?: object): boolean
setElementContent(id: string, content: string, jsonCfg?: object): boolean
setElementsContent(paramArr: object[], jsonCfg?: object): boolean
getElementProperties(identity?: object, config?: object): any[]
getElementsContent(identity: object, jsonCfg?: object): any[]
setElementIdentity(id: string, newId: string, newName: string): boolean
setElementBase(id: string, hint: string, tip: string, startBorder: string, endBorder: string, beforeTag: string, afterTag: string): boolean
setElementInputText(id: string): boolean
setElementInputNumber(id: string): boolean
setElementSelectOption(id: string, optionClass: string, optionId: string, itemLinkStr: string, elementCfg: any): any
setElementSelectDateTime(id: string, dateType: E_TIME_TYPE): any

图片操作

insertImage(id: string, width: number, height: number, filename: string, arrayBuffer: ArrayBuffer, dataLen: number, jsonCfg?: object): string
insertImageBase64(id: string, width: number, height: number, filename: string, base64Str: string, base64StrLen: number, jsonCfg?: object): boolean
setImageConfig(id: string, jsonCfg: object): boolean
setsetImageResource(imageName: string, arrayBuffer: ArrayBuffer, dataLen: number, jsonCfg?: object): string
setsetImageResourceBase64(fileName: string, base64Str: string, base64StrLen: number, jsonCfg?: object): string

条形码/二维码

insertBarCode(jsonCfg: BarcodeConfig): boolean
getBarCodeList(): object
getBarCodeClass(barcodeType: E_BARCODE_TYPE): number
calcBarCodeProperties(jsonCfg: object): object
setBarCodeConfig(id: string, jsonCfg: object): boolean

其他插入

// 公式
insertFormula(jsonCfg: FormulaConfig): boolean
getFormulaProperties(jsonCfg?: object): object
setFormulaConfig(id: string, jsonCfg: object): boolean

// 选框
insertCheckBox(jsonCfg: CheckBoxConfig): boolean
insertCheckBoxGroup(jsonCfg: object): boolean
getCheckBoxProperties(identity?: object): object
setCheckBoxConfig(identity: object, config: object): boolean

// 页码
insertPageNum(jsonCfg: object): boolean
setPageNumConfig(id: string, jsonCfg: object): boolean

// 特殊对象
insertPageFeed(count?: number): any
insertLineFeed(count?: number): any
insertSeparator(width: number, height: number, jsonCfg: object): boolean
insertButton(jsonCfg: object): any
insertAnnotate(id: string, fragment: string, jsonCfg?: object): any

// 批注
insertComment(id: string, fragment: string, jsonCfg?: object): any
deleteComment(jsonCfg: object): boolean
insertReplyComment(fragment: string, jsonCfg?: object): any
deleteReplyComment(jsonCfg: object): boolean
setCommentResolve(jsonCfg: object): boolean
selectComments(jsonCfg?: object): any
getCommentReport(): any

视图操作

setViewMode(viewMode: E_VIEW_MODE, cfg?: object): void
setDisplayScale(pagesLayoutMode: number, value: number): void
resizeViewPanel(width: number, height: number): boolean

水印设置

setWaterMarkConfig(id: string, jsonCfg?: object): any
getWaterMarkReport(): any
setBackgroundColor(backColor: string): void

页面设置

setPageConfig(jsonCfg: PageConfig): any
getPageProperties(): any
setHeaderConfig(jsonCfg: object): any
setFooterConfig(jsonCfg: object): any
displayPageSetWindow(displayMode: E_DISPLAY_MODE): void

查找替换

search(searchCfg: SearchConfig): any
searchReplace(searchCfg: SearchConfig): any
displaySearchReplaceWindow(displayMode: E_DISPLAY_MODE): void

打印

printDoc(jsonCfg?: PrintConfig): Promise<void>
displayPrintSetWindow(displayMode: E_DISPLAY_MODE, jsonCfg?: object): void

知识库

setOptions(options: object): any
delOptions(options: object): any
setAlgorithms(algorithms: object): any
delAlgorithms(algorithms: object): any
getSourceList(docName: string): object
getAlgorithmList(): object
getOptionList(): object

数据源

setSource(sourceClass: string, sourceId: string, fragment: string): boolean
setSystemSource(sourceClass: string, sourceId: string, fragment: string): any
setSources(sources: SourceData[], jsonCfg?: object): boolean
setDataSources(obj: object | undefined, param: object): boolean
getDataSources(identity?: object): object
getDocSourceReport(docName: string): any

质控

getQualityControlReport(): any
selectQualityControl(jsonCfg: object): any

审阅痕迹

getReviseReport(jsonCfg?: object): any
selectRevise(jsonCfg: object): any
setReviseConfig(jsonCfg: object): any

其他

getFocusProperties(jsonCfg?: object): FocusProperties
setInputFocus(state: boolean): void
setEditorFocus(): void
getSelectRangeContent(docFormat: E_DOC_FORMAT, jsonCfg?: object): string
getObjectFragment(identityObjectType: E_IDENTITY_OBJECT_TYPE, id: string, docFormat: E_DOC_FORMAT, jsonCfg?: object): any
selectObject(identity: object, config: object): boolean
updateServerTime(serverTime: string): void
loadFont(fontName: string, arrayBuffer: ArrayBuffer): boolean
setUserProfile(settings: object): boolean
setEditorConfig(obj: object): any
getMenu(): any
displayMessageBoxWindow(displayMode: E_DISPLAY_MODE, jsonCfg: object): void
displaySpecialSymbolSetWindow(displayMode: E_DISPLAY_MODE): void
addEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: boolean | AddEventListenerOptions): void
removeEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: boolean | EventListenerOptions): void
destroyEditor(): void

枚举值

组件导出了完整的枚举定义(来自 @vsoft_liu/vsoft-editor 的 VS_ENUM_* 枚举),包括:

  • VS_ENUM_VIEW_MODE - 视图模式
  • VS_ENUM_DOC_FORMAT - 文档格式
  • VS_ENUM_DOC_TYPE - 文档类型
  • VS_ENUM_IMAGE_TYPE - 图像类型
  • VS_ENUM_PASTE_TYPE - 粘贴类型
  • VS_ENUM_BRUSH_STATE - 格式刷状态
  • VS_ENUM_DISPLAY_MODE - 显示模式
  • VS_ENUM_SET_MODE - 设置模式
  • VS_ENUM_SCRIPT_MODE - 上下标模式
  • VS_ENUM_FERRULE_MODE - 套圈模式
  • VS_ENUM_LIST_MODE - 列表模式
  • VS_ENUM_LIST_LEVEL - 列表级别
  • VS_ENUM_ALIGN_HORIZONTAL_MODE - 水平对齐
  • VS_ENUM_ALIGN_VERTICAL_MODE - 垂直对齐
  • VS_ENUM_TABLE_INSERT_MODE - 表格插入模式
  • VS_ENUM_TABLE_DELETE_MODE - 表格删除模式
  • VS_ENUM_CELL_OPT_MODE - 单元格操作模式
  • VS_ENUM_TIME_TYPE - 日期时间类型
  • VS_ENUM_MESSAGE_LEVEL - 消息级别
  • VS_ENUM_IDENTITY_OBJECT_TYPE - 身份对象类型
  • VS_ENUM_BARCODE_TYPE - 条形码类型
  • VS_ENUM_FORMULA_STYLE - 公式样式
  • 更多枚举请参考 enums.ts 文件

运行演示

  1. 将 VsoftEmrDoc 或 VsoftEmrDoc 作为应用入口组件
  2. 确保 ThinkEditor SDK 文件在正确的路径下
  3. 启动开发服务器

注意事项

  1. 组件依赖 ThinkEditor SDK,请确保 SDK 文件正确放置
  2. 字体文件需要提前准备好
  3. 部分功能需要在特定环境下才能正常工作(如打印、文件选择等)

License

MIT