208 | )
209 | }
210 |
211 | export default Component
212 |
--------------------------------------------------------------------------------
/src/lib/monaco.ts:
--------------------------------------------------------------------------------
1 | import * as monaco from '@codingame/monaco-vscode-editor-api'
2 | import { examples, WS_BACKEND_URL } from '@/const'
3 | import { saveAsFile } from '@/lib/file'
4 | import { generateDataShareUrl, generateHashShareUrl, loadLegacyShareCode } from '@/service/share'
5 | import AsyncLock from 'async-lock'
6 | import { toast } from 'sonner'
7 | import { CloseAction, ErrorAction } from 'vscode-languageclient/browser'
8 | import type { LanguageClientConfig } from 'monaco-languageclient/lcwrapper'
9 | import type { MonacoVscodeApiConfig } from 'monaco-languageclient/vscodeApiWrapper'
10 | import type { EditorAppConfig } from 'monaco-languageclient/editorApp'
11 | import { configureDefaultWorkerFactory } from 'monaco-languageclient/workerFactory'
12 | import { eventEmitter, EVENTS } from '@/lib/events'
13 | import { t } from '@lingui/core/macro'
14 |
15 | import { fontFamily } from '@/app/font'
16 |
17 | import langConf from '@/lib/language-configuration.json'
18 | import textMate from '@/grammars/Cangjie.tmLanguage.json'
19 | import isMobile from 'is-mobile'
20 |
21 | const remoteLock = new AsyncLock()
22 |
23 | function isBusy() {
24 | return remoteLock.isBusy('run')
25 | }
26 |
27 | interface OnMountFunctionDependencies {
28 | setToolOutput: (output: string) => void
29 | setProgramOutput: (output: string) => void
30 | ed: monaco.editor.IStandaloneCodeEditor
31 | }
32 |
33 | function loadLegacyShareCodeToEditor(ed: monaco.editor.IStandaloneCodeEditor, setToolOutput: (output: string) => void) {
34 | if (window.location.hash.includes('hash')) {
35 | ed.setValue(t`分享代码加载中...`)
36 |
37 | toast.promise(new Promise((resolve, reject) => {
38 | remoteLock.acquire('run', async () => {
39 | const [code, success] = await loadLegacyShareCode()
40 | if (success && code) {
41 | setToolOutput(t`分享代码加载成功`)
42 | setEditorValue(ed, code)
43 | resolve()
44 | }
45 | else {
46 | setToolOutput(t`分享代码加载失败`)
47 | reject()
48 | }
49 | })
50 | }), {
51 | loading: t`分享代码加载中...`,
52 | success: t`分享代码加载成功`,
53 | error: t`分享代码加载失败`,
54 | })
55 | }
56 | }
57 |
58 | export function setEditorValue(ed: monaco.editor.ICodeEditor, code: string) {
59 | const model = ed.getModel()
60 | if (model) {
61 | model.setValue(code)
62 | }
63 | }
64 |
65 | export function updateEditor(deps: OnMountFunctionDependencies) {
66 | const {
67 | setToolOutput,
68 | ed,
69 | } = deps
70 |
71 | monaco.languages.registerDocumentFormattingEditProvider('Cangjie', {
72 | async provideDocumentFormattingEdits(model) {
73 | if (isBusy()) {
74 | return
75 | }
76 |
77 | return new Promise((resolve) => {
78 | const handleFormatted = (formattedCode: string) => {
79 | eventEmitter.off(EVENTS.FORMAT_CODE_COMPLETE, handleFormatted)
80 | if (formattedCode === model.getValue()) {
81 | resolve([])
82 | }
83 | else {
84 | resolve([{
85 | range: model.getFullModelRange(),
86 | text: formattedCode,
87 | }])
88 | }
89 | }
90 |
91 | eventEmitter.on(EVENTS.FORMAT_CODE_COMPLETE, handleFormatted)
92 | eventEmitter.emit(EVENTS.FORMAT_CODE, model.getValue())
93 |
94 | window.umami?.track('format')
95 | })
96 | },
97 | })
98 |
99 | ed.addAction({
100 | id: 'cangjie.compile.run',
101 | label: t`编译运行`,
102 | contextMenuGroupId: 'cangjie',
103 | contextMenuOrder: 1.5,
104 | keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyB],
105 | run: async (editor: monaco.editor.ICodeEditor) => {
106 | if (isBusy()) {
107 | return
108 | }
109 |
110 | eventEmitter.emit(EVENTS.RUN_CODE, editor.getValue())
111 | window.umami?.track('run')
112 | },
113 | })
114 |
115 | ed.addAction({
116 | id: 'cangjie.share.url',
117 | label: t`分享 (URL 方式)`,
118 | contextMenuGroupId: 'cangjie',
119 | contextMenuOrder: 1.5,
120 | run: async (editor: monaco.editor.ICodeEditor) => {
121 | const code = editor.getValue()
122 | const url = generateDataShareUrl(code)
123 | eventEmitter.emit(EVENTS.SHOW_SHARE_DIALOG, url)
124 | window.umami?.track('share.url')
125 | },
126 | })
127 |
128 | ed.addAction({
129 | id: 'cangjie.share.hash',
130 | label: t`分享 (Hash 方式)`,
131 | contextMenuGroupId: 'cangjie',
132 | contextMenuOrder: 1.5,
133 | run: async (editor: monaco.editor.ICodeEditor) => {
134 | const code = editor.getValue()
135 |
136 | toast.promise(async () => {
137 | const url = await generateHashShareUrl(code)
138 | eventEmitter.emit(EVENTS.SHOW_SHARE_DIALOG, url)
139 | }, {
140 | loading: t`分享中...`,
141 | success: t`分享成功`,
142 | error: t`分享失败`,
143 | })
144 |
145 | window.umami?.track('share.hash')
146 | },
147 | })
148 |
149 | ed.addAction({
150 | id: 'cangjie.save',
151 | label: t`保存代码`,
152 | contextMenuGroupId: 'cangjie',
153 | contextMenuOrder: 1.5,
154 | keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],
155 | run: async (editor: monaco.editor.ICodeEditor) => {
156 | saveAsFile(editor.getValue())
157 | toast.success(t`已保存代码`)
158 |
159 | window.umami?.track('save')
160 | },
161 | })
162 |
163 | loadLegacyShareCodeToEditor(ed, setToolOutput)
164 | }
165 |
166 | function buildLanguageConfig(): LanguageClientConfig {
167 | return {
168 | languageId: 'Cangjie',
169 | connection: {
170 | options: {
171 | $type: 'WebSocketUrl',
172 | url: WS_BACKEND_URL,
173 | },
174 | },
175 | clientOptions: {
176 | documentSelector: ['Cangjie'],
177 | initializationOptions: {
178 | multiModuleOption: {
179 | 'file:///playground': {
180 | name: 'playground',
181 | requires: {},
182 | package_requires: {
183 | path_option: [
184 | 'file:///linux_x86_64_llvm/dynamic/stdx',
185 | ],
186 | },
187 | },
188 | },
189 | modulesHomeOption: '/cangjie',
190 | telemetryOption: true,
191 | conditionCompileOption: {},
192 | conditionCompilePaths: [],
193 | targetLib: '/playground/target/debug',
194 | singleConditionCompileOption: {},
195 | },
196 | workspaceFolder: {
197 | name: 'playground',
198 | index: 0,
199 | uri: (() => {
200 | const uri = monaco.Uri.parse('file:///playground')
201 | // @ts-expect-error not exposed in type
202 | uri._fsPath = '/playground'
203 | return uri
204 | })(),
205 | },
206 | errorHandler: {
207 | error: () => ({
208 | action: ErrorAction.Continue,
209 | }),
210 | closed: () => ({
211 | action: CloseAction.Restart,
212 | }),
213 | },
214 | },
215 | }
216 | }
217 |
218 | export function createMonacoVscodeApiConfig(): MonacoVscodeApiConfig {
219 | return {
220 | $type: 'extended',
221 | userConfiguration: {
222 | json: JSON.stringify({
223 | 'editor.wordBasedSuggestions': 'off',
224 | 'editor.experimental.asyncTokenization': true,
225 | 'window.autoDetectColorScheme': true,
226 | 'workbench.preferredDarkColorTheme': 'Default Dark Modern',
227 | 'workbench.preferredLightColorTheme': 'Default Light Modern',
228 |
229 | 'editor.minimap.enabled': false,
230 | 'editor.lightbulb.enabled': 'on',
231 | 'editor.scrollBeyondLastLine': true,
232 | 'editor.fontSize': 15,
233 | 'editor.fontFamily': fontFamily,
234 | 'editor.fontLigatures': false,
235 | 'editor.mouseWheelZoom': true,
236 | 'editor.semanticHighlighting.enabled': false,
237 | 'editor.cursorSmoothCaretAnimation': 'on',
238 | }),
239 | },
240 | viewsConfig: {
241 | $type: 'EditorService',
242 | htmlContainer: 'ReactPlaceholder',
243 | },
244 | monacoWorkerFactory: configureDefaultWorkerFactory,
245 | extensions: [
246 | {
247 | config: {
248 | name: 'Cangjie Extension',
249 | publisher: 'Zxilly',
250 | version: '1.0.0',
251 | engines: {
252 | vscode: '*',
253 | },
254 | contributes: {
255 | languages: [{
256 | id: 'Cangjie',
257 | extensions: ['.cj'],
258 | aliases: ['cangjie'],
259 | configuration: './language-configuration.json',
260 | }],
261 | grammars: [{
262 | language: 'Cangjie',
263 | scopeName: 'source.cj',
264 | path: './cangjie-grammar.json',
265 | }],
266 | },
267 | },
268 | filesOrContents: new Map([
269 | ['./language-configuration.json', JSON.stringify(langConf)],
270 | ['./cangjie-grammar.json', JSON.stringify(textMate)],
271 | ]),
272 | },
273 | ],
274 | }
275 | }
276 |
277 | export function createLanguageClientConfig(): LanguageClientConfig | undefined {
278 | if (isMobile({ tablet: true, featureDetect: true })) {
279 | return undefined
280 | }
281 | return buildLanguageConfig()
282 | }
283 |
284 | export function createEditorAppConfig(shareCode?: string, locale?: string): EditorAppConfig {
285 | const helloWorldExample = examples.find(([key]) => key === 'hello-world')
286 | const defaultCode = shareCode ?? (locale === 'en' ? helloWorldExample?.[1].en.content : helloWorldExample?.[1].zh.content) ?? ''
287 |
288 | return {
289 | overrideAutomaticLayout: true,
290 | editorOptions: {
291 | language: 'Cangjie',
292 | },
293 | codeResources: {
294 | modified: {
295 | text: defaultCode,
296 | uri: 'file:///playground/src/main.cj',
297 | },
298 | },
299 | }
300 | }
301 |
--------------------------------------------------------------------------------
/src/examples/cube.cj:
--------------------------------------------------------------------------------
1 | package playground
2 |
3 | /**
4 | * 示例场景:用仓颉语言表达魔方置换群,并进行模拟验证
5 | * 本例体现了仓颉在代数/符号演算方面的表达能力,以及语言的易用性和灵活性等
6 | * 涉及特性:enum/构造器/递归定义/模式匹配,操作符重载,接口,类型别名,递归调用,
7 | * class,tuple,Array,HashMap,for-in/Range,if-let,lambda
8 | */
9 | import std.collection.*
10 |
11 | enum Rotation <: ToString & Hashable & Equatable {
12 | // 在魔方研究中,通常用 Front/Back/Left/Right/Up/Down 表示六个面以及对应的原子操作,即正对此面顺时针旋转 90 度
13 | F
14 | | B
15 | | L
16 | | R
17 | | U
18 | | D
19 | | X(Rotation, Rotation) // 仓颉支持 enum 构造器和递归定义,此处 X 用于组织复合旋转操作
20 | | I(Rotation) // I(r) 用于表示 r 的逆变换,即正对 r 面逆时针旋转 90 度
21 |
22 | // enum 中也可以定义成员函数,这里我们重载 * 运算符以实现旋转操作的组合,由此可生成一个置换群
23 | public operator func *(that: Rotation): Rotation {
24 | match (this) {
25 | case X(x1, x2) => X(x1, X(x2, that)) // 按此顺序分解重组,使得递归时按从左到右的顺序执行变换
26 | case _ => X(this, that)
27 | }
28 | }
29 |
30 | // 重载 ** 运算符实现幂运算,以便表示和验证高阶置换操作,如 (F*F*L*L*B*R)**90 会让魔方回归初态
31 | public operator func **(exp: UInt32): Rotation {
32 | var result = this
33 | for (_ in 0..(exp - 1)) {
34 | result = result * this
35 | }
36 | return result
37 | }
38 |
39 | // 实现 ToString 接口以便打印和调试此代数系统
40 | private func text(inv: Bool): String {
41 | let exp = if (inv) {
42 | "⁻¹"
43 | } else {
44 | ""
45 | }
46 | match (this) {
47 | case F => "F${exp}"
48 | case B => "B${exp}"
49 | case L => "L${exp}"
50 | case R => "R${exp}"
51 | case U => "U${exp}"
52 | case D => "D${exp}"
53 | case I(r) => r.text(!inv)
54 | case X(x1, x2) =>
55 | if (inv) { // 逆变换需要反序
56 | x2.text(inv) + x1.text(inv)
57 | } else {
58 | x1.text(inv) + x2.text(inv)
59 | }
60 | }
61 | }
62 |
63 | public func toString(): String {
64 | text(false)
65 | }
66 |
67 | // 下面实现 Hashable 和 Equatable 接口,以便 Rotation 作为 HashMap 的 Key
68 | public func hashCode(): Int64 {
69 | this.toString().hashCode()
70 | }
71 |
72 | public operator func ==(that: Rotation): Bool {
73 | this.toString() == that.toString()
74 | }
75 |
76 | public operator func !=(that: Rotation): Bool {
77 | this.toString() != that.toString()
78 | }
79 | }
80 |
81 | type Face = Rotation
82 |
83 | type Vector = Array<(Face, Int64)>
84 |
85 | type Matrix = Array
86 |
87 | enum Index {
88 | Row(Int64) | Col(Int64) | Inv(Index)
89 | // 用于标记向量倒置
90 | public operator func -(): Index {
91 | match (this) {
92 | case Inv(v) => v
93 | case _ => Inv(this)
94 | }
95 | }
96 | // 去掉 Inv 符号
97 | public func value(): Index {
98 | match (this) {
99 | case Inv(v) => v
100 | case _ => this
101 | }
102 | }
103 | }
104 |
105 | extend Matrix {
106 | // 给指定的魔方面创建初始矩阵
107 | public static func create(face: Face) {
108 | Matrix(
109 | 3,
110 | {
111 | i => Vector(3, {j => (face, 3 * i + j + 1)})
112 | }
113 | )
114 | }
115 |
116 | // 获取矩阵的行或列
117 | public operator func [](index: Index): Vector {
118 | match (index) {
119 | case Row(r) => this[r].clone()
120 | case Col(c) => Vector(this.size, {i => this[i][c]})
121 | case Inv(i) => this[i] // 应用场景需要,取值时忽略符号、不做倒置
122 | }
123 | }
124 |
125 | // 给矩阵的行或列赋值
126 | public func set(index: Index, value: Vector): Unit {
127 | match (index) {
128 | case Row(r) => this[r] = value
129 | case Col(c) => for (i in 0..value.size) {
130 | this[i][c] = value[i]
131 | }
132 | case Inv(i) => // 赋值时根据 index 符号做倒置
133 | value.reverse()
134 | this.set(i, value)
135 | }
136 | }
137 |
138 | // 打印矩阵的一行
139 | public func print(row: Int64) {
140 | for ((face, id) in this[row]) {
141 | print("${face}${id} ")
142 | }
143 | }
144 |
145 | // 打印整个矩阵
146 | public func print() {
147 | for (row in 0..this.size) {
148 | print(" ")
149 | print(row)
150 | println()
151 | }
152 | }
153 | }
154 |
155 | // 直接用以上 enum 表示行列索引还不够优雅,我们为整型扩展两个属性,让索引数值可以直接标记行列
156 | extend Int64 {
157 | public prop r: Index {
158 | get() {
159 | Index.Row(this)
160 | }
161 | }
162 | public prop c: Index {
163 | get() {
164 | Index.Col(this)
165 | }
166 | }
167 | }
168 |
169 | // Permutation 可以表示一个置换序列
170 | // 如 [(L, 2.c), (U, -0.r)] 表示 L 面第三列和 U 面第一行之间的轮换,且前者在换到后者时需要倒置
171 | type Permutation = Array<(Face, Index)>
172 |
173 | extend Permutation {
174 | // 获取当前置换的逆变换
175 | public func inverse() {
176 | let perm = this.clone()
177 | for (i in 0..perm.size) {
178 | let j = (i + 1) % perm.size
179 | let (face, index) = this[i] // 解构元组
180 | if (let Inv(_) <- this[j][1]) { // if-let 模式匹配
181 | perm[i] = (face, -(index.value()))
182 | } else {
183 | perm[i] = (face, index.value())
184 | }
185 | }
186 | perm.reverse()
187 | return perm
188 | }
189 | }
190 |
191 | class Cube {
192 | public let data = HashMap()
193 | private var history = ArrayList()
194 | private static let permutation = HashMap()
195 |
196 | public init() {
197 | reset()
198 | }
199 |
200 | static init() {
201 | // 每个面顺时针转动 90 度时,相邻四面的置换关系
202 | permutation[F] = [(L, 2.c), (U, -2.r), (R, 0.c), (D, -0.r)]
203 | permutation[B] = [(L, -0.c), (D, 2.r), (R, -2.c), (U, 0.r)]
204 | permutation[L] = [(U, 0.c), (F, 0.c), (D, 0.c), (B, 0.c)]
205 | permutation[R] = [(B, 2.c), (D, 2.c), (F, 2.c), (U, 2.c)]
206 | permutation[U] = [(L, 0.r), (B, -2.r), (R, -0.r), (F, 0.r)]
207 | permutation[D] = [(R, 2.r), (B, -0.r), (L, -2.r), (F, 2.r)]
208 | }
209 |
210 | public func reset() {
211 | history = ArrayList()
212 | for (face in [F, B, L, R, U, D]) {
213 | data[face] = Matrix.create(face)
214 | }
215 | }
216 |
217 | // 对指定面上的矩阵旋转 90 度,inverse = true 代表逆时针方向
218 | // 此操作不影响其他面,要配合邻边置换操作才能完成魔方的实际转动
219 | private func rotate(face: Face, inverse: Bool) {
220 | const N = 3
221 | let matrix = Matrix.create(face)
222 | let map = if (inverse) {
223 | {i: Int64, j: Int64 => (N - 1 - j, i)}
224 | } else {
225 | {i: Int64, j: Int64 => (j, N - 1 - i)}
226 | }
227 | for (i in 0..N) {
228 | for (j in 0..N) {
229 | let (u, v) = map(i, j)
230 | matrix[u][v] = data[face][i][j]
231 | }
232 | }
233 | data[face] = matrix
234 | }
235 |
236 | // 实现各面行/列之间的置换操作,输入是一个置换序列
237 | private func permute(perm: Permutation, inverse: Bool) {
238 | let p = if (inverse) {
239 | perm.inverse()
240 | } else {
241 | perm.clone()
242 | }
243 | p.reverse()
244 | var (lastFace, lastIndex) = p[0]
245 | let vector = data[lastFace][lastIndex]
246 | for (i in 1..p.size) {
247 | let (face, index) = p[i]
248 | data[lastFace].set(lastIndex, data[face][index])
249 | (lastFace, lastIndex) = (face, index)
250 | }
251 | data[lastFace].set(lastIndex, vector)
252 | }
253 |
254 | // 在魔方上按序执行 rotation 中定义的操作序列
255 | private func transform(rotation: Rotation, inverse: Bool): Unit {
256 | match (rotation) {
257 | case I(r) => transform(r, !inverse)
258 | case X(r1, r2) => // 对复合操作进行递归分解
259 | if (inverse) { // 逆变换需要反序
260 | transform(r2, inverse)
261 | transform(r1, inverse)
262 | } else {
263 | transform(r1, inverse)
264 | transform(r2, inverse)
265 | }
266 | case _ => // 各原子操作对应面先旋转 90 度,然后对相邻四个面执行置换操作
267 | rotate(rotation, inverse)
268 | permute(permutation[rotation], inverse)
269 | }
270 | }
271 |
272 | public func transform(rotation: Rotation) {
273 | transform(rotation, false)
274 | history.add(rotation)
275 | print()
276 | }
277 |
278 | public func print() {
279 | var prompt = ">> "
280 | for (rotation in history) {
281 | prompt += rotation.toString()
282 | }
283 | println(prompt)
284 | data[U].print()
285 | for (i in 0..3) {
286 | for (face in [L, F, R]) {
287 | data[face].print(i)
288 | }
289 | println()
290 | }
291 | data[D].print()
292 | data[B].print()
293 | println()
294 | }
295 | }
296 |
297 | main() {
298 | let cube = Cube()
299 | cube.print()
300 | // 1.基本操作
301 | for (r in [F, B, L, R, U, D]) {
302 | cube.transform(r) // 原子操作
303 | }
304 | Cube().transform(F * R * I(F * R)) // 复合操作
305 |
306 | // 2.置换的阶数
307 | // FFRR 是 2,3 阶置换的组合,其最小公倍数是 6,重复 6 次两类置换都会还原
308 | Cube().transform((F * F * R * R) ** 6)
309 | // FULLR 是 3,4,6,9,18 阶置换的组合,同理可得其阶数为 36
310 | Cube().transform((F * U * L * L * R) ** 36)
311 | Cube().transform((F * F * L * L * B * R) ** 90)
312 |
313 | // 3.相似变换 UGU⁻¹
314 | // 已知 R⁻¹DRFDF⁻¹ 可以翻转 FUR 角块
315 | let G = I(R) * D * R * F * D * I(F)
316 | Cube().transform(G)
317 | // 为了翻转 BUR 角块,可以先执行 U 把 BUR 换到 FUR 位置,然后执行 G 翻转 FUR,最后执行 U⁻¹ 恢复 BUR 位置
318 | let H = U * G * I(U)
319 | Cube().transform(H)
320 |
321 | // 4.组合子变换 MU⁻¹M⁻¹U
322 | // 已知 RL⁻¹FFLR⁻¹D⁻¹RL⁻¹FLR⁻¹ 可以保持顶面其他方块不变、仅翻转 UF 棱块,但下面两层会被打乱
323 | let M = R * I(L) * F * F * L * I(R) * I(D) * R * I(L) * F * L * I(R)
324 | Cube().transform(M)
325 | // 为了同时翻转 UF 和 UL,可以先执行 M 翻转 UF,然后执行 U⁻¹ 把 UL 换到 UF 位置
326 | // 再执行 M⁻¹ 翻转 UL 并还原下面两层,最后执行 U 恢复 UF 和 UL 位置,这样整个魔方仅有 UF 和 UL 被翻转
327 | let N = M * I(U) * I(M) * U
328 | Cube().transform(N)
329 | // 在此基础上,如果我们想同时翻转 UL 和 UR,可以按组合子思想执行 NUN⁻¹U⁻¹
330 | let P = N * U * I(N) * I(U)
331 | Cube().transform(P)
332 | }
333 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------