Merge remote-tracking branch 'origin/master'
# Conflicts: # package-lock.json
This commit is contained in:
commit
7167b83c9e
|
@ -0,0 +1 @@
|
|||
static/js/lib/* linguist-vendored
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
name: 报告缺陷
|
||||
about: 报告缺陷以帮助我们改进
|
||||
---
|
||||
|
||||
**请先看[《提问的智慧》](https://hacpai.com/article/1536377163156)**,并尝试到[讨论区](https://hacpai.com/tag/wide)搜寻资料解决问题。
|
||||
|
||||
----
|
||||
|
||||
### 描述问题
|
||||
|
||||
请尽量清晰精准地描述你碰到的问题。
|
||||
|
||||
### 重现步骤
|
||||
|
||||
请描述如何重现这个问题:
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '...'
|
||||
3. Scroll down to '...'
|
||||
4. See error
|
||||
|
||||
### 期待的结果
|
||||
|
||||
请尽量清晰精准地描述你所期待的结果。
|
||||
|
||||
### 截屏或录像
|
||||
|
||||
如果可能,请尽量附加截图或录像来描述你遇到的问题。
|
||||
|
||||
### 桌面端环境
|
||||
|
||||
- OS: [e.g. windows, mac, linux]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
### 移动端环境
|
||||
|
||||
- Device: [e.g. iPhone8]
|
||||
- OS: [e.g. iOS12]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
### 其他信息
|
||||
|
||||
请提供其他附加信息帮助我们诊断问题。
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
name: 请求新功能
|
||||
about: 提出你期待的功能特性
|
||||
---
|
||||
|
||||
### 你在什么场景下需要该功能?
|
||||
|
||||
请尽量清晰精准地描述你碰到的问题。
|
||||
|
||||
### 描述可能的解决方案
|
||||
|
||||
请尽量清晰精准地描述你期待我们要做的,描述你想到的实现方案。
|
||||
|
||||
### 描述你认为的候选方案
|
||||
|
||||
请尽量清晰精准地描述你能接受的候选解决方案。
|
||||
|
||||
### 其他信息
|
||||
|
||||
请提供关于该功能建议的其他附加信息。
|
|
@ -1,8 +1,6 @@
|
|||
/wide.exe
|
||||
/wide
|
||||
|
||||
/static/user/admin/style.css
|
||||
|
||||
/header
|
||||
/header.exe
|
||||
|
||||
|
|
|
@ -10,11 +10,12 @@
|
|||
],
|
||||
"Excludes": [
|
||||
"static/js/lib/*",
|
||||
"static/user/*"
|
||||
"static/user/*",
|
||||
"vendor/**"
|
||||
],
|
||||
"UseDefaultExcludes": true,
|
||||
"Properties": {
|
||||
"Year": "2014-2017",
|
||||
"Year": "2014-2019",
|
||||
"Owner": "b3log.org & hacpai.com"
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
|
|||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.4
|
||||
- 1.12
|
||||
before_install:
|
||||
- go get github.com/axw/gocov/gocov
|
||||
- go get github.com/mattn/goveralls
|
||||
|
|
32
Dockerfile
32
Dockerfile
|
@ -1,32 +0,0 @@
|
|||
FROM golang:1.7.4
|
||||
MAINTAINER Liang Ding <dl88250@gmail.com>
|
||||
|
||||
RUN apt-get update && apt-get install bzip2 zip unzip
|
||||
|
||||
ENV GOROOT /usr/local/go
|
||||
RUN cp -r /usr/local/go /usr/local/gobt
|
||||
ENV GOROOT_BOOTSTRAP=/usr/local/gobt
|
||||
|
||||
RUN cd /usr/local/go/src && export GOOS=darwin && export GOARCH=amd64 && ./make.bash --no-clean
|
||||
RUN cd /usr/local/go/src && export GOOS=linux && export GOARCH=arm && ./make.bash --no-clean
|
||||
RUN cd /usr/local/go/src && export GOOS=windows && export GOARCH=amd64 && ./make.bash --no-clean
|
||||
|
||||
ADD . /wide/gogogo/src/github.com/b3log/wide
|
||||
|
||||
RUN unzip /wide/gogogo/src/github.com/b3log/wide/deps/golang.org.zip -d /wide/gogogo/src/
|
||||
RUN unzip /wide/gogogo/src/github.com/b3log/wide/deps/github.com.zip -d /wide/gogogo/src/
|
||||
|
||||
RUN useradd wide && useradd runner
|
||||
|
||||
ENV GOPATH /wide/gogogo
|
||||
|
||||
RUN go build github.com/go-fsnotify/fsnotify
|
||||
RUN go build github.com/gorilla/sessions
|
||||
RUN go build github.com/gorilla/websocket
|
||||
|
||||
RUN go install github.com/visualfc/gotools github.com/nsf/gocode github.com/bradfitz/goimports
|
||||
|
||||
WORKDIR /wide/gogogo/src/github.com/b3log/wide
|
||||
RUN go build -v
|
||||
|
||||
EXPOSE 7070
|
2
LICENSE
2
LICENSE
|
@ -192,7 +192,7 @@
|
|||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
236
README.md
236
README.md
|
@ -1,173 +1,129 @@
|
|||
# [Wide](https://github.com/b3log/wide) [![Build Status](https://img.shields.io/travis/b3log/wide.svg?style=flat)](https://travis-ci.org/b3log/wide) [![Coverage Status](https://img.shields.io/coveralls/b3log/wide.svg?style=flat)](https://coveralls.io/r/b3log/wide) [![Apache License](http://img.shields.io/badge/license-apache2-orange.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0) [![API Documentation](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](http://godoc.org/github.com/b3log/wide) [![Download](http://img.shields.io/badge/download-~4.3K-red.svg?style=flat)](http://pan.baidu.com/s/1dD3XwOT)
|
||||
# [Wide](https://github.com/b3log/wide) [![Build Status](https://img.shields.io/travis/b3log/wide.svg?style=flat)](https://travis-ci.org/b3log/wide) [![Go Report Card](https://goreportcard.com/badge/github.com/b3log/wide)](https://goreportcard.com/report/github.com/b3log/wide) [![Coverage Status](https://img.shields.io/coveralls/b3log/wide.svg?style=flat)](https://coveralls.io/r/b3log/wide) [![Apache License](https://img.shields.io/badge/license-apache2-orange.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) [![API Documentation](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/b3log/wide) [![Download](https://img.shields.io/badge/download-~4.3K-red.svg?style=flat)](https://pan.baidu.com/s/1dD3XwOT)
|
||||
|
||||
_Have a [try](http://wide.b3log.org/signup) first, then [download](http://pan.baidu.com/s/1dD3XwOT) and setup it on your local area network, enjoy yourself!_
|
||||
先试试我们搭建好的[在线服务](https://wide.b3log.org/signup),你可以在这里[下载](https://pan.baidu.com/s/1dD3XwOT)并在本地环境运行,然后邀请小伙伴们来玩吧!
|
||||
|
||||
先试试我们搭建好的[在线服务](http://wide.b3log.org/signup),你可以在这里[下载](http://pan.baidu.com/s/1dD3XwOT)并在本地环境运行,然后邀请小伙伴们来玩吧!
|
||||
## 简介
|
||||
|
||||
> * 关于 Wide 的产品定位,请看[这里](http://hacpai.com/article/1438407961481),并欢迎参与讨论~
|
||||
> * 加入[**黑客派**](http://hacpai.com/register),与其他程序员、设计师共同成长!
|
||||
Wide 是一个基于 **W**eb 的 Go 语言 **IDE**。
|
||||
|
||||
## Introduction
|
||||
![](https://cloud.githubusercontent.com/assets/873584/4606377/d0ca3c2a-521b-11e4-912c-d955ab05850b.png)
|
||||
|
||||
A <b>W</b>eb-based <b>IDE</b> for Teams using Go programming language/Golang.
|
||||
## 动机
|
||||
|
||||
![Hello, 世界](https://cloud.githubusercontent.com/assets/873584/4606377/d0ca3c2a-521b-11e4-912c-d955ab05850b.png)
|
||||
目前较为流行的 Go IDE 都有一些缺陷或遗憾:
|
||||
* 文本编辑器类(vim/emacs/sublime/Atom 等):对于新手门槛太高,搭建复杂
|
||||
* 插件类(goclipse、IDEA 等):需要原 IDE 支持,不够专业
|
||||
* LiteIDE 界面不够 modern、goland 收费
|
||||
* **缺少网络分享、嵌入网站可运行功能**
|
||||
|
||||
## Authors
|
||||
另外,Go IDE 很少,用 Go 本身开发的 IDE 更是没有,这是一个很好的尝试。关于产品定位的讨论请看[这里](https://hacpai.com/article/1438407961481)。
|
||||
|
||||
[Daniel](https://github.com/88250) and [Vanessa](https://github.com/Vanessa219) are the main authors of Wide, [here](https://github.com/b3log/wide/graphs/contributors) are all contributors.
|
||||
## 特性
|
||||
|
||||
Wide 的主要作者是 [Daniel](https://github.com/88250) 与 [Vanessa](https://github.com/Vanessa219),所有贡献者可以在[这里](https://github.com/b3log/wide/graphs/contributors)看到。
|
||||
基于 Web 的 IDE:
|
||||
|
||||
## Motivation
|
||||
|
||||
* **Team** IDE:
|
||||
* _Safe and reliable_: the project source code stored on the server in real time, the developer's machine crashes without losing any source code
|
||||
* _Unified environment_: server unified development environment configuration, the developer machine without any additional configuration
|
||||
* _Out of the box_: 5 minutes to setup a server then open browser to develop, debug
|
||||
* _Version Control_: each developer has its own source code repository, easy sync with the trunk
|
||||
* **Web-based** IDE:
|
||||
* Developer needs a browser only
|
||||
* Cross-platform, even on mobile devices
|
||||
* Easy to extend
|
||||
* Easy to integrate with other systems
|
||||
* For the geeks
|
||||
* A try for commercial-open source: versions customized for enterprises, close to their development work flows respectively
|
||||
* Currently more popular Go IDE has some defects or regrets:
|
||||
* Text editor (vim/emacs/sublime/Atom, etc.): For the Go newbie is too complex
|
||||
* Plug-in (goclipse, etc.): the need for the original IDE support, not professional
|
||||
* LiteIDE: no modern user interface :p
|
||||
* No team development experience
|
||||
* There are a few of GO IDEs, and no one developed by Go itself, this is a nice try
|
||||
|
||||
## Features
|
||||
|
||||
* [X] Code Highlight, Folding: Go/HTML/JavaScript/Markdown etc.
|
||||
* [X] Autocomplete: Go/HTML etc.
|
||||
* [X] Format: Go/HTML/JSON etc.
|
||||
* [X] Build & Run
|
||||
* [X] Multiplayer: a real team development experience
|
||||
* [X] Navigation, Jump to declaration, Find usages, File search etc.
|
||||
* [X] Shell: run command on the server
|
||||
* [X] Web development: HTML/JS/CSS editor with [Emmet](http://emmet.io) integrated
|
||||
* [X] Go tool: go get/install/fmt etc.
|
||||
* [X] File Import & Export
|
||||
* [X] Themes: editor and UI adjust, respectively
|
||||
* [X] Cross-Compilation
|
||||
* [ ] Debug
|
||||
* [ ] Git integration: git command on the web
|
||||
|
||||
## Screenshots
|
||||
|
||||
* **Overview**
|
||||
* 只需要浏览器就能进行开发、运行
|
||||
* 跨平台,甚至在移动设备上
|
||||
* 易进行功能扩展
|
||||
* 易与其他系统集成
|
||||
* 极客体验
|
||||
|
||||
![Overview](https://cloud.githubusercontent.com/assets/873584/5450620/1d51831e-8543-11e4-930b-670871902425.png)
|
||||
* **Goto File**
|
||||
|
||||
![Goto File](https://cloud.githubusercontent.com/assets/873584/5450616/1d495da6-8543-11e4-9285-f9d9c60779ac.png)
|
||||
* **Autocomplete**
|
||||
|
||||
![Autocomplete](https://cloud.githubusercontent.com/assets/873584/5450619/1d4d5712-8543-11e4-8fe4-35dbc8348a6e.png)
|
||||
* **Theme**
|
||||
|
||||
![4](https://cloud.githubusercontent.com/assets/873584/5450617/1d4c0826-8543-11e4-8b86-f79a4e41550a.png)
|
||||
* **Show Expression Info**
|
||||
|
||||
![Show Expression Info](https://cloud.githubusercontent.com/assets/873584/5450618/1d4cd9f4-8543-11e4-950f-121bd3ff4a39.png)
|
||||
* **Build Error Info**
|
||||
|
||||
![Build Error Info](https://cloud.githubusercontent.com/assets/873584/5450632/3e51cccc-8543-11e4-8ca8-8d2427aa16b8.png)
|
||||
* **Git Clone**
|
||||
核心功能:
|
||||
|
||||
![Git Clone](https://cloud.githubusercontent.com/assets/873584/6545235/2284f230-c5b7-11e4-985e-7e04367921b1.png)
|
||||
* **Cross-Compilation**
|
||||
|
||||
![Cross-Compilation](https://cloud.githubusercontent.com/assets/873584/10130037/226d75fc-65f7-11e5-94e4-25ee579ca175.png)
|
||||
* 代码高亮、折叠:Go/HTML/JavaScript/Markdown 等
|
||||
* 自动完成:Go/HTML 等
|
||||
* 编译检查:编辑器提示编译错误
|
||||
* 格式化:Go/HTML/JSON 等
|
||||
* 运行:支持同时运行多个程序
|
||||
* 代码导航:跳转到声明,查找使用,文件搜索等
|
||||
* Web 开发:前端(HTML/JS/CSS)开发支持
|
||||
* go tool:go get/install/fmt 等
|
||||
* 项目文件导出
|
||||
* UI/编辑器多主题
|
||||
* 支持交叉编译
|
||||
|
||||
* **Playground**
|
||||
![Playground](https://cloud.githubusercontent.com/assets/873584/21209772/449ecfd2-c2b1-11e6-9aa6-a83477d9f269.gif)
|
||||
|
||||
## Architecture
|
||||
## 界面
|
||||
|
||||
### Build & Run
|
||||
### 主界面
|
||||
|
||||
![Overview](https://cloud.githubusercontent.com/assets/873584/5450620/1d51831e-8543-11e4-930b-670871902425.png)
|
||||
|
||||
### 跳转到文件
|
||||
|
||||
![Goto File](https://cloud.githubusercontent.com/assets/873584/5450616/1d495da6-8543-11e4-9285-f9d9c60779ac.png)
|
||||
|
||||
### 自动完成
|
||||
|
||||
![Autocomplete](https://cloud.githubusercontent.com/assets/873584/5450619/1d4d5712-8543-11e4-8fe4-35dbc8348a6e.png)
|
||||
|
||||
### 主题
|
||||
|
||||
![Theme](https://cloud.githubusercontent.com/assets/873584/5450617/1d4c0826-8543-11e4-8b86-f79a4e41550a.png)
|
||||
|
||||
### 查看表达式
|
||||
|
||||
![Show Expression Info](https://cloud.githubusercontent.com/assets/873584/5450618/1d4cd9f4-8543-11e4-950f-121bd3ff4a39.png)
|
||||
|
||||
### 构建报错提示
|
||||
|
||||
![Build Error Info](https://cloud.githubusercontent.com/assets/873584/5450632/3e51cccc-8543-11e4-8ca8-8d2427aa16b8.png)
|
||||
|
||||
### 交叉编译
|
||||
|
||||
![Cross-Compilation](https://cloud.githubusercontent.com/assets/873584/10130037/226d75fc-65f7-11e5-94e4-25ee579ca175.png)
|
||||
|
||||
### Playground
|
||||
|
||||
![Playground](https://cloud.githubusercontent.com/assets/873584/21209772/449ecfd2-c2b1-11e6-9aa6-a83477d9f269.gif)
|
||||
|
||||
## 架构
|
||||
|
||||
### 构建与运行
|
||||
|
||||
![Build & Run](https://cloud.githubusercontent.com/assets/873584/4389219/3642bc62-43f3-11e4-8d1f-06d7aaf22784.png)
|
||||
|
||||
* A browser tab corresponds to a Wide session
|
||||
* Execution output push via WebSocket
|
||||
* 一个浏览器 tab 对应一个 Wide 会话
|
||||
* 通过 WebSocket 进行程序执行输出推送
|
||||
|
||||
Flow:
|
||||
1. Browser sends ````Build```` request
|
||||
2. Server executes ````go build```` command via ````os/exec````<br/>
|
||||
2.1. Generates a executable file
|
||||
3. Browser sends ````Run```` request
|
||||
4. Server executes the file via ````os/exec````<br/>
|
||||
4.1. A running process<br/>
|
||||
4.2. Execution output push via WebSocket channel
|
||||
5. Browser renders with callback function ````ws.onmessage````
|
||||
1. 客户端浏览器发送 ````Build```` 请求
|
||||
2. 服务器使用 ````os/exec```` 执行 ````go build```` 命令<br/>
|
||||
2.1. 生成可执行文件
|
||||
3. 客户端浏览器发送 ````Run```` 请求
|
||||
4. 服务器使用 ````os/exec```` 执行文件<br/>
|
||||
4.1. 生成进程<br/>
|
||||
4.2. 运行结果输出到 WebSocket 通道
|
||||
5. 客户端浏览器监听 ````ws.onmessage```` 到消息后做展现
|
||||
|
||||
### Code Assist
|
||||
### 代码辅助
|
||||
|
||||
![Code Assist](https://cloud.githubusercontent.com/assets/873584/4399135/3b80c21c-4463-11e4-8e94-7f7e8d12a4df.png)
|
||||
![](https://cloud.githubusercontent.com/assets/873584/4399135/3b80c21c-4463-11e4-8e94-7f7e8d12a4df.png)
|
||||
|
||||
* Autocompletion
|
||||
* Find Usages/Jump To Declaration/etc.
|
||||
* 自动完成
|
||||
* 查找使用
|
||||
|
||||
Flow:
|
||||
1. Browser sends code assist request
|
||||
2. Handler gets user workspace of the request with HTTP session
|
||||
3. Server executes ````gocode````/````ide_stub(gotools)````<br/>
|
||||
3.1 Sets environment variables (e.g. ${GOPATH})<br/>
|
||||
3.2 ````gocode```` with ````lib-path```` parameter
|
||||
1. 浏览器客户端发送代码辅助请求
|
||||
2. Handler 根据请求对应的 HTTP 会话获取用户工作空间
|
||||
3. 执行 `gocode`/`ide_stub(gotools)` 命令<br/>
|
||||
3.1 设置环境变量(${GOPATH} 为用户工作空间路径)<br/>
|
||||
3.2 `gocode` 命令需要设置参数 `lib-path`
|
||||
|
||||
## Documents
|
||||
## 文档
|
||||
|
||||
* [用户指南](https://www.gitbook.com/book/88250/wide-user-guide)
|
||||
* [开发指南](https://www.gitbook.com/book/88250/wide-dev-guide)
|
||||
* [用户指南](https://hacpai.com/article/1538873544275)
|
||||
* [开发指南](https://hacpai.com/article/1538876422995)
|
||||
|
||||
## Setup
|
||||
## 社区
|
||||
|
||||
### Download Binary
|
||||
* [讨论区](https://hacpai.com/tag/wide)
|
||||
* [报告问题](https://github.com/b3log/wide/issues/new/choose)
|
||||
|
||||
We have provided OS-specific executable binary as follows:
|
||||
## 授权
|
||||
|
||||
* linux-amd64/386
|
||||
* windows-amd64/386
|
||||
* darwin-amd64/386
|
||||
Wide 使用 [Apache License, Version 2](https://www.apache.org/licenses/LICENSE-2.0) 作为开源协议,请务必遵循该开源协议相关约定。
|
||||
|
||||
Download [HERE](http://pan.baidu.com/s/1dD3XwOT)!
|
||||
## 鸣谢
|
||||
|
||||
### Build Wide for yourself
|
||||
|
||||
1. [Download](https://github.com/b3log/wide/archive/master.zip) source or by `git clone https://github.com/b3log/wide`
|
||||
2. Get dependencies with
|
||||
* `go get`
|
||||
* `go get github.com/visualfc/gotools github.com/nsf/gocode github.com/bradfitz/goimports`
|
||||
3. Compile wide with `go build`
|
||||
|
||||
### Docker
|
||||
|
||||
1. Get image: `sudo docker pull 88250/wide:latest`
|
||||
2. Run: `sudo docker run -p 127.0.0.1:7070:7070 88250/wide:latest ./wide -docker=true -channel=ws://127.0.0.1:7070`
|
||||
3. Open browser: http://127.0.0.1:7070
|
||||
|
||||
## Known Issues
|
||||
|
||||
* [Shell is not available on Windows](https://github.com/b3log/wide/issues/32)
|
||||
* [Rename directory](https://github.com/b3log/wide/issues/251)
|
||||
|
||||
## Terms
|
||||
|
||||
* This software is open sourced under the Apache License 2.0
|
||||
* You can not get rid of the "Powered by [B3log](http://b3log.org)" from any page, even which you made
|
||||
* If you want to use this software for commercial purpose, please mail to support@liuyun.io for a commercial license request
|
||||
* Copyright © b3log.org, all rights reserved
|
||||
|
||||
## Credits
|
||||
|
||||
Wide is made possible by the following open source projects.
|
||||
|
||||
* [golang](http://golang.org)
|
||||
* [golang](https://golang.org)
|
||||
* [CodeMirror](https://github.com/marijnh/CodeMirror)
|
||||
* [zTree](https://github.com/zTree/zTree_v3)
|
||||
* [LiteIDE](https://github.com/visualfc/liteide)
|
||||
|
|
4
TERMS.md
4
TERMS.md
|
@ -1,4 +1,4 @@
|
|||
* This software is open sourced under the Apache License 2.0
|
||||
* You can not get rid of the "Powered by [B3log](http://b3log.org)" from any pages, even the pages are developed by you
|
||||
* If you want to use this software for commercial purpose, please mail to support@liuyun.io for request a commercial license
|
||||
* You can not get rid of the "Powered by [B3log](https://b3log.org)" from any pages, even the pages are developed by you
|
||||
* If you want to use this software for commercial purpose, please mail to os@b3log.org for request a commercial license
|
||||
* Copyright (c) b3log.org, all rights reserved
|
||||
|
|
68
conf/user.go
68
conf/user.go
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -15,9 +15,6 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
@ -25,8 +22,6 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/util"
|
||||
)
|
||||
|
||||
// Panel represents a UI panel.
|
||||
|
@ -52,11 +47,9 @@ type LatestSessionContent struct {
|
|||
|
||||
// User configuration.
|
||||
type User struct {
|
||||
Id string
|
||||
Name string
|
||||
Password string
|
||||
Salt string
|
||||
Email string
|
||||
Gravatar string // see http://gravatar.com
|
||||
Avatar string
|
||||
Workspace string // the GOPATH of this user (maybe contain several paths splitted by os.PathListSeparator)
|
||||
Locale string
|
||||
GoFormat string
|
||||
|
@ -83,28 +76,7 @@ type editor struct {
|
|||
TabSize string
|
||||
}
|
||||
|
||||
// NewUser creates a user with the specified username, password, email and workspace.
|
||||
func NewUser(username, password, email, workspace string) *User {
|
||||
md5hash := md5.New()
|
||||
md5hash.Write([]byte(email))
|
||||
gravatar := hex.EncodeToString(md5hash.Sum(nil))
|
||||
|
||||
salt := util.Rand.String(16)
|
||||
password = Salt(password, salt)
|
||||
|
||||
now := time.Now().UnixNano()
|
||||
|
||||
return &User{Name: username, Password: password, Salt: salt, Email: email, Gravatar: gravatar, Workspace: workspace,
|
||||
Locale: Wide.Locale, GoFormat: "gofmt",
|
||||
GoBuildArgsForLinux: "-i", GoBuildArgsForWindows: "-i", GoBuildArgsForDarwin: "-i",
|
||||
FontFamily: "Helvetica", FontSize: "13px", Theme: "default",
|
||||
Keymap: "wide",
|
||||
Created: now, Updated: now, Lived: now,
|
||||
Editor: &editor{FontFamily: "Consolas, 'Courier New', monospace", FontSize: "inherit", LineHeight: "17px",
|
||||
Theme: "wide", TabSize: "4"}}
|
||||
}
|
||||
|
||||
// Save saves the user's configurations in conf/users/{username}.json.
|
||||
// Save saves the user's configurations in conf/users/{userId}.json.
|
||||
func (u *User) Save() bool {
|
||||
bytes, err := json.MarshalIndent(u, "", " ")
|
||||
|
||||
|
@ -115,12 +87,12 @@ func (u *User) Save() bool {
|
|||
}
|
||||
|
||||
if "" == string(bytes) {
|
||||
logger.Error("Truncated user [" + u.Name + "]")
|
||||
logger.Error("Truncated user [" + u.Id + "]")
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile("conf/users/"+u.Name+".json", bytes, 0644); nil != err {
|
||||
if err = ioutil.WriteFile(filepath.Join(Wide.Data, "users", u.Id+".json"), bytes, 0644); nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
return false
|
||||
|
@ -129,6 +101,20 @@ func (u *User) Save() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// NewUser creates a user with the specified username and workspace.
|
||||
func NewUser(id, name, avatar, workspace string) *User {
|
||||
now := time.Now().UnixNano()
|
||||
|
||||
return &User{Id: id, Name: name, Avatar: avatar, Workspace: workspace,
|
||||
Locale: Wide.Locale, GoFormat: "gofmt",
|
||||
GoBuildArgsForLinux: "-i", GoBuildArgsForWindows: "-i", GoBuildArgsForDarwin: "-i",
|
||||
FontFamily: "Helvetica", FontSize: "13px", Theme: "default",
|
||||
Keymap: "wide",
|
||||
Created: now, Updated: now, Lived: now,
|
||||
Editor: &editor{FontFamily: "Consolas, 'Courier New', monospace", FontSize: "inherit", LineHeight: "17px",
|
||||
Theme: "wide", TabSize: "4"}}
|
||||
}
|
||||
|
||||
// WorkspacePath gets workspace path of the user.
|
||||
//
|
||||
// Compared to the use of Wide.Workspace, this function will be processed as follows:
|
||||
|
@ -136,7 +122,7 @@ func (u *User) Save() bool {
|
|||
// 2. Replace ${GOPATH} with enviorment variable GOPATH
|
||||
// 3. Replace "/" with "\\" (Windows)
|
||||
func (u *User) WorkspacePath() string {
|
||||
w := strings.Replace(u.Workspace, "{WD}", Wide.WD, 1)
|
||||
w := u.Workspace
|
||||
w = strings.Replace(w, "${GOPATH}", os.Getenv("GOPATH"), 1)
|
||||
|
||||
return filepath.FromSlash(w)
|
||||
|
@ -168,17 +154,9 @@ func (u *User) BuildArgs(os string) []string {
|
|||
func GetOwner(path string) string {
|
||||
for _, user := range Users {
|
||||
if strings.HasPrefix(path, user.WorkspacePath()) {
|
||||
return user.Name
|
||||
return user.Id
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// Salt salts the specified password with the specified salt.
|
||||
func Salt(password, salt string) string {
|
||||
sha1hash := sha1.New()
|
||||
sha1hash.Write([]byte(password + salt))
|
||||
|
||||
return hex.EncodeToString(sha1hash.Sum(nil))
|
||||
}
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
{
|
||||
"Name": "admin",
|
||||
"Password": "d1bfca21893c908e64fabda01d71294b1ccdcaa7",
|
||||
"Salt": "dnoyeb",
|
||||
"Email": "",
|
||||
"Gravatar": "d41d8cd98f00b204e9800998ecf8427e",
|
||||
"Workspace": "${GOPATH}",
|
||||
"Locale": "en_US",
|
||||
"GoFormat": "gofmt",
|
||||
"GoBuildArgsForLinux": "-i",
|
||||
"GoBuildArgsForWindows": "-i",
|
||||
"GoBuildArgsForDarwin": "-i",
|
||||
"FontFamily": "Helvetica",
|
||||
"FontSize": "13px",
|
||||
"Theme": "default",
|
||||
"Keymap": "wide",
|
||||
"Created": 1414080000000000000,
|
||||
"Updated": 1492963306222604966,
|
||||
"Lived": 1492963306222604966,
|
||||
"Editor": {
|
||||
"FontFamily": "Consolas, 'Courier New', monospace",
|
||||
"FontSize": "13px",
|
||||
"LineHeight": "17px",
|
||||
"Theme": "wide",
|
||||
"TabSize": "4"
|
||||
},
|
||||
"LatestSessionContent": {
|
||||
"fileTree": [
|
||||
"/Users/Vanessa/Work/Code/GoGoGo/src",
|
||||
"/Users/Vanessa/Work/Code/GoGoGo/src/github.com",
|
||||
"/Users/Vanessa/Work/Code/GoGoGo/src/github.com/b3log",
|
||||
"/Users/Vanessa/Work/Code/GoGoGo/src/github.com/b3log/wide",
|
||||
"/Users/Vanessa/Work/Code/GoGoGo/src/github.com/b3log/wide/.idea",
|
||||
"/Users/Vanessa/Work/Code/GoGoGo/src/github.com/b3log/wide/static",
|
||||
"/Users/Vanessa/Work/Code/GoGoGo/src/github.com/b3log/wide/static/css",
|
||||
"/Users/Vanessa/Work/Code/GoGoGo/src/github.com/b3log/wide/static/js"
|
||||
],
|
||||
"files": [],
|
||||
"currentFile": "",
|
||||
"layout": {
|
||||
"side": {
|
||||
"state": "normal",
|
||||
"size": 200
|
||||
},
|
||||
"sideRight": {
|
||||
"state": "normal",
|
||||
"size": 200
|
||||
},
|
||||
"bottom": {
|
||||
"state": "normal",
|
||||
"size": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
163
conf/wide.go
163
conf/wide.go
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -39,9 +39,11 @@ const (
|
|||
PathListSeparator = string(os.PathListSeparator)
|
||||
|
||||
// WideVersion holds the current Wide's version.
|
||||
WideVersion = "1.5.2"
|
||||
WideVersion = "1.5.3"
|
||||
// CodeMirrorVer holds the current editor version.
|
||||
CodeMirrorVer = "5.1"
|
||||
// UserAgent represents HTTP client user agent.
|
||||
UserAgent = "Wide/" + WideVersion + "; +https://github.com/b3log/wide"
|
||||
|
||||
HelloWorld = `package main
|
||||
|
||||
|
@ -55,22 +57,14 @@ func main() {
|
|||
|
||||
// Configuration.
|
||||
type conf struct {
|
||||
IP string // server ip, ${ip}
|
||||
Port string // server port
|
||||
Context string // server context
|
||||
Server string // server host and port ({IP}:{Port})
|
||||
StaticServer string // static resources server scheme, host and port (http://{IP}:{Port})
|
||||
Server string // server
|
||||
LogLevel string // logging level: trace/debug/info/warn/error
|
||||
Channel string // channel (ws://{IP}:{Port})
|
||||
Data string // data directory
|
||||
RuntimeMode string // runtime mode (dev/prod)
|
||||
HTTPSessionMaxAge int // HTTP session max age (in seciond)
|
||||
StaticResourceVersion string // version of static resources
|
||||
MaxProcs int // Go max procs
|
||||
RuntimeMode string // runtime mode (dev/prod)
|
||||
WD string // current working direcitory, ${pwd}
|
||||
Locale string // default locale
|
||||
Playground string // playground directory
|
||||
UsersWorkspaces string // users' workspaces directory (admin defaults to ${GOPATH}, others using this)
|
||||
AllowRegister bool // allow register or not
|
||||
Autocomplete bool // default autocomplete
|
||||
}
|
||||
|
||||
|
@ -83,21 +77,34 @@ var Wide *conf
|
|||
// configurations of users.
|
||||
var Users []*User
|
||||
|
||||
// Indicates whether runs via Docker.
|
||||
// Indicates whether Docker is available.
|
||||
var Docker bool
|
||||
|
||||
// Load loads the Wide configurations from wide.json and users' configurations from users/{username}.json.
|
||||
func Load(confPath, confIP, confPort, confServer, confLogLevel, confStaticServer, confContext, confChannel,
|
||||
confPlayground string, confDocker bool, confUsersWorkspaces string) {
|
||||
// XXX: ugly args list....
|
||||
// Docker image to run user's program
|
||||
const DockerImageGo = "golang"
|
||||
|
||||
initWide(confPath, confIP, confPort, confServer, confLogLevel, confStaticServer, confContext, confChannel,
|
||||
confPlayground, confDocker, confUsersWorkspaces)
|
||||
// Load loads the Wide configurations from wide.json and users' configurations from users/{userId}.json.
|
||||
func Load(confPath, confData, confServer, confLogLevel string) {
|
||||
initWide(confPath, confData, confServer, confLogLevel)
|
||||
initUsers()
|
||||
|
||||
cmd := exec.Command("docker", "version")
|
||||
_, err := cmd.CombinedOutput()
|
||||
if nil != err {
|
||||
if !util.OS.IsWindows() {
|
||||
logger.Errorf("Not found 'docker' installed, running user's code will cause security problem")
|
||||
|
||||
os.Exit(-1)
|
||||
}
|
||||
} else {
|
||||
Docker = true
|
||||
}
|
||||
}
|
||||
|
||||
func initUsers() {
|
||||
f, err := os.Open("conf/users")
|
||||
os.MkdirAll(Wide.Data+PathSeparator+"users", 0755)
|
||||
|
||||
f, err := os.Open(Wide.Data + PathSeparator + "users")
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
|
@ -123,8 +130,7 @@ func initUsers() {
|
|||
|
||||
user := &User{}
|
||||
|
||||
bytes, _ := ioutil.ReadFile("conf/users/" + name)
|
||||
|
||||
bytes, _ := ioutil.ReadFile(filepath.Join(Wide.Data, "users", name))
|
||||
err := json.Unmarshal(bytes, user)
|
||||
if err != nil {
|
||||
logger.Errorf("Parses [%s] error: %v, skip loading this user", name, err)
|
||||
|
@ -155,8 +161,7 @@ func initUsers() {
|
|||
initCustomizedConfs()
|
||||
}
|
||||
|
||||
func initWide(confPath, confIP, confPort, confServer, confLogLevel, confStaticServer, confContext, confChannel,
|
||||
confPlayground string, confDocker bool, confUsersWorkspaces string) {
|
||||
func initWide(confPath, confData, confServer, confLogLevel string) {
|
||||
bytes, err := ioutil.ReadFile(confPath)
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
|
@ -182,10 +187,6 @@ func initWide(confPath, confIP, confPort, confServer, confLogLevel, confStaticSe
|
|||
|
||||
logger.Debug("Conf: \n" + string(bytes))
|
||||
|
||||
// Working Directory
|
||||
Wide.WD = util.OS.Pwd()
|
||||
logger.Debugf("${pwd} [%s]", Wide.WD)
|
||||
|
||||
// User Home
|
||||
home, err := util.OS.Home()
|
||||
if nil != err {
|
||||
|
@ -193,82 +194,30 @@ func initWide(confPath, confIP, confPort, confServer, confLogLevel, confStaticSe
|
|||
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
logger.Debugf("${user.home} [%s]", home)
|
||||
|
||||
// Playground Directory
|
||||
Wide.Playground = strings.Replace(Wide.Playground, "${home}", home, 1)
|
||||
if "" != confPlayground {
|
||||
Wide.Playground = confPlayground
|
||||
// Data directory
|
||||
if "" != confData {
|
||||
Wide.Data = confData
|
||||
}
|
||||
|
||||
// Users' workspaces Directory
|
||||
Wide.UsersWorkspaces = strings.Replace(Wide.UsersWorkspaces, "${WD}", Wide.WD, 1)
|
||||
Wide.UsersWorkspaces = strings.Replace(Wide.UsersWorkspaces, "${home}", home, 1)
|
||||
if "" != confUsersWorkspaces {
|
||||
Wide.UsersWorkspaces = confUsersWorkspaces
|
||||
}
|
||||
Wide.UsersWorkspaces = filepath.Clean(Wide.UsersWorkspaces)
|
||||
|
||||
if !util.File.IsExist(Wide.Playground) {
|
||||
if err := os.Mkdir(Wide.Playground, 0775); nil != err {
|
||||
logger.Errorf("Create Playground [%s] error", err)
|
||||
Wide.Data = strings.Replace(Wide.Data, "${home}", home, -1)
|
||||
Wide.Data = filepath.Clean(Wide.Data)
|
||||
if !util.File.IsExist(Wide.Data) {
|
||||
if err := os.MkdirAll(Wide.Data, 0775); nil != err {
|
||||
logger.Errorf("Create data directory [%s] error", err)
|
||||
|
||||
os.Exit(-1)
|
||||
}
|
||||
}
|
||||
|
||||
// IP
|
||||
if "" != confIP {
|
||||
Wide.IP = confIP
|
||||
} else {
|
||||
ip, err := util.Net.LocalIP()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
logger.Debugf("${ip} [%s]", ip)
|
||||
Wide.IP = strings.Replace(Wide.IP, "${ip}", ip, 1)
|
||||
}
|
||||
|
||||
if "" != confPort {
|
||||
Wide.Port = confPort
|
||||
}
|
||||
|
||||
// Docker flag
|
||||
Docker = confDocker
|
||||
|
||||
// Server
|
||||
Wide.Server = strings.Replace(Wide.Server, "{IP}", Wide.IP, 1)
|
||||
Wide.Server = strings.Replace(Wide.Server, "{Port}", Wide.Port, 1)
|
||||
if "" != confServer {
|
||||
Wide.Server = confServer
|
||||
}
|
||||
|
||||
// Static Server
|
||||
Wide.StaticServer = strings.Replace(Wide.StaticServer, "{IP}", Wide.IP, 1)
|
||||
Wide.StaticServer = strings.Replace(Wide.StaticServer, "{Port}", Wide.Port, 1)
|
||||
if "" != confStaticServer {
|
||||
Wide.StaticServer = confStaticServer
|
||||
}
|
||||
|
||||
// Context
|
||||
if "" != confContext {
|
||||
Wide.Context = confContext
|
||||
}
|
||||
|
||||
time := strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
logger.Debugf("${time} [%s]", time)
|
||||
Wide.StaticResourceVersion = strings.Replace(Wide.StaticResourceVersion, "${time}", time, 1)
|
||||
|
||||
// Channel
|
||||
Wide.Channel = strings.Replace(Wide.Channel, "{IP}", Wide.IP, 1)
|
||||
Wide.Channel = strings.Replace(Wide.Channel, "{Port}", Wide.Port, 1)
|
||||
if "" != confChannel {
|
||||
Wide.Channel = confChannel
|
||||
}
|
||||
}
|
||||
|
||||
// FixedTimeCheckEnv checks Wide runtime enviorment periodically (7 minutes).
|
||||
|
@ -279,7 +228,7 @@ func FixedTimeCheckEnv() {
|
|||
checkEnv() // check immediately
|
||||
|
||||
go func() {
|
||||
for _ = range time.Tick(time.Minute * 7) {
|
||||
for _ = range time.Tick(time.Minute*7) {
|
||||
checkEnv()
|
||||
}
|
||||
}()
|
||||
|
@ -322,10 +271,10 @@ func checkEnv() {
|
|||
}
|
||||
}
|
||||
|
||||
// GetUserWorkspace gets workspace path with the specified username, returns "" if not found.
|
||||
func GetUserWorkspace(username string) string {
|
||||
// GetUserWorkspace gets workspace path with the specified user id, returns "" if not found.
|
||||
func GetUserWorkspace(userId string) string {
|
||||
for _, user := range Users {
|
||||
if user.Name == username {
|
||||
if user.Id == userId {
|
||||
return user.WorkspacePath()
|
||||
}
|
||||
}
|
||||
|
@ -334,9 +283,9 @@ func GetUserWorkspace(username string) string {
|
|||
}
|
||||
|
||||
// GetGoFmt gets the path of Go format tool, returns "gofmt" if not found "goimports".
|
||||
func GetGoFmt(username string) string {
|
||||
func GetGoFmt(userId string) string {
|
||||
for _, user := range Users {
|
||||
if user.Name == username {
|
||||
if user.Id == userId {
|
||||
switch user.GoFormat {
|
||||
case "gofmt":
|
||||
return "gofmt"
|
||||
|
@ -352,15 +301,14 @@ func GetGoFmt(username string) string {
|
|||
return "gofmt"
|
||||
}
|
||||
|
||||
// GetUser gets configuration of the user specified by the given username, returns nil if not found.
|
||||
func GetUser(username string) *User {
|
||||
if "playground" == username { // reserved user for Playground
|
||||
// mock it
|
||||
return NewUser("playground", "", "", "")
|
||||
// GetUser gets configuration of the user specified by the given user id, returns nil if not found.
|
||||
func GetUser(id string) *User {
|
||||
if "playground" == id { // reserved user for Playground
|
||||
return NewUser("playground", "playground", "", "")
|
||||
}
|
||||
|
||||
for _, user := range Users {
|
||||
if user.Name == username {
|
||||
if user.Id == id {
|
||||
return user
|
||||
}
|
||||
}
|
||||
|
@ -371,17 +319,17 @@ func GetUser(username string) *User {
|
|||
// initCustomizedConfs initializes the user customized configurations.
|
||||
func initCustomizedConfs() {
|
||||
for _, user := range Users {
|
||||
UpdateCustomizedConf(user.Name)
|
||||
UpdateCustomizedConf(user.Id)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateCustomizedConf creates (if not exists) or updates user customized configuration files.
|
||||
//
|
||||
// 1. /static/user/{username}/style.css
|
||||
func UpdateCustomizedConf(username string) {
|
||||
// 1. /static/users/{userId}/style.css
|
||||
func UpdateCustomizedConf(userId string) {
|
||||
var u *User
|
||||
for _, user := range Users { // maybe it is a beauty of the trade-off of the another world between design and implementation
|
||||
if user.Name == username {
|
||||
if user.Id == userId {
|
||||
u = user
|
||||
}
|
||||
}
|
||||
|
@ -399,8 +347,7 @@ func UpdateCustomizedConf(username string) {
|
|||
os.Exit(-1)
|
||||
}
|
||||
|
||||
wd := util.OS.Pwd()
|
||||
dir := filepath.Clean(wd + "/static/user/" + u.Name)
|
||||
dir := filepath.Clean(Wide.Data + "/static/users/" + userId)
|
||||
if err := os.MkdirAll(dir, 0755); nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
|
|
|
@ -1,19 +1,11 @@
|
|||
{
|
||||
"IP": "${ip}",
|
||||
"Port": "7070",
|
||||
"Context": "",
|
||||
"Server": "{IP}:{Port}",
|
||||
"StaticServer": "",
|
||||
"Server": "http://127.0.0.1:7070",
|
||||
"LogLevel": "debug",
|
||||
"Channel": "ws://{IP}:{Port}",
|
||||
"Data": "${home}/wide",
|
||||
"RuntimeMode": "dev",
|
||||
"HTTPSessionMaxAge": 86400,
|
||||
"StaticResourceVersion": "${time}",
|
||||
"MaxProcs": 4,
|
||||
"RuntimeMode": "dev",
|
||||
"WD": "${pwd}",
|
||||
"Locale": "en_US",
|
||||
"Playground": "${home}/playground",
|
||||
"UsersWorkspaces": "${WD}/workspaces",
|
||||
"AllowRegister": true,
|
||||
"Autocomplete": true
|
||||
}
|
|
@ -8,7 +8,7 @@ set -e
|
|||
echo "mode: count" > profile.cov
|
||||
|
||||
# Standard go tooling behavior is to ignore dirs with leading underscors
|
||||
for dir in $(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d);
|
||||
for dir in $(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -not -path './vendor*' -type d);
|
||||
do
|
||||
if ls $dir/*.go &> /dev/null; then
|
||||
go test -covermode=count -coverprofile=$dir/profile.tmp $dir
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,2 +0,0 @@
|
|||
* [User Guide](https://www.gitbook.com/book/88250/wide-user-guide)
|
||||
* [Developer Guide](https://www.gitbook.com/book/88250/wide-dev-guide)
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -41,7 +41,7 @@ var logger = log.NewLogger(os.Stdout)
|
|||
// WSHandler handles request of creating editor channel.
|
||||
// XXX: NOT used at present
|
||||
func WSHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
|
@ -111,13 +111,13 @@ func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
session, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
session, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if session.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := session.Values["username"].(string)
|
||||
uid := session.Values["uid"].(string)
|
||||
|
||||
path := args["path"].(string)
|
||||
|
||||
|
@ -147,7 +147,7 @@ func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
logger.Tracef("offset: %d", offset)
|
||||
|
||||
userWorkspace := conf.GetUserWorkspace(username)
|
||||
userWorkspace := conf.GetUserWorkspace(uid)
|
||||
workspaces := filepath.SplitList(userWorkspace)
|
||||
libPath := ""
|
||||
for _, workspace := range workspaces {
|
||||
|
@ -182,8 +182,8 @@ func GetExprInfoHandler(w http.ResponseWriter, r *http.Request) {
|
|||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
session, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
username := session.Values["username"].(string)
|
||||
session, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
uid := session.Values["uid"].(string)
|
||||
|
||||
var args map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
|
@ -228,7 +228,7 @@ func GetExprInfoHandler(w http.ResponseWriter, r *http.Request) {
|
|||
cmd := exec.Command(ideStub, argv...)
|
||||
cmd.Dir = curDir
|
||||
|
||||
setCmdEnv(cmd, username)
|
||||
setCmdEnv(cmd, uid)
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if nil != err {
|
||||
|
@ -253,13 +253,13 @@ func FindDeclarationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
session, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
session, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if session.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := session.Values["username"].(string)
|
||||
uid := session.Values["uid"].(string)
|
||||
|
||||
var args map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
|
@ -304,7 +304,7 @@ func FindDeclarationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
cmd := exec.Command(ideStub, argv...)
|
||||
cmd.Dir = curDir
|
||||
|
||||
setCmdEnv(cmd, username)
|
||||
setCmdEnv(cmd, uid)
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if nil != err {
|
||||
|
@ -341,13 +341,13 @@ func FindUsagesHandler(w http.ResponseWriter, r *http.Request) {
|
|||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
session, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
session, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if session.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := session.Values["username"].(string)
|
||||
uid := session.Values["uid"].(string)
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
|
@ -392,7 +392,7 @@ func FindUsagesHandler(w http.ResponseWriter, r *http.Request) {
|
|||
cmd := exec.Command(ideStub, argv...)
|
||||
cmd.Dir = curDir
|
||||
|
||||
setCmdEnv(cmd, username)
|
||||
setCmdEnv(cmd, uid)
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if nil != err {
|
||||
|
@ -453,8 +453,8 @@ func getCursorOffset(code string, line, ch int) (offset int) {
|
|||
return offset
|
||||
}
|
||||
|
||||
func setCmdEnv(cmd *exec.Cmd, username string) {
|
||||
userWorkspace := conf.GetUserWorkspace(username)
|
||||
func setCmdEnv(cmd *exec.Cmd, userId string) {
|
||||
userWorkspace := conf.GetUserWorkspace(userId)
|
||||
|
||||
cmd.Env = append(cmd.Env,
|
||||
"GOPATH="+userWorkspace,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -34,13 +34,13 @@ func GoFmtHandler(w http.ResponseWriter, r *http.Request) {
|
|||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
session, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
session, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if session.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := session.Values["username"].(string)
|
||||
uid := session.Values["uid"].(string)
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
|
@ -85,7 +85,7 @@ func GoFmtHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
result.Data = data
|
||||
|
||||
fmt := conf.GetGoFmt(username)
|
||||
fmt := conf.GetGoFmt(uid)
|
||||
|
||||
argv := []string{filePath}
|
||||
cmd := exec.Command(fmt, argv...)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -74,18 +74,18 @@ func initAPINode() {
|
|||
// The Go API source code package also as a child node,
|
||||
// so that users can easily view the Go API source code in file tree.
|
||||
func GetFilesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetGzResult(w, r, result)
|
||||
|
||||
userWorkspace := conf.GetUserWorkspace(username)
|
||||
userWorkspace := conf.GetUserWorkspace(uid)
|
||||
workspaces := filepath.SplitList(userWorkspace)
|
||||
|
||||
root := Node{Name: "root", Path: "", IconSkin: "ico-ztree-dir ", Type: "d", IsParent: true, Children: []*Node{}}
|
||||
|
@ -123,18 +123,18 @@ func GetFilesHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// RefreshDirectoryHandler handles request of refresh a directory of file tree.
|
||||
func RefreshDirectoryHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
r.ParseForm()
|
||||
path := r.FormValue("path")
|
||||
|
||||
if !util.Go.IsAPI(path) && !session.CanAccess(username, path) {
|
||||
if !util.Go.IsAPI(path) && !session.CanAccess(uid, path) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -156,13 +156,13 @@ func RefreshDirectoryHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// GetFileHandler handles request of opening file by editor.
|
||||
func GetFileHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
@ -178,7 +178,7 @@ func GetFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
path := args["path"].(string)
|
||||
|
||||
if !util.Go.IsAPI(path) && !session.CanAccess(username, path) {
|
||||
if !util.Go.IsAPI(path) && !session.CanAccess(uid, path) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -204,15 +204,15 @@ func GetFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
data["mode"] = "img"
|
||||
|
||||
username := conf.GetOwner(path)
|
||||
if "" == username {
|
||||
logger.Warnf("The path [%s] has no owner")
|
||||
userId := conf.GetOwner(path)
|
||||
if "" == userId {
|
||||
logger.Warnf("The path [%s] has no owner", path)
|
||||
data["path"] = ""
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
user := conf.GetUser(username)
|
||||
user := conf.GetUser(uid)
|
||||
|
||||
data["path"] = "/workspace/" + user.Name + "/" + strings.Replace(path, user.WorkspacePath(), "", 1)
|
||||
|
||||
|
@ -232,13 +232,13 @@ func GetFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// SaveFileHandler handles request of saving file.
|
||||
func SaveFileHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
@ -255,7 +255,7 @@ func SaveFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
filePath := args["file"].(string)
|
||||
sid := args["sid"].(string)
|
||||
|
||||
if util.Go.IsAPI(filePath) || !session.CanAccess(username, filePath) {
|
||||
if util.Go.IsAPI(filePath) || !session.CanAccess(uid, filePath) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -288,13 +288,13 @@ func SaveFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// NewFileHandler handles request of creating file or directory.
|
||||
func NewFileHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
@ -310,7 +310,7 @@ func NewFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
path := args["path"].(string)
|
||||
|
||||
if util.Go.IsAPI(path) || !session.CanAccess(username, path) {
|
||||
if util.Go.IsAPI(path) || !session.CanAccess(uid, path) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -331,22 +331,22 @@ func NewFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if "f" == fileType {
|
||||
logger.Debugf("Created a file [%s] by user [%s]", path, wSession.Username)
|
||||
logger.Debugf("Created a file [%s] by user [%s]", path, wSession.UserId)
|
||||
} else {
|
||||
logger.Debugf("Created a dir [%s] by user [%s]", path, wSession.Username)
|
||||
logger.Debugf("Created a dir [%s] by user [%s]", path, wSession.UserId)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// RemoveFileHandler handles request of removing file or directory.
|
||||
func RemoveFileHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
@ -362,7 +362,7 @@ func RemoveFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
path := args["path"].(string)
|
||||
|
||||
if util.Go.IsAPI(path) || !session.CanAccess(username, path) {
|
||||
if util.Go.IsAPI(path) || !session.CanAccess(uid, path) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -381,18 +381,18 @@ func RemoveFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
logger.Debugf("Removed a file [%s] by user [%s]", path, wSession.Username)
|
||||
logger.Debugf("Removed a file [%s] by user [%s]", path, wSession.UserId)
|
||||
}
|
||||
|
||||
// RenameFileHandler handles request of renaming file or directory.
|
||||
func RenameFileHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
@ -408,14 +408,14 @@ func RenameFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
oldPath := args["oldPath"].(string)
|
||||
if util.Go.IsAPI(oldPath) ||
|
||||
!session.CanAccess(username, oldPath) {
|
||||
!session.CanAccess(uid, oldPath) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
newPath := args["newPath"].(string)
|
||||
if util.Go.IsAPI(newPath) || !session.CanAccess(username, newPath) {
|
||||
if util.Go.IsAPI(newPath) || !session.CanAccess(uid, newPath) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -434,7 +434,7 @@ func RenameFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
logger.Debugf("Renamed a file [%s] to [%s] by user [%s]", oldPath, newPath, wSession.Username)
|
||||
logger.Debugf("Renamed a file [%s] to [%s] by user [%s]", oldPath, newPath, wSession.UserId)
|
||||
}
|
||||
|
||||
// Use to find results sorting.
|
||||
|
@ -451,13 +451,13 @@ func (f foundPaths) Less(i, j int) bool { return f[i].score > f[j].score }
|
|||
|
||||
// FindHandler handles request of find files under the specified directory with the specified filename pattern.
|
||||
func FindHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
@ -471,7 +471,7 @@ func FindHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
path := args["path"].(string) // path of selected file in file tree
|
||||
if !util.Go.IsAPI(path) && !session.CanAccess(username, path) {
|
||||
if !util.Go.IsAPI(path) && !session.CanAccess(uid, path) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -479,7 +479,7 @@ func FindHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
name := args["name"].(string)
|
||||
|
||||
userWorkspace := conf.GetUserWorkspace(username)
|
||||
userWorkspace := conf.GetUserWorkspace(uid)
|
||||
workspaces := filepath.SplitList(userWorkspace)
|
||||
|
||||
if "" != path && !util.File.IsDir(path) {
|
||||
|
@ -505,7 +505,7 @@ func FindHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// SearchTextHandler handles request of searching files under the specified directory with the specified keyword.
|
||||
func SearchTextHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
|
@ -536,7 +536,7 @@ func SearchTextHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
dir := args["dir"].(string)
|
||||
if "" == dir {
|
||||
userWorkspace := conf.GetUserWorkspace(wSession.Username)
|
||||
userWorkspace := conf.GetUserWorkspace(wSession.UserId)
|
||||
workspaces := filepath.SplitList(userWorkspace)
|
||||
dir = workspaces[0]
|
||||
}
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/b3log/wide/util"
|
||||
)
|
||||
|
||||
type fileInfo struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func handleUpload(p *multipart.Part, dir string) (fi *fileInfo) {
|
||||
fi = &fileInfo{
|
||||
Name: p.FileName(),
|
||||
Type: p.Header.Get("Content-Type"),
|
||||
}
|
||||
|
||||
path := filepath.Clean(dir + "/" + fi.Name)
|
||||
f, _ := os.Create(path)
|
||||
|
||||
io.Copy(f, p)
|
||||
|
||||
f.Close()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func handleUploads(r *http.Request, dir string) (fileInfos []*fileInfo) {
|
||||
fileInfos = make([]*fileInfo, 0)
|
||||
mr, err := r.MultipartReader()
|
||||
|
||||
part, err := mr.NextPart()
|
||||
|
||||
for err == nil {
|
||||
if name := part.FormName(); name != "" {
|
||||
if part.FileName() != "" {
|
||||
fileInfos = append(fileInfos, handleUpload(part, dir))
|
||||
}
|
||||
}
|
||||
|
||||
part, err = mr.NextPart()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UploadHandler handles request of file upload.
|
||||
func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
q := r.URL.Query()
|
||||
dir := q["path"][0]
|
||||
|
||||
result.Data = handleUploads(r, dir)
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
module github.com/b3log/wide
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/gorilla/context v0.0.0-20141217160251-215affda49ad // indirect
|
||||
github.com/gorilla/securecookie v0.0.0-20150327155805-8e98dd730fc4 // indirect
|
||||
github.com/gorilla/sessions v0.0.0-20150417174705-f61c3ec2cf65
|
||||
github.com/gorilla/websocket v0.0.0-20150530030352-a3ec486e6a7a
|
||||
github.com/hashicorp/go-version v1.2.0
|
||||
github.com/moul/http2curl v1.0.0 // indirect
|
||||
github.com/parnurzeal/gorequest v0.2.15
|
||||
github.com/pkg/errors v0.8.1 // indirect
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect
|
||||
golang.org/x/net v0.0.0-20190514140710-3ec191127204 // indirect
|
||||
golang.org/x/sys v0.0.0-20190515190549-87c872767d25 // indirect
|
||||
golang.org/x/text v0.3.2
|
||||
)
|
|
@ -0,0 +1,43 @@
|
|||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f h1:8GDPb0tCY8LQ+OJ3dbHb5sA6YZWXFORQYZx5sdsTlMs=
|
||||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f h1:AUj1VoZUfhPhOPHULCQQDnGhRelpFWHMLhQVWDsS0v4=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v0.0.0-20141217160251-215affda49ad h1:wJwKN6X6iRRVnjdBgrkWjhBOvYm7yw5boqXwFUnBtbE=
|
||||
github.com/gorilla/context v0.0.0-20141217160251-215affda49ad/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/securecookie v0.0.0-20150327155805-8e98dd730fc4 h1:X0DbEdoaUJT+NZ8mLHRNMSLmogzqLhsA1Eh6gs7Y7Zg=
|
||||
github.com/gorilla/securecookie v0.0.0-20150327155805-8e98dd730fc4/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v0.0.0-20150417174705-f61c3ec2cf65 h1:bDPV+Nh80WIp0U0a/o9wKilWRxH+l8jIySjElU91LeA=
|
||||
github.com/gorilla/sessions v0.0.0-20150417174705-f61c3ec2cf65/go.mod h1:+WVp8kdw6VhyKExm03PAMRn2ZxnPtm58pV0dBVPdhHE=
|
||||
github.com/gorilla/websocket v0.0.0-20150530030352-a3ec486e6a7a h1:p/PGT+3UGSK7eULOGHUMCUxI5U976R34HWuKHbFpK3Q=
|
||||
github.com/gorilla/websocket v0.0.0-20150530030352-a3ec486e6a7a/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs=
|
||||
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
||||
github.com/parnurzeal/gorequest v0.2.15 h1:oPjDCsF5IkD4gUk6vIgsxYNaSgvAnIh1EJeROn3HdJU=
|
||||
github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190514140710-3ec191127204 h1:4yG6GqBtw9C+UrLp6s2wtSniayy/Vd/3F7ffLE427XI=
|
||||
golang.org/x/net v0.0.0-20190514140710-3ec191127204/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190515190549-87c872767d25 h1:SSKQq5sjDoW0L0NaDoVl7d7HmtTxM0ezm0Ef9azs4uQ=
|
||||
golang.org/x/sys v0.0.0-20190515190549-87c872767d25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
235
gulpfile.js
235
gulpfile.js
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2015, b3log.org
|
||||
* Copyright (c) 2014-2018, b3log.org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -16,120 +16,135 @@
|
|||
|
||||
/**
|
||||
* @file frontend tool.
|
||||
*
|
||||
*
|
||||
* @author <a href="mailto:liliyuan@fangstar.net">Liyuan Li</a>
|
||||
* @version 0.1.0.0, Dec 15, 2015
|
||||
* @version 0.2.0.0, Oct 5, 2018
|
||||
*/
|
||||
var gulp = require("gulp");
|
||||
var concat = require('gulp-concat');
|
||||
var minifyCSS = require('gulp-minify-css');
|
||||
var uglify = require('gulp-uglify');
|
||||
var sourcemaps = require("gulp-sourcemaps");
|
||||
var gulp = require('gulp')
|
||||
var concat = require('gulp-concat')
|
||||
var minifyCSS = require('gulp-minify-css')
|
||||
var uglify = require('gulp-uglify')
|
||||
var sourcemaps = require('gulp-sourcemaps')
|
||||
|
||||
gulp.task('cc', function () {
|
||||
// css
|
||||
var cssLibs = ['./static/js/lib/jquery-layout/layout-default-latest.css',
|
||||
'./static/js/lib/codemirror-5.1/codemirror.css',
|
||||
'./static/js/lib/codemirror-5.1/addon/hint/show-hint.css',
|
||||
'./static/js/lib/codemirror-5.1/addon/lint/lint.css',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/foldgutter.css',
|
||||
'./static/js/lib/codemirror-5.1/addon/dialog/dialog.css',
|
||||
'./static/js/overwrite/codemirror/theme/*.css'];
|
||||
gulp.src(cssLibs)
|
||||
.pipe(minifyCSS())
|
||||
.pipe(concat('lib.min.css'))
|
||||
.pipe(gulp.dest('./static/css/'));
|
||||
function minLibCSS () {
|
||||
// css
|
||||
var cssLibs = [
|
||||
'./static/js/lib/jquery-layout/layout-default-latest.css',
|
||||
'./static/js/lib/codemirror-5.1/codemirror.css',
|
||||
'./static/js/lib/codemirror-5.1/addon/hint/show-hint.css',
|
||||
'./static/js/lib/codemirror-5.1/addon/lint/lint.css',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/foldgutter.css',
|
||||
'./static/js/lib/codemirror-5.1/addon/dialog/dialog.css',
|
||||
'./static/js/overwrite/codemirror/theme/*.css']
|
||||
return gulp.src(cssLibs).
|
||||
pipe(minifyCSS()).
|
||||
pipe(concat('lib.min.css')).
|
||||
pipe(gulp.dest('./static/css/'))
|
||||
}
|
||||
|
||||
gulp.src('./static/js/lib/ztree/zTreeStyle.css')
|
||||
.pipe(minifyCSS())
|
||||
.pipe(concat('zTreeStyle.min.css'))
|
||||
.pipe(gulp.dest('./static/js/lib/ztree/'));
|
||||
function minZTreeStyleCSS () {
|
||||
return gulp.src('./static/js/lib/ztree/zTreeStyle.css').
|
||||
pipe(minifyCSS()).
|
||||
pipe(concat('zTreeStyle.min.css')).
|
||||
pipe(gulp.dest('./static/js/lib/ztree/'))
|
||||
}
|
||||
|
||||
var cssWide = ['./static/css/dialog.css',
|
||||
'./static/css/base.css',
|
||||
'./static/css/wide.css',
|
||||
'./static/css/side.css',
|
||||
'./static/css/start.css',
|
||||
'./static/css/about.css'
|
||||
];
|
||||
function minWideCSS () {
|
||||
var cssWide = [
|
||||
'./static/css/dialog.css',
|
||||
'./static/css/base.css',
|
||||
'./static/css/wide.css',
|
||||
'./static/css/side.css',
|
||||
'./static/css/start.css',
|
||||
'./static/css/about.css',
|
||||
]
|
||||
|
||||
gulp.src(cssWide)
|
||||
.pipe(minifyCSS())
|
||||
.pipe(concat('wide.min.css'))
|
||||
.pipe(gulp.dest('./static/css/'));
|
||||
return gulp.src(cssWide).
|
||||
pipe(minifyCSS()).
|
||||
pipe(concat('wide.min.css')).
|
||||
pipe(gulp.dest('./static/css/'))
|
||||
}
|
||||
|
||||
function minLibJS () {
|
||||
// js
|
||||
var jsLibs = [
|
||||
'./static/js/lib/jquery-2.1.1.min.js',
|
||||
'./static/js/lib/jquery-ui.min.js',
|
||||
'./static/js/lib/jquery-layout/jquery.layout-latest.js',
|
||||
'./static/js/lib/reconnecting-websocket.js',
|
||||
'./static/js/lib/Autolinker.min.js',
|
||||
'./static/js/lib/emmet.js',
|
||||
'./static/js/lib/js-beautify-1.5.4/beautify.js',
|
||||
'./static/js/lib/js-beautify-1.5.4/beautify-html.js',
|
||||
'./static/js/lib/js-beautify-1.5.4/beautify-css.js',
|
||||
'./static/js/lib/jquery-file-upload-9.8.0/vendor/jquery.ui.widget.js',
|
||||
'./static/js/lib/jquery-file-upload-9.8.0/jquery.iframe-transport.js',
|
||||
'./static/js/lib/jquery-file-upload-9.8.0/jquery.fileupload.js',
|
||||
'./static/js/lib/codemirror-5.1/codemirror.min.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/lint/lint.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/lint/json-lint.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/selection/active-line.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/selection/active-line.js',
|
||||
'./static/js/overwrite/codemirror/addon/hint/show-hint.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/hint/anyword-hint.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/display/rulers.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/edit/closebrackets.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/edit/matchbrackets.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/edit/closetag.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/search/searchcursor.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/search/search.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/dialog/dialog.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/search/match-highlighter.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/foldcode.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/foldgutter.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/brace-fold.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/xml-fold.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/markdown-fold.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/comment-fold.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/mode/loadmode.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/comment/comment.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/meta.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/go/go.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/clike/clike.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/xml/xml.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/htmlmixed/htmlmixed.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/javascript/javascript.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/markdown/markdown.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/css/css.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/shell/shell.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/sql/sql.js',
|
||||
'./static/js/lib/codemirror-5.1/keymap/vim.js',
|
||||
'./static/js/lib/lint/json-lint.js',
|
||||
'./static/js/lib/lint/go-lint.js']
|
||||
return gulp.src(jsLibs).
|
||||
pipe(uglify()).
|
||||
pipe(concat('lib.min.js')).
|
||||
pipe(gulp.dest('./static/js/'))
|
||||
}
|
||||
|
||||
// js
|
||||
var jsLibs = ['./static/js/lib/jquery-2.1.1.min.js',
|
||||
'./static/js/lib/jquery-ui.min.js',
|
||||
'./static/js/lib/jquery-layout/jquery.layout-latest.js',
|
||||
'./static/js/lib/reconnecting-websocket.js',
|
||||
'./static/js/lib/Autolinker.min.js',
|
||||
'./static/js/lib/emmet.js',
|
||||
'./static/js/lib/js-beautify-1.5.4/beautify.js',
|
||||
'./static/js/lib/js-beautify-1.5.4/beautify-html.js',
|
||||
'./static/js/lib/js-beautify-1.5.4/beautify-css.js',
|
||||
'./static/js/lib/jquery-file-upload-9.8.0/vendor/jquery.ui.widget.js',
|
||||
'./static/js/lib/jquery-file-upload-9.8.0/jquery.iframe-transport.js',
|
||||
'./static/js/lib/jquery-file-upload-9.8.0/jquery.fileupload.js',
|
||||
'./static/js/lib/codemirror-5.1/codemirror.min.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/lint/lint.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/lint/json-lint.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/selection/active-line.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/selection/active-line.js',
|
||||
'./static/js/overwrite/codemirror/addon/hint/show-hint.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/hint/anyword-hint.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/display/rulers.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/edit/closebrackets.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/edit/matchbrackets.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/edit/closetag.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/search/searchcursor.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/search/search.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/dialog/dialog.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/search/match-highlighter.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/foldcode.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/foldgutter.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/brace-fold.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/xml-fold.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/markdown-fold.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/comment-fold.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/mode/loadmode.js',
|
||||
'./static/js/lib/codemirror-5.1/addon/fold/comment/comment.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/meta.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/go/go.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/clike/clike.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/xml/xml.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/htmlmixed/htmlmixed.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/javascript/javascript.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/markdown/markdown.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/css/css.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/shell/shell.js',
|
||||
'./static/js/lib/codemirror-5.1/mode/sql/sql.js',
|
||||
'./static/js/lib/codemirror-5.1/keymap/vim.js',
|
||||
'./static/js/lib/lint/json-lint.js',
|
||||
'./static/js/lib/lint/go-lint.js'];
|
||||
gulp.src(jsLibs)
|
||||
.pipe(uglify())
|
||||
.pipe(concat('lib.min.js'))
|
||||
.pipe(gulp.dest('./static/js/'));
|
||||
function minWideJS () {
|
||||
var jsWide = [
|
||||
'./static/js/tabs.js',
|
||||
'./static/js/tabs.js',
|
||||
'./static/js/dialog.js',
|
||||
'./static/js/editors.js',
|
||||
'./static/js/notification.js',
|
||||
'./static/js/tree.js',
|
||||
'./static/js/wide.js',
|
||||
'./static/js/session.js',
|
||||
'./static/js/menu.js',
|
||||
'./static/js/windows.js',
|
||||
'./static/js/hotkeys.js',
|
||||
'./static/js/bottomGroup.js',
|
||||
]
|
||||
return gulp.src(jsWide).
|
||||
pipe(sourcemaps.init()).
|
||||
pipe(uglify()).
|
||||
pipe(concat('wide.min.js')).
|
||||
pipe(sourcemaps.write('.')).
|
||||
pipe(gulp.dest('./static/js/'))
|
||||
}
|
||||
|
||||
var jsWide = ['./static/js/tabs.js',
|
||||
'./static/js/tabs.js',
|
||||
'./static/js/dialog.js',
|
||||
'./static/js/editors.js',
|
||||
'./static/js/notification.js',
|
||||
'./static/js/tree.js',
|
||||
'./static/js/wide.js',
|
||||
'./static/js/session.js',
|
||||
'./static/js/menu.js',
|
||||
'./static/js/windows.js',
|
||||
'./static/js/hotkeys.js',
|
||||
'./static/js/bottomGroup.js'
|
||||
];
|
||||
gulp.src(jsWide)
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(uglify())
|
||||
.pipe(concat('wide.min.js'))
|
||||
.pipe(sourcemaps.write("."))
|
||||
.pipe(gulp.dest('./static/js/'));
|
||||
});
|
||||
gulp.task('default',
|
||||
gulp.series(
|
||||
gulp.parallel(minLibCSS, minZTreeStyleCSS, minWideCSS, minLibJS, minWideJS)))
|
|
@ -105,8 +105,6 @@
|
|||
"start-get": "START [go get]",
|
||||
"get-succ": "[go get] SUCCESS",
|
||||
"get-error": "[go get] ERROR",
|
||||
"start-git_clone": "START [git clone]",
|
||||
"git_clone-done": "[git clone] DONE",
|
||||
"check_version": "Checking update",
|
||||
"new_version_available": "new version available",
|
||||
"go_env": "Go",
|
||||
|
@ -139,7 +137,6 @@
|
|||
"clearOutput": "Clear Output",
|
||||
"export": "Export",
|
||||
"refresh": "Refresh",
|
||||
"import": "Import",
|
||||
"theme": "Theme",
|
||||
"tab_size": "Tab Size",
|
||||
"copy_file_path": "Copy File Path",
|
||||
|
@ -162,7 +159,6 @@
|
|||
"no_empty": "Can not Empty!",
|
||||
"change_avatar": "Avatar modify go",
|
||||
"open": "Open",
|
||||
"pricing": "Pricing",
|
||||
"search_no_match": "No matching files were found.",
|
||||
"outline": "Outline",
|
||||
"govet": "go vet",
|
||||
|
@ -174,7 +170,6 @@
|
|||
"url": "URL",
|
||||
"short_url": "Short URL",
|
||||
"embeded": "Embeded",
|
||||
"git_clone": "Git Clone",
|
||||
"terms": "Terms",
|
||||
"download": "Download",
|
||||
"decompress": "Decompress",
|
||||
|
|
|
@ -105,8 +105,6 @@
|
|||
"start-get": "[go get] 開始",
|
||||
"get-succ": "[go get] 成功",
|
||||
"get-error": "[go get] 失敗",
|
||||
"start-git_clone": "[git clone] 開始",
|
||||
"git_clone-done": "[git clone] 終わった",
|
||||
"check_version": "更新をチェック中",
|
||||
"new_version_available": "新しいバージョンがあります",
|
||||
"go_env": "Go",
|
||||
|
@ -139,7 +137,6 @@
|
|||
"clearOutput": "空の出力",
|
||||
"export": "輸出",
|
||||
"refresh": "リフレッシュ",
|
||||
"import": "インポート",
|
||||
"theme": "テーマ",
|
||||
"tab_size": "Tab サイズ",
|
||||
"copy_file_path": "ファイルパスをコピー",
|
||||
|
@ -162,7 +159,6 @@
|
|||
"no_empty": "空ではありません",
|
||||
"change_avatar": "アバターの変更は行く",
|
||||
"open": "オープン",
|
||||
"pricing": "价格",
|
||||
"search_no_match": "一致するファイルが見つかりませんでした。",
|
||||
"outline": "アウトライン",
|
||||
"govet": "go vet",
|
||||
|
@ -174,7 +170,6 @@
|
|||
"url": "リンク",
|
||||
"short_url": "ショートリンク",
|
||||
"embeded": "埋め込む",
|
||||
"git_clone": "Git クローン",
|
||||
"terms": "利用規約",
|
||||
"download": "ダウンロード",
|
||||
"decompress": "解凍する",
|
||||
|
|
|
@ -105,8 +105,6 @@
|
|||
"start-get": "시작 [go get]",
|
||||
"get-succ": "[go get] 성공",
|
||||
"get-error": "[go get] 실패",
|
||||
"start-git_clone": "시작 [git clone]",
|
||||
"git_clone-done": "[git clone] 완성",
|
||||
"check_version": "최신버전검색중",
|
||||
"new_version_available": "최신업데이트 사용 가능",
|
||||
"go_env": "Go 환경",
|
||||
|
@ -139,7 +137,6 @@
|
|||
"clearOutput": "ouput 클리어",
|
||||
"export": "내보내기",
|
||||
"refresh": "새로고침",
|
||||
"import": "가져오기",
|
||||
"theme": "주제",
|
||||
"tab_size": "Tab 크기",
|
||||
"copy_file_path": "경로복사",
|
||||
|
@ -162,7 +159,6 @@
|
|||
"no_empty": "값을 입력해 주세요.",
|
||||
"change_avatar": "아이콘변경은 여기로.",
|
||||
"open": "열기",
|
||||
"pricing": "가격",
|
||||
"search_no_match": "해당 문서를 찾지 못하였습니다.",
|
||||
"outline": "주제",
|
||||
"govet": "go vet",
|
||||
|
@ -174,7 +170,6 @@
|
|||
"url": "하이퍼링크",
|
||||
"short_url": "짧은 링크",
|
||||
"embeded": "삽입",
|
||||
"git_clone": "Git clone",
|
||||
"terms": "사용계약",
|
||||
"download": "다운로드",
|
||||
"decompress": "압축풀기",
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -105,8 +105,6 @@
|
|||
"start-get": "开始 [go get]",
|
||||
"get-succ": "[go get] 成功",
|
||||
"get-error": "[go get] 失败",
|
||||
"start-git_clone": "开始 [git clone]",
|
||||
"git_clone-done": "[git clone] 完成",
|
||||
"check_version": "正在检查更新",
|
||||
"new_version_available": "新版本可用",
|
||||
"go_env": "Go 环境",
|
||||
|
@ -139,7 +137,6 @@
|
|||
"clearOutput": "清空输出",
|
||||
"export": "导出",
|
||||
"refresh": "刷新",
|
||||
"import": "导入",
|
||||
"theme": "主题",
|
||||
"tab_size": "Tab 大小",
|
||||
"copy_file_path": "复制文件路径",
|
||||
|
@ -162,7 +159,6 @@
|
|||
"no_empty": "不能为空",
|
||||
"change_avatar": "头像修改请到",
|
||||
"open": "打开",
|
||||
"pricing": "价格",
|
||||
"search_no_match": "没有发现匹配的文件。",
|
||||
"outline": "大纲",
|
||||
"govet": "go vet",
|
||||
|
@ -174,7 +170,6 @@
|
|||
"url": "链接",
|
||||
"short_url": "短链接",
|
||||
"embeded": "嵌入",
|
||||
"git_clone": "Git 克隆",
|
||||
"terms": "使用条款",
|
||||
"download": "下载",
|
||||
"decompress": "解压缩",
|
||||
|
|
|
@ -105,8 +105,6 @@
|
|||
"start-get": "開始 [go get]",
|
||||
"get-succ": "[go get] 成功",
|
||||
"get-error": "[go get] 失敗",
|
||||
"start-git_clone": "開始 [git clone]",
|
||||
"git_clone-done": "[git clone] 完成",
|
||||
"check_version": "正在檢查更新",
|
||||
"new_version_available": "可用新版本",
|
||||
"go_env": "Go 環境",
|
||||
|
@ -139,7 +137,6 @@
|
|||
"clearOutput": "清空輸出",
|
||||
"export": "導出",
|
||||
"refresh": "刷新",
|
||||
"import": "導入",
|
||||
"theme": "主題",
|
||||
"tab_size": "Tab 大小",
|
||||
"copy_file_path": "複製檔案位置",
|
||||
|
@ -162,7 +159,6 @@
|
|||
"no_empty": "不能為空",
|
||||
"change_avatar": "修改頭像請到",
|
||||
"open": "開啟",
|
||||
"pricing": "價格",
|
||||
"search_no_match": "沒有發現匹配的文件。",
|
||||
"outline": "大綱",
|
||||
"govet": "go vet",
|
||||
|
@ -174,7 +170,6 @@
|
|||
"url": "連結",
|
||||
"short_url": "短網址",
|
||||
"embeded": "嵌入",
|
||||
"git_clone": "Git Clone",
|
||||
"terms": "使用條款",
|
||||
"download": "下載",
|
||||
"decompress": "解壓縮",
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
216
main.go
216
main.go
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -38,7 +38,6 @@ import (
|
|||
"github.com/b3log/wide/notification"
|
||||
"github.com/b3log/wide/output"
|
||||
"github.com/b3log/wide/playground"
|
||||
"github.com/b3log/wide/scm/git"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
)
|
||||
|
@ -49,34 +48,26 @@ var logger *log.Logger
|
|||
// The only one init function in Wide.
|
||||
func init() {
|
||||
confPath := flag.String("conf", "conf/wide.json", "path of wide.json")
|
||||
confIP := flag.String("ip", "", "this will overwrite Wide.IP if specified")
|
||||
confPort := flag.String("port", "", "this will overwrite Wide.Port if specified")
|
||||
confData := flag.String("data", "", "path of data dir")
|
||||
confServer := flag.String("server", "", "this will overwrite Wide.Server if specified")
|
||||
confLogLevel := flag.String("log_level", "", "this will overwrite Wide.LogLevel if specified")
|
||||
confStaticServer := flag.String("static_server", "", "this will overwrite Wide.StaticServer if specified")
|
||||
confContext := flag.String("context", "", "this will overwrite Wide.Context if specified")
|
||||
confChannel := flag.String("channel", "", "this will overwrite Wide.Channel if specified")
|
||||
confStat := flag.Bool("stat", false, "whether report statistics periodically")
|
||||
confDocker := flag.Bool("docker", false, "whether run in a docker container")
|
||||
confPlayground := flag.String("playground", "", "this will overwrite Wide.Playground if specified")
|
||||
confUsersWorkspaces := flag.String("users_workspaces", "", "this will overwrite Wide.UsersWorkspaces if specified")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
log.SetLevel("warn")
|
||||
logger = log.NewLogger(os.Stdout)
|
||||
|
||||
wd := util.OS.Pwd()
|
||||
if strings.HasPrefix(wd, os.TempDir()) {
|
||||
logger.Error("Don't run Wide in OS' temp directory or with `go run`")
|
||||
|
||||
os.Exit(-1)
|
||||
}
|
||||
//wd := util.OS.Pwd()
|
||||
//if strings.HasPrefix(wd, os.TempDir()) {
|
||||
// logger.Error("Don't run Wide in OS' temp directory or with `go run`")
|
||||
//
|
||||
// os.Exit(-1)
|
||||
//}
|
||||
|
||||
i18n.Load()
|
||||
event.Load()
|
||||
conf.Load(*confPath, *confIP, *confPort, *confServer, *confLogLevel, *confStaticServer, *confContext, *confChannel,
|
||||
*confPlayground, *confDocker, *confUsersWorkspaces)
|
||||
conf.Load(*confPath, *confData, *confServer, *confLogLevel)
|
||||
|
||||
conf.FixedTimeCheckEnv()
|
||||
session.FixedTimeSave()
|
||||
|
@ -86,8 +77,7 @@ func init() {
|
|||
session.FixedTimeReport()
|
||||
}
|
||||
|
||||
logger.Debug("host ["+runtime.Version()+", "+runtime.GOOS+"_"+runtime.GOARCH+"], cross-compilation ",
|
||||
util.Go.GetCrossPlatforms())
|
||||
logger.Debug("host ["+runtime.Version()+", "+runtime.GOOS+"_"+runtime.GOARCH+"], cross-compilation ", util.Go.GetCrossPlatforms())
|
||||
}
|
||||
|
||||
// Main.
|
||||
|
@ -98,96 +88,86 @@ func main() {
|
|||
handleSignal()
|
||||
|
||||
// IDE
|
||||
http.HandleFunc(conf.Wide.Context+"/", handlerGzWrapper(indexHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/start", handlerWrapper(startHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/about", handlerWrapper(aboutHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/keyboard_shortcuts", handlerWrapper(keyboardShortcutsHandler))
|
||||
http.HandleFunc("/", handlerGzWrapper(indexHandler))
|
||||
http.HandleFunc("/start", handlerWrapper(startHandler))
|
||||
http.HandleFunc("/about", handlerWrapper(aboutHandler))
|
||||
http.HandleFunc("/keyboard_shortcuts", handlerWrapper(keyboardShortcutsHandler))
|
||||
|
||||
// static resources
|
||||
http.Handle(conf.Wide.Context+"/static/", http.StripPrefix(conf.Wide.Context+"/static/", http.FileServer(http.Dir("static"))))
|
||||
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
||||
http.Handle("/static/users/", http.StripPrefix("/static/", http.FileServer(http.Dir("C:\\Users\\DL882\\wide\\static\\"))))
|
||||
serveSingle("/favicon.ico", "./static/favicon.ico")
|
||||
|
||||
// workspaces
|
||||
for _, user := range conf.Users {
|
||||
http.Handle(conf.Wide.Context+"/workspace/"+user.Name+"/",
|
||||
http.StripPrefix(conf.Wide.Context+"/workspace/"+user.Name+"/", http.FileServer(http.Dir(user.WorkspacePath()))))
|
||||
}
|
||||
// oauth
|
||||
http.HandleFunc("/oauth/github", session.RedirectGitHubHandler)
|
||||
http.HandleFunc("/oauth/github/callback", session.GithubCallbackHandler)
|
||||
|
||||
// session
|
||||
http.HandleFunc(conf.Wide.Context+"/session/ws", handlerWrapper(session.WSHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/session/save", handlerWrapper(session.SaveContentHandler))
|
||||
http.HandleFunc("/session/ws", handlerWrapper(session.WSHandler))
|
||||
http.HandleFunc("/session/save", handlerWrapper(session.SaveContentHandler))
|
||||
|
||||
// run
|
||||
http.HandleFunc(conf.Wide.Context+"/build", handlerWrapper(output.BuildHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/run", handlerWrapper(output.RunHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/stop", handlerWrapper(output.StopHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/go/test", handlerWrapper(output.GoTestHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/go/vet", handlerWrapper(output.GoVetHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/go/get", handlerWrapper(output.GoGetHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/go/install", handlerWrapper(output.GoInstallHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/output/ws", handlerWrapper(output.WSHandler))
|
||||
http.HandleFunc("/build", handlerWrapper(output.BuildHandler))
|
||||
http.HandleFunc("/run", handlerWrapper(output.RunHandler))
|
||||
http.HandleFunc("/stop", handlerWrapper(output.StopHandler))
|
||||
http.HandleFunc("/go/test", handlerWrapper(output.GoTestHandler))
|
||||
http.HandleFunc("/go/vet", handlerWrapper(output.GoVetHandler))
|
||||
http.HandleFunc("/go/get", handlerWrapper(output.GoGetHandler))
|
||||
http.HandleFunc("/go/install", handlerWrapper(output.GoInstallHandler))
|
||||
http.HandleFunc("/output/ws", handlerWrapper(output.WSHandler))
|
||||
|
||||
// cross-compilation
|
||||
http.HandleFunc(conf.Wide.Context+"/cross", handlerWrapper(output.CrossCompilationHandler))
|
||||
http.HandleFunc("/cross", handlerWrapper(output.CrossCompilationHandler))
|
||||
|
||||
// file tree
|
||||
http.HandleFunc(conf.Wide.Context+"/files", handlerWrapper(file.GetFilesHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/file/refresh", handlerWrapper(file.RefreshDirectoryHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/file", handlerWrapper(file.GetFileHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/file/save", handlerWrapper(file.SaveFileHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/file/new", handlerWrapper(file.NewFileHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/file/remove", handlerWrapper(file.RemoveFileHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/file/rename", handlerWrapper(file.RenameFileHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/file/search/text", handlerWrapper(file.SearchTextHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/file/find/name", handlerWrapper(file.FindHandler))
|
||||
http.HandleFunc("/files", handlerWrapper(file.GetFilesHandler))
|
||||
http.HandleFunc("/file/refresh", handlerWrapper(file.RefreshDirectoryHandler))
|
||||
http.HandleFunc("/file", handlerWrapper(file.GetFileHandler))
|
||||
http.HandleFunc("/file/save", handlerWrapper(file.SaveFileHandler))
|
||||
http.HandleFunc("/file/new", handlerWrapper(file.NewFileHandler))
|
||||
http.HandleFunc("/file/remove", handlerWrapper(file.RemoveFileHandler))
|
||||
http.HandleFunc("/file/rename", handlerWrapper(file.RenameFileHandler))
|
||||
http.HandleFunc("/file/search/text", handlerWrapper(file.SearchTextHandler))
|
||||
http.HandleFunc("/file/find/name", handlerWrapper(file.FindHandler))
|
||||
|
||||
// outline
|
||||
http.HandleFunc(conf.Wide.Context+"/outline", handlerWrapper(file.GetOutlineHandler))
|
||||
http.HandleFunc("/outline", handlerWrapper(file.GetOutlineHandler))
|
||||
|
||||
// file export/import
|
||||
http.HandleFunc(conf.Wide.Context+"/file/zip/new", handlerWrapper(file.CreateZipHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/file/zip", handlerWrapper(file.GetZipHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/file/upload", handlerWrapper(file.UploadHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/file/decompress", handlerWrapper(file.DecompressHandler))
|
||||
http.HandleFunc("/file/zip/new", handlerWrapper(file.CreateZipHandler))
|
||||
http.HandleFunc("/file/zip", handlerWrapper(file.GetZipHandler))
|
||||
http.HandleFunc("/file/decompress", handlerWrapper(file.DecompressHandler))
|
||||
|
||||
// editor
|
||||
http.HandleFunc(conf.Wide.Context+"/editor/ws", handlerWrapper(editor.WSHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/go/fmt", handlerWrapper(editor.GoFmtHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/autocomplete", handlerWrapper(editor.AutocompleteHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/exprinfo", handlerWrapper(editor.GetExprInfoHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/find/decl", handlerWrapper(editor.FindDeclarationHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/find/usages", handlerWrapper(editor.FindUsagesHandler))
|
||||
|
||||
// shell
|
||||
// http.HandleFunc(conf.Wide.Context+"/shell/ws", handlerWrapper(shell.WSHandler))
|
||||
// http.HandleFunc(conf.Wide.Context+"/shell", handlerWrapper(shell.IndexHandler))
|
||||
http.HandleFunc("/editor/ws", handlerWrapper(editor.WSHandler))
|
||||
http.HandleFunc("/go/fmt", handlerWrapper(editor.GoFmtHandler))
|
||||
http.HandleFunc("/autocomplete", handlerWrapper(editor.AutocompleteHandler))
|
||||
http.HandleFunc("/exprinfo", handlerWrapper(editor.GetExprInfoHandler))
|
||||
http.HandleFunc("/find/decl", handlerWrapper(editor.FindDeclarationHandler))
|
||||
http.HandleFunc("/find/usages", handlerWrapper(editor.FindUsagesHandler))
|
||||
|
||||
// notification
|
||||
http.HandleFunc(conf.Wide.Context+"/notification/ws", handlerWrapper(notification.WSHandler))
|
||||
http.HandleFunc("/notification/ws", handlerWrapper(notification.WSHandler))
|
||||
|
||||
// user
|
||||
http.HandleFunc(conf.Wide.Context+"/login", handlerWrapper(session.LoginHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/logout", handlerWrapper(session.LogoutHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/signup", handlerWrapper(session.SignUpUserHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/preference", handlerWrapper(session.PreferenceHandler))
|
||||
http.HandleFunc("/logout", handlerWrapper(session.LogoutHandler))
|
||||
http.HandleFunc("/preference", handlerWrapper(session.PreferenceHandler))
|
||||
|
||||
// playground
|
||||
http.HandleFunc(conf.Wide.Context+"/playground", handlerWrapper(playground.IndexHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/playground/", handlerWrapper(playground.IndexHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/playground/ws", handlerWrapper(playground.WSHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/playground/save", handlerWrapper(playground.SaveHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/playground/short-url", handlerWrapper(playground.ShortURLHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/playground/build", handlerWrapper(playground.BuildHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/playground/run", handlerWrapper(playground.RunHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/playground/stop", handlerWrapper(playground.StopHandler))
|
||||
http.HandleFunc(conf.Wide.Context+"/playground/autocomplete", handlerWrapper(playground.AutocompleteHandler))
|
||||
http.HandleFunc("/playground", handlerWrapper(playground.IndexHandler))
|
||||
http.HandleFunc("/playground/", handlerWrapper(playground.IndexHandler))
|
||||
http.HandleFunc("/playground/ws", handlerWrapper(playground.WSHandler))
|
||||
http.HandleFunc("/playground/save", handlerWrapper(playground.SaveHandler))
|
||||
http.HandleFunc("/playground/short-url", handlerWrapper(playground.ShortURLHandler))
|
||||
http.HandleFunc("/playground/build", handlerWrapper(playground.BuildHandler))
|
||||
http.HandleFunc("/playground/run", handlerWrapper(playground.RunHandler))
|
||||
http.HandleFunc("/playground/stop", handlerWrapper(playground.StopHandler))
|
||||
http.HandleFunc("/playground/autocomplete", handlerWrapper(playground.AutocompleteHandler))
|
||||
|
||||
// git
|
||||
http.HandleFunc(conf.Wide.Context+"/git/clone", handlerWrapper(git.CloneHandler))
|
||||
logger.Infof("Wide is running [%s]", conf.Wide.Server)
|
||||
|
||||
logger.Infof("Wide is running [%s]", conf.Wide.Server+conf.Wide.Context)
|
||||
|
||||
err := http.ListenAndServe(conf.Wide.Server, nil)
|
||||
listen := conf.Wide.Server[strings.Index(conf.Wide.Server, "://")+3:]
|
||||
err := http.ListenAndServe(listen, nil)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
|
@ -195,51 +175,46 @@ func main() {
|
|||
|
||||
// indexHandler handles request of Wide index.
|
||||
func indexHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if conf.Wide.Context+"/" != r.RequestURI {
|
||||
http.Redirect(w, r, conf.Wide.Context+"/", http.StatusFound)
|
||||
if "/" != r.RequestURI {
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Redirect(w, r, conf.Wide.Context+"/login", http.StatusFound)
|
||||
http.Redirect(w, r, "/login", http.StatusFound)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
username := httpSession.Values["username"].(string)
|
||||
if "playground" == username { // reserved user for Playground
|
||||
http.Redirect(w, r, conf.Wide.Context+"/login", http.StatusFound)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
if "playground" == uid { // reserved user for Playground
|
||||
http.Redirect(w, r, "/login", http.StatusFound)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
httpSession.Options.MaxAge = conf.Wide.HTTPSessionMaxAge
|
||||
if "" != conf.Wide.Context {
|
||||
httpSession.Options.Path = conf.Wide.Context
|
||||
}
|
||||
httpSession.Save(r, w)
|
||||
|
||||
user := conf.GetUser(username)
|
||||
user := conf.GetUser(uid)
|
||||
if nil == user {
|
||||
logger.Warnf("Not found user [%s]", username)
|
||||
|
||||
http.Redirect(w, r, conf.Wide.Context+"/login", http.StatusFound)
|
||||
http.Redirect(w, r, "/login", http.StatusFound)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
locale := user.Locale
|
||||
|
||||
wideSessions := session.WideSessions.GetByUsername(username)
|
||||
wideSessions := session.WideSessions.GetByUserId(uid)
|
||||
|
||||
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(locale), "locale": locale,
|
||||
"username": username, "sid": session.WideSessions.GenId(), "latestSessionContent": user.LatestSessionContent,
|
||||
"uid": uid, "sid": session.WideSessions.GenId(), "latestSessionContent": user.LatestSessionContent,
|
||||
"pathSeparator": conf.PathSeparator, "codeMirrorVer": conf.CodeMirrorVer,
|
||||
"user": user, "editorThemes": conf.GetEditorThemes(), "crossPlatforms": util.Go.GetCrossPlatforms()}
|
||||
|
||||
logger.Debugf("User [%s] has [%d] sessions", username, len(wideSessions))
|
||||
logger.Debugf("User [%s] has [%d] sessions", uid, len(wideSessions))
|
||||
|
||||
t, err := template.ParseFiles("views/index.html")
|
||||
if nil != err {
|
||||
|
@ -277,22 +252,19 @@ func serveSingle(pattern string, filename string) {
|
|||
|
||||
// startHandler handles request of start page.
|
||||
func startHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Redirect(w, r, conf.Wide.Context+"/login", http.StatusFound)
|
||||
http.Redirect(w, r, "/s", http.StatusFound)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
httpSession.Options.MaxAge = conf.Wide.HTTPSessionMaxAge
|
||||
if "" != conf.Wide.Context {
|
||||
httpSession.Options.Path = conf.Wide.Context
|
||||
}
|
||||
httpSession.Save(r, w)
|
||||
|
||||
username := httpSession.Values["username"].(string)
|
||||
locale := conf.GetUser(username).Locale
|
||||
userWorkspace := conf.GetUserWorkspace(username)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
locale := conf.GetUser(uid).Locale
|
||||
userWorkspace := conf.GetUserWorkspace(uid)
|
||||
|
||||
sid := r.URL.Query()["sid"][0]
|
||||
wSession := session.WideSessions.Get(sid)
|
||||
|
@ -301,7 +273,7 @@ func startHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(locale), "locale": locale,
|
||||
"username": username, "workspace": userWorkspace, "ver": conf.WideVersion, "sid": sid}
|
||||
"uid": uid, "workspace": userWorkspace, "ver": conf.WideVersion, "sid": sid}
|
||||
|
||||
t, err := template.ParseFiles("views/start.html")
|
||||
|
||||
|
@ -317,21 +289,18 @@ func startHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// keyboardShortcutsHandler handles request of keyboard shortcuts page.
|
||||
func keyboardShortcutsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Redirect(w, r, conf.Wide.Context+"/login", http.StatusFound)
|
||||
http.Redirect(w, r, "/login", http.StatusFound)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
httpSession.Options.MaxAge = conf.Wide.HTTPSessionMaxAge
|
||||
if "" != conf.Wide.Context {
|
||||
httpSession.Options.Path = conf.Wide.Context
|
||||
}
|
||||
httpSession.Save(r, w)
|
||||
|
||||
username := httpSession.Values["username"].(string)
|
||||
locale := conf.GetUser(username).Locale
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
locale := conf.GetUser(uid).Locale
|
||||
|
||||
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(locale), "locale": locale}
|
||||
|
||||
|
@ -349,21 +318,18 @@ func keyboardShortcutsHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// aboutHandle handles request of about page.
|
||||
func aboutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Redirect(w, r, conf.Wide.Context+"/login", http.StatusFound)
|
||||
http.Redirect(w, r, "/login", http.StatusFound)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
httpSession.Options.MaxAge = conf.Wide.HTTPSessionMaxAge
|
||||
if "" != conf.Wide.Context {
|
||||
httpSession.Options.Path = conf.Wide.Context
|
||||
}
|
||||
httpSession.Save(r, w)
|
||||
|
||||
username := httpSession.Values["username"].(string)
|
||||
locale := conf.GetUser(username).Locale
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
locale := conf.GetUser(uid).Locale
|
||||
|
||||
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(locale), "locale": locale,
|
||||
"ver": conf.WideVersion, "goos": runtime.GOOS, "goarch": runtime.GOARCH, "gover": runtime.Version()}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -62,9 +62,9 @@ func event2Notification(e *event.Event) {
|
|||
return
|
||||
}
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(wsChannel.Request, "wide-session")
|
||||
username := httpSession.Values["username"].(string)
|
||||
locale := conf.GetUser(username).Locale
|
||||
httpSession, _ := session.HTTPSession.Get(wsChannel.Request, session.CookieName)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
locale := conf.GetUser(uid).Locale
|
||||
|
||||
var notification *Notification
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -38,14 +38,14 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
user := conf.GetUser(username)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
user := conf.GetUser(uid)
|
||||
locale := user.Locale
|
||||
|
||||
var args map[string]interface{}
|
||||
|
@ -61,7 +61,7 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
filePath := args["file"].(string)
|
||||
|
||||
if util.Go.IsAPI(filePath) || !session.CanAccess(username, filePath) {
|
||||
if util.Go.IsAPI(filePath) || !session.CanAccess(uid, filePath) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -95,13 +95,13 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
goBuildArgs := []string{}
|
||||
goBuildArgs = append(goBuildArgs, "build")
|
||||
goBuildArgs = append(goBuildArgs, "build", "-i")
|
||||
goBuildArgs = append(goBuildArgs, user.BuildArgs(runtime.GOOS)...)
|
||||
|
||||
cmd := exec.Command("go", goBuildArgs...)
|
||||
cmd.Dir = curDir
|
||||
|
||||
setCmdEnv(cmd, username)
|
||||
setCmdEnv(cmd, uid)
|
||||
|
||||
executable := filepath.Base(curDir) + suffix
|
||||
executable = filepath.Join(curDir, executable)
|
||||
|
@ -155,8 +155,6 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// logger.Debugf("User [%s, %s] is building [id=%d, dir=%s]", username, sid, runningId, curDir)
|
||||
|
||||
channelRet["cmd"] = "build"
|
||||
channelRet["executable"] = executable
|
||||
|
||||
|
@ -188,6 +186,7 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
err = wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -196,7 +195,7 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}()
|
||||
|
||||
errReader := bufio.NewReader(stderr)
|
||||
lines := []string{}
|
||||
var lines []string
|
||||
for {
|
||||
wsChannel := session.OutputWS[sid]
|
||||
if nil == wsChannel {
|
||||
|
@ -232,20 +231,6 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
if nil == cmd.Wait() {
|
||||
channelRet["nextCmd"] = args["nextCmd"]
|
||||
channelRet["output"] = "<span class='build-succ'>" + i18n.Get(locale, "build-succ").(string) + "</span>\n"
|
||||
|
||||
go func() { // go install, for subsequent gocode lib-path
|
||||
defer util.Recover()
|
||||
|
||||
cmd := exec.Command("go", "install")
|
||||
cmd.Dir = curDir
|
||||
|
||||
setCmdEnv(cmd, username)
|
||||
|
||||
out, _ := cmd.CombinedOutput()
|
||||
if len(out) > 0 {
|
||||
logger.Warn(string(out))
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
channelRet["output"] = "<span class='build-error'>" + i18n.Get(locale, "build-error").(string) + "</span>\n"
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -37,14 +37,14 @@ func CrossCompilationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
locale := conf.GetUser(username).Locale
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
locale := conf.GetUser(uid).Locale
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
|
@ -58,7 +58,7 @@ func CrossCompilationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sid := args["sid"].(string)
|
||||
filePath := args["path"].(string)
|
||||
|
||||
if util.Go.IsAPI(filePath) || !session.CanAccess(username, filePath) {
|
||||
if util.Go.IsAPI(filePath) || !session.CanAccess(uid, filePath) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -75,7 +75,7 @@ func CrossCompilationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
suffix = ".exe"
|
||||
}
|
||||
|
||||
user := conf.GetUser(username)
|
||||
user := conf.GetUser(uid)
|
||||
goBuildArgs := []string{}
|
||||
goBuildArgs = append(goBuildArgs, "build")
|
||||
goBuildArgs = append(goBuildArgs, user.BuildArgs(goos)...)
|
||||
|
@ -83,7 +83,7 @@ func CrossCompilationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
cmd := exec.Command("go", goBuildArgs...)
|
||||
cmd.Dir = curDir
|
||||
|
||||
setCmdEnv(cmd, username)
|
||||
setCmdEnv(cmd, uid)
|
||||
|
||||
for i, env := range cmd.Env {
|
||||
if strings.HasPrefix(env, "GOOS=") {
|
||||
|
@ -155,8 +155,6 @@ func CrossCompilationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
defer util.Recover()
|
||||
defer cmd.Wait()
|
||||
|
||||
// logger.Debugf("User [%s, %s] is building [id=%d, dir=%s]", username, sid, runningId, curDir)
|
||||
|
||||
// read all
|
||||
buf, _ := ioutil.ReadAll(reader)
|
||||
|
||||
|
@ -235,8 +233,6 @@ func CrossCompilationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if nil != session.OutputWS[sid] {
|
||||
// logger.Debugf("User [%s, %s] 's build [id=%d, dir=%s] has done", username, sid, runningId, curDir)
|
||||
|
||||
wsChannel := session.OutputWS[sid]
|
||||
err := wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -35,14 +35,14 @@ func GoGetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
locale := conf.GetUser(username).Locale
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
locale := conf.GetUser(uid).Locale
|
||||
|
||||
var args map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
|
@ -60,7 +60,7 @@ func GoGetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
cmd := exec.Command("go", "get")
|
||||
cmd.Dir = curDir
|
||||
|
||||
setCmdEnv(cmd, username)
|
||||
setCmdEnv(cmd, uid)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if nil != err {
|
||||
|
@ -114,7 +114,7 @@ func GoGetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
defer util.Recover()
|
||||
defer cmd.Wait()
|
||||
|
||||
logger.Debugf("User [%s, %s] is running [go get] [runningId=%d]", username, sid, runningId)
|
||||
logger.Debugf("User [%s, %s] is running [go get] [runningId=%d]", uid, sid, runningId)
|
||||
|
||||
channelRet := map[string]interface{}{}
|
||||
channelRet["cmd"] = "go get"
|
||||
|
@ -123,11 +123,11 @@ func GoGetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
buf, _ := ioutil.ReadAll(reader)
|
||||
|
||||
if 0 != len(buf) {
|
||||
logger.Debugf("User [%s, %s] 's [go get] [runningId=%d] has done (with error)", username, sid, runningId)
|
||||
logger.Debugf("User [%s, %s] 's [go get] [runningId=%d] has done (with error)", uid, sid, runningId)
|
||||
|
||||
channelRet["output"] = "<span class='get-error'>" + i18n.Get(locale, "get-error").(string) + "</span>\n" + string(buf)
|
||||
} else {
|
||||
logger.Debugf("User [%s, %s] 's running [go get] [runningId=%d] has done", username, sid, runningId)
|
||||
logger.Debugf("User [%s, %s] 's running [go get] [runningId=%d] has done", uid, sid, runningId)
|
||||
|
||||
channelRet["output"] = "<span class='get-succ'>" + i18n.Get(locale, "get-succ").(string) + "</span>\n"
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -37,14 +37,14 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) {
|
|||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
locale := conf.GetUser(username).Locale
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
locale := conf.GetUser(uid).Locale
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
|
@ -63,7 +63,7 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) {
|
|||
cmd := exec.Command("go", "install")
|
||||
cmd.Dir = curDir
|
||||
|
||||
setCmdEnv(cmd, username)
|
||||
setCmdEnv(cmd, uid)
|
||||
|
||||
logger.Debugf("go install %s", curDir)
|
||||
|
||||
|
@ -119,7 +119,7 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) {
|
|||
defer util.Recover()
|
||||
defer cmd.Wait()
|
||||
|
||||
logger.Debugf("User [%s, %s] is running [go install] [id=%d, dir=%s]", username, sid, runningId, curDir)
|
||||
logger.Debugf("User [%s, %s] is running [go install] [id=%d, dir=%s]", uid, sid, runningId, curDir)
|
||||
|
||||
// read all
|
||||
buf, _ := ioutil.ReadAll(reader)
|
||||
|
@ -183,7 +183,7 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if nil != session.OutputWS[sid] {
|
||||
logger.Debugf("User [%s, %s] 's running [go install] [id=%d, dir=%s] has done", username, sid, runningId, curDir)
|
||||
logger.Debugf("User [%s, %s] 's running [go install] [id=%d, dir=%s] has done", uid, sid, runningId, curDir)
|
||||
|
||||
wsChannel := session.OutputWS[sid]
|
||||
err := wsChannel.WriteJSON(&channelRet)
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !linux
|
||||
|
||||
package output
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func SetNamespace(cmd *exec.Cmd) {
|
||||
// do nothing
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package output
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func SetNamespace(cmd *exec.Cmd) {
|
||||
// XXX: keep move with Go 1.4 and later's
|
||||
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
//cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWUSER | syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWIPC | syscall.CLONE_NEWNET
|
||||
cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWUSER /*| syscall.CLONE_NEWNS*/ | syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWIPC /*| syscall.CLONE_NEWNET*/
|
||||
cmd.SysProcAttr.Credential = &syscall.Credential{
|
||||
Uid: 0,
|
||||
Gid: 0,
|
||||
}
|
||||
|
||||
cmd.SysProcAttr.UidMappings = []syscall.SysProcIDMap{{ContainerID: 0, HostID: 1001, Size: 1}}
|
||||
cmd.SysProcAttr.GidMappings = []syscall.SysProcIDMap{{ContainerID: 0, HostID: 1001, Size: 1}}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -104,18 +104,27 @@ func parsePath(curDir, outputLine string) string {
|
|||
return tagStart + text + tagEnd + msgPart
|
||||
}
|
||||
|
||||
func setCmdEnv(cmd *exec.Cmd, username string) {
|
||||
userWorkspace := conf.GetUserWorkspace(username)
|
||||
func setCmdEnv(cmd *exec.Cmd, uid string) {
|
||||
userWorkspace := conf.GetUserWorkspace(uid)
|
||||
cache, err := os.UserCacheDir()
|
||||
if nil != err {
|
||||
logger.Warnf("Get user cache dir failed [" + err.Error() + "]")
|
||||
cache = os.TempDir()
|
||||
}
|
||||
|
||||
cmd.Env = append(cmd.Env,
|
||||
"GOPATH="+userWorkspace,
|
||||
"GOOS="+runtime.GOOS,
|
||||
"GOARCH="+runtime.GOARCH,
|
||||
"GOROOT="+runtime.GOROOT(),
|
||||
"GOCACHE="+cache,
|
||||
"PATH="+os.Getenv("PATH"))
|
||||
|
||||
if util.OS.IsWindows() {
|
||||
// FIXME: for some weird issues on Windows, such as: The requested service provider could not be loaded or initialized.
|
||||
cmd.Env = append(cmd.Env, os.Environ()...)
|
||||
} else {
|
||||
// 编译链接时找不到依赖的动态库 https://github.com/b3log/wide/issues/352
|
||||
cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+os.Getenv("LD_LIBRARY_PATH"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -86,7 +86,7 @@ func (procs *procs) Kill(wSession *session.WideSession, pid int) {
|
|||
for i, p := range userProcesses {
|
||||
if p.Pid == pid {
|
||||
if err := p.Kill(); nil != err {
|
||||
logger.Errorf("Kill a process [pid=%d] of user [%s, %s] failed [error=%v]", pid, wSession.Username, sid, err)
|
||||
logger.Errorf("Kill a process [pid=%d] of user [%s, %s] failed [error=%v]", pid, wSession.UserId, sid, err)
|
||||
} else {
|
||||
var newProcesses []*os.Process
|
||||
|
||||
|
@ -96,7 +96,7 @@ func (procs *procs) Kill(wSession *session.WideSession, pid int) {
|
|||
// bind process with wide session
|
||||
wSession.SetProcesses(newProcesses)
|
||||
|
||||
logger.Debugf("Killed a process [pid=%d] of user [%s, %s]", pid, wSession.Username, sid)
|
||||
logger.Debugf("Killed a process [pid=%d] of user [%s, %s]", pid, wSession.UserId, sid)
|
||||
}
|
||||
|
||||
return
|
||||
|
|
195
output/run.go
195
output/run.go
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -22,24 +22,12 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
)
|
||||
|
||||
const (
|
||||
outputBufMax = 1024 // 1024 string(rune)
|
||||
outputTimeout = 100 // 100ms
|
||||
outputCountMax = 30 // 30 reads
|
||||
)
|
||||
|
||||
type outputBuf struct {
|
||||
content string
|
||||
millisecond int64
|
||||
}
|
||||
|
||||
// RunHandler handles request of executing a binary file.
|
||||
func RunHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
|
@ -59,13 +47,15 @@ func RunHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
filePath := args["executable"].(string)
|
||||
curDir := filepath.Dir(filePath)
|
||||
|
||||
cmd := exec.Command(filePath)
|
||||
cmd.Dir = curDir
|
||||
|
||||
var cmd *exec.Cmd
|
||||
if conf.Docker {
|
||||
SetNamespace(cmd)
|
||||
fileName := filepath.Base(filePath)
|
||||
cmd = exec.Command("timeout", "5", "docker", "run", "--rm", "-v", filePath+":/"+fileName, conf.DockerImageGo, "/"+fileName)
|
||||
} else {
|
||||
cmd = exec.Command(filePath)
|
||||
curDir := filepath.Dir(filePath)
|
||||
cmd.Dir = curDir
|
||||
}
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
|
@ -87,24 +77,13 @@ func RunHandler(w http.ResponseWriter, r *http.Request) {
|
|||
logger.Error(err)
|
||||
result.Succ = false
|
||||
}
|
||||
|
||||
wsChannel := session.OutputWS[sid]
|
||||
|
||||
channelRet := map[string]interface{}{}
|
||||
|
||||
if !result.Succ {
|
||||
if nil != wsChannel {
|
||||
channelRet["cmd"] = "run-done"
|
||||
channelRet["output"] = ""
|
||||
|
||||
err := wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
return
|
||||
}
|
||||
|
||||
wsChannel.Refresh()
|
||||
}
|
||||
channelRet["cmd"] = "run-done"
|
||||
channelRet["output"] = ""
|
||||
wsChannel.WriteJSON(&channelRet)
|
||||
wsChannel.Refresh()
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -114,148 +93,76 @@ func RunHandler(w http.ResponseWriter, r *http.Request) {
|
|||
// add the process to user's process set
|
||||
Processes.Add(wSession, cmd.Process)
|
||||
|
||||
go func(runningId int) {
|
||||
defer util.Recover()
|
||||
defer cmd.Wait()
|
||||
|
||||
logger.Debugf("User [%s, %s] is running [id=%d, file=%s]", wSession.Username, sid, runningId, filePath)
|
||||
|
||||
// push once for front-end to get the 'run' state and pid
|
||||
// push once for front-end to get the 'run' state and pid
|
||||
if nil != wsChannel {
|
||||
channelRet["cmd"] = "run"
|
||||
channelRet["output"] = ""
|
||||
if nil != wsChannel {
|
||||
channelRet["cmd"] = "run"
|
||||
channelRet["output"] = ""
|
||||
err := wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
return
|
||||
}
|
||||
|
||||
wsChannel.WriteJSON(&channelRet)
|
||||
wsChannel.Refresh()
|
||||
}
|
||||
}
|
||||
|
||||
go func(runningId int) {
|
||||
defer util.Recover()
|
||||
|
||||
logger.Debugf("User [%s, %s] is running [id=%d, file=%s]", wSession.UserId, sid, runningId, filePath)
|
||||
|
||||
go func() {
|
||||
defer util.Recover()
|
||||
|
||||
buf := outputBuf{}
|
||||
count := 0
|
||||
|
||||
for {
|
||||
wsChannel := session.OutputWS[sid]
|
||||
if nil == wsChannel {
|
||||
break
|
||||
}
|
||||
|
||||
r, _, err := outReader.ReadRune()
|
||||
count++
|
||||
|
||||
if nil != err {
|
||||
// remove the exited process from user's process set
|
||||
Processes.Remove(wSession, cmd.Process)
|
||||
|
||||
logger.Debugf("User [%s, %s] 's running [id=%d, file=%s] has done [stdout %v], ",
|
||||
wSession.Username, sid, runningId, filePath, err)
|
||||
|
||||
channelRet["cmd"] = "run-done"
|
||||
channelRet["output"] = buf.content
|
||||
err := wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
break
|
||||
}
|
||||
|
||||
wsChannel.Refresh()
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
oneRuneStr := string(r)
|
||||
oneRuneStr = strings.Replace(oneRuneStr, "<", "<", -1)
|
||||
oneRuneStr = strings.Replace(oneRuneStr, ">", ">", -1)
|
||||
|
||||
buf.content += oneRuneStr
|
||||
|
||||
now := time.Now().UnixNano() / int64(time.Millisecond)
|
||||
|
||||
if 0 == buf.millisecond {
|
||||
buf.millisecond = now
|
||||
}
|
||||
|
||||
flood := count > outputCountMax
|
||||
|
||||
if "\n" == oneRuneStr && !flood {
|
||||
channelRet["cmd"] = "run"
|
||||
channelRet["output"] = buf.content
|
||||
|
||||
buf = outputBuf{} // a new buffer
|
||||
count = 0 // clear count
|
||||
|
||||
err = wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
break
|
||||
}
|
||||
|
||||
channelRet["cmd"] = "run"
|
||||
channelRet["output"] = oneRuneStr
|
||||
wsChannel := session.OutputWS[sid]
|
||||
if nil != wsChannel {
|
||||
wsChannel.WriteJSON(&channelRet)
|
||||
wsChannel.Refresh()
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if now-outputTimeout >= buf.millisecond || len(buf.content) > outputBufMax {
|
||||
channelRet["cmd"] = "run"
|
||||
channelRet["output"] = buf.content
|
||||
|
||||
buf = outputBuf{} // a new buffer
|
||||
count = 0 // clear count
|
||||
|
||||
err = wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
break
|
||||
}
|
||||
|
||||
wsChannel.Refresh()
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
buf := outputBuf{}
|
||||
for {
|
||||
r, _, err := errReader.ReadRune()
|
||||
|
||||
wsChannel := session.OutputWS[sid]
|
||||
if nil != err || nil == wsChannel {
|
||||
if nil != err {
|
||||
break
|
||||
}
|
||||
|
||||
oneRuneStr := string(r)
|
||||
oneRuneStr = strings.Replace(oneRuneStr, "<", "<", -1)
|
||||
oneRuneStr = strings.Replace(oneRuneStr, ">", ">", -1)
|
||||
|
||||
buf.content += oneRuneStr
|
||||
|
||||
now := time.Now().UnixNano() / int64(time.Millisecond)
|
||||
|
||||
if 0 == buf.millisecond {
|
||||
buf.millisecond = now
|
||||
}
|
||||
|
||||
if now-outputTimeout >= buf.millisecond || len(buf.content) > outputBufMax || oneRuneStr == "\n" {
|
||||
channelRet["cmd"] = "run"
|
||||
channelRet["output"] = "<span class='stderr'>" + buf.content + "</span>"
|
||||
|
||||
buf = outputBuf{} // a new buffer
|
||||
|
||||
err = wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
break
|
||||
}
|
||||
|
||||
channelRet["cmd"] = "run"
|
||||
channelRet["output"] = "<span class='stderr'>" + oneRuneStr + "</span>"
|
||||
wsChannel := session.OutputWS[sid]
|
||||
if nil != wsChannel {
|
||||
wsChannel.WriteJSON(&channelRet)
|
||||
wsChannel.Refresh()
|
||||
}
|
||||
}
|
||||
|
||||
cmd.Wait()
|
||||
|
||||
// remove the exited process from user's process set
|
||||
Processes.Remove(wSession, cmd.Process)
|
||||
|
||||
channelRet["cmd"] = "run-done"
|
||||
if 124 == cmd.ProcessState.ExitCode() {
|
||||
channelRet["output"] = "<span class='stderr'>run program timeout in 5s</span>\n"
|
||||
} else {
|
||||
channelRet["output"] = "\n<span class='stderr'>run program complete</span>\n"
|
||||
}
|
||||
if nil != wsChannel {
|
||||
wsChannel.WriteJSON(&channelRet)
|
||||
wsChannel.Refresh()
|
||||
}
|
||||
}(rand.Int())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -35,14 +35,14 @@ func GoTestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
locale := conf.GetUser(username).Locale
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
locale := conf.GetUser(uid).Locale
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
|
@ -61,7 +61,7 @@ func GoTestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
cmd := exec.Command("go", "test", "-v")
|
||||
cmd.Dir = curDir
|
||||
|
||||
setCmdEnv(cmd, username)
|
||||
setCmdEnv(cmd, uid)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if nil != err {
|
||||
|
@ -114,7 +114,7 @@ func GoTestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
go func(runningId int) {
|
||||
defer util.Recover()
|
||||
|
||||
logger.Debugf("User [%s, %s] is running [go test] [runningId=%d]", username, sid, runningId)
|
||||
logger.Debugf("User [%s, %s] is running [go test] [runningId=%d]", uid, sid, runningId)
|
||||
|
||||
channelRet := map[string]interface{}{}
|
||||
channelRet["cmd"] = "go test"
|
||||
|
@ -126,11 +126,11 @@ func GoTestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
cmd.Wait()
|
||||
|
||||
if !cmd.ProcessState.Success() {
|
||||
logger.Debugf("User [%s, %s] 's running [go test] [runningId=%d] has done (with error)", username, sid, runningId)
|
||||
logger.Debugf("User [%s, %s] 's running [go test] [runningId=%d] has done (with error)", uid, sid, runningId)
|
||||
|
||||
channelRet["output"] = "<span class='test-error'>" + i18n.Get(locale, "test-error").(string) + "</span>\n" + string(buf)
|
||||
} else {
|
||||
logger.Debugf("User [%s, %s] 's running [go test] [runningId=%d] has done", username, sid, runningId)
|
||||
logger.Debugf("User [%s, %s] 's running [go test] [runningId=%d] has done", uid, sid, runningId)
|
||||
|
||||
channelRet["output"] = "<span class='test-succ'>" + i18n.Get(locale, "test-succ").(string) + "</span>\n" + string(buf)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -35,14 +35,14 @@ func GoVetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
locale := conf.GetUser(username).Locale
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
locale := conf.GetUser(uid).Locale
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
|
@ -61,7 +61,7 @@ func GoVetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
cmd := exec.Command("go", "vet", ".")
|
||||
cmd.Dir = curDir
|
||||
|
||||
setCmdEnv(cmd, username)
|
||||
setCmdEnv(cmd, uid)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if nil != err {
|
||||
|
@ -114,7 +114,7 @@ func GoVetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
go func(runningId int) {
|
||||
defer util.Recover()
|
||||
|
||||
logger.Debugf("User [%s, %s] is running [go vet] [runningId=%d]", username, sid, runningId)
|
||||
logger.Debugf("User [%s, %s] is running [go vet] [runningId=%d]", uid, sid, runningId)
|
||||
|
||||
channelRet := map[string]interface{}{}
|
||||
channelRet["cmd"] = "go vet"
|
||||
|
@ -126,11 +126,11 @@ func GoVetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
cmd.Wait()
|
||||
|
||||
if !cmd.ProcessState.Success() {
|
||||
logger.Debugf("User [%s, %s] 's running [go vet] [runningId=%d] has done (with error)", username, sid, runningId)
|
||||
logger.Debugf("User [%s, %s] 's running [go vet] [runningId=%d] has done (with error)", uid, sid, runningId)
|
||||
|
||||
channelRet["output"] = "<span class='vet-error'>" + i18n.Get(locale, "vet-error").(string) + "</span>\n" + string(buf)
|
||||
} else {
|
||||
logger.Debugf("User [%s, %s] 's running [go vet] [runningId=%d] has done", username, sid, runningId)
|
||||
logger.Debugf("User [%s, %s] 's running [go vet] [runningId=%d] has done", uid, sid, runningId)
|
||||
|
||||
channelRet["output"] = "<span class='vet-succ'>" + i18n.Get(locale, "vet-succ").(string) + "</span>\n" + string(buf)
|
||||
}
|
||||
|
|
13
package.json
13
package.json
|
@ -12,22 +12,25 @@
|
|||
},
|
||||
"license": "Apache License",
|
||||
"private": true,
|
||||
"author": "Daniel <dl882509@gmail.com> (http://88250.b3log.org) & Vanessa <lly219@gmail.com> (http://vanessa.b3log.org)",
|
||||
"author": "Daniel <d@b3log.org> (http://88250.b3log.org) & Vanessa <v@b3log.org> (http://vanessa.b3log.org)",
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Daniel",
|
||||
"email": "dl88250@gmail.com"
|
||||
"email": "d@b3log.org"
|
||||
},
|
||||
{
|
||||
"name": "Vanessa",
|
||||
"email": "lly219@gmail.com"
|
||||
"email": "v@b3log.org"
|
||||
}
|
||||
],
|
||||
"scripts": {
|
||||
"build": "gulp"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gulp": "^3.9.1",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-minify-css": "^1.2.4",
|
||||
"gulp-sourcemaps": "^2.6.0",
|
||||
"gulp-uglify": "^2.1.2"
|
||||
"gulp-uglify": "^3.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -37,7 +37,7 @@ func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
session, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
session, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if session.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -32,7 +32,7 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
|
@ -48,7 +48,7 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
fileName := args["fileName"].(string)
|
||||
filePath := filepath.Clean(conf.Wide.Playground + "/" + fileName)
|
||||
filePath := filepath.Clean(conf.Wide.Data + "/playground/" + fileName)
|
||||
|
||||
suffix := ""
|
||||
if util.OS.IsWindows() {
|
||||
|
@ -58,7 +58,7 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
data := map[string]interface{}{}
|
||||
result.Data = &data
|
||||
|
||||
executable := filepath.Clean(conf.Wide.Playground + "/" + strings.Replace(fileName, ".go", suffix, -1))
|
||||
executable := filepath.Clean(conf.Wide.Data + "/playground/" + strings.Replace(fileName, ".go", suffix, -1))
|
||||
|
||||
cmd := exec.Command("go", "build", "-o", executable, filePath)
|
||||
out, err := cmd.CombinedOutput()
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -35,7 +35,7 @@ func SaveHandler(w http.ResponseWriter, r *http.Request) {
|
|||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
session, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
session, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if session.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
|
@ -85,7 +85,7 @@ func SaveHandler(w http.ResponseWriter, r *http.Request) {
|
|||
data["fileName"] = fileName
|
||||
|
||||
// Step3. write file
|
||||
filePath := filepath.Clean(conf.Wide.Playground + "/" + fileName)
|
||||
filePath := filepath.Clean(conf.Wide.Data + "/playground" + fileName)
|
||||
fout, err := os.Create(filePath)
|
||||
fout.WriteString(code)
|
||||
if err := fout.Close(); nil != err {
|
||||
|
@ -101,7 +101,7 @@ func ShortURLHandler(w http.ResponseWriter, r *http.Request) {
|
|||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
session, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
session, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if session.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -40,19 +40,16 @@ var logger = log.NewLogger(os.Stdout)
|
|||
// IndexHandler handles request of Playground index.
|
||||
func IndexHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// create a HTTP session
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
httpSession.Values["id"] = strconv.Itoa(rand.Int())
|
||||
httpSession.Values["username"] = "playground"
|
||||
httpSession.Values["uid"] = "playground"
|
||||
}
|
||||
|
||||
httpSession.Options.MaxAge = conf.Wide.HTTPSessionMaxAge
|
||||
if "" != conf.Wide.Context {
|
||||
httpSession.Options.Path = conf.Wide.Context
|
||||
}
|
||||
httpSession.Save(r, w)
|
||||
|
||||
username := httpSession.Values["username"].(string)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
locale := conf.Wide.Locale
|
||||
|
||||
|
@ -62,7 +59,7 @@ func IndexHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if strings.HasSuffix(r.URL.Path, ".go") {
|
||||
fileNameArg := r.URL.Path[len("/playground/"):]
|
||||
filePath := filepath.Clean(conf.Wide.Playground + "/" + fileNameArg)
|
||||
filePath := filepath.Clean(conf.Wide.Data+ "/playground" + fileNameArg)
|
||||
|
||||
bytes, err := ioutil.ReadFile(filePath)
|
||||
if nil != err {
|
||||
|
@ -92,9 +89,9 @@ func IndexHandler(w http.ResponseWriter, r *http.Request) {
|
|||
"code": template.HTML(code), "ver": conf.WideVersion, "year": time.Now().Year(),
|
||||
"embed": embed, "disqus": disqus, "fileName": fileName}
|
||||
|
||||
wideSessions := session.WideSessions.GetByUsername(username)
|
||||
wideSessions := session.WideSessions.GetByUserId(uid)
|
||||
|
||||
logger.Debugf("User [%s] has [%d] sessions", username, len(wideSessions))
|
||||
logger.Debugf("User [%s] has [%d] sessions", uid, len(wideSessions))
|
||||
|
||||
t, err := template.ParseFiles("views/playground/index.html")
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -20,7 +20,8 @@ import (
|
|||
"math/rand"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"time"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/output"
|
||||
|
@ -28,17 +29,6 @@ import (
|
|||
"github.com/b3log/wide/util"
|
||||
)
|
||||
|
||||
const (
|
||||
outputBufMax = 1024 // 1024 string(rune)
|
||||
outputTimeout = 100 // 100ms
|
||||
outputCountMax = 30 // 30 reads
|
||||
)
|
||||
|
||||
type outputBuf struct {
|
||||
content string
|
||||
millisecond int64
|
||||
}
|
||||
|
||||
// RunHandler handles request of executing a binary file.
|
||||
func RunHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
|
@ -59,10 +49,14 @@ func RunHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
filePath := args["executable"].(string)
|
||||
|
||||
cmd := exec.Command(filePath)
|
||||
|
||||
var cmd *exec.Cmd
|
||||
if conf.Docker {
|
||||
output.SetNamespace(cmd)
|
||||
fileName := filepath.Base(filePath)
|
||||
cmd = exec.Command("timeout", "5", "docker", "run", "--rm", "-v", filePath+":/"+fileName, conf.DockerImageGo, "/"+fileName)
|
||||
} else {
|
||||
cmd = exec.Command(filePath)
|
||||
curDir := filepath.Dir(filePath)
|
||||
cmd.Dir = curDir
|
||||
}
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
|
@ -86,22 +80,12 @@ func RunHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
wsChannel := session.PlaygroundWS[sid]
|
||||
|
||||
channelRet := map[string]interface{}{}
|
||||
|
||||
if !result.Succ {
|
||||
if nil != wsChannel {
|
||||
channelRet["cmd"] = "run-done"
|
||||
channelRet["output"] = ""
|
||||
|
||||
err := wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
return
|
||||
}
|
||||
|
||||
wsChannel.Refresh()
|
||||
}
|
||||
channelRet["cmd"] = "run-done"
|
||||
channelRet["output"] = ""
|
||||
wsChannel.WriteJSON(&channelRet)
|
||||
wsChannel.Refresh()
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -111,143 +95,74 @@ func RunHandler(w http.ResponseWriter, r *http.Request) {
|
|||
// add the process to user's process set
|
||||
output.Processes.Add(wSession, cmd.Process)
|
||||
|
||||
go func(runningId int) {
|
||||
defer util.Recover()
|
||||
defer cmd.Wait()
|
||||
|
||||
logger.Debugf("User [%s, %s] is running [id=%d, file=%s]", wSession.Username, sid, runningId, filePath)
|
||||
|
||||
// push once for front-end to get the 'run' state and pid
|
||||
// push once for front-end to get the 'run' state and pid
|
||||
if nil != wsChannel {
|
||||
channelRet["cmd"] = "run"
|
||||
channelRet["output"] = ""
|
||||
if nil != wsChannel {
|
||||
channelRet["cmd"] = "run"
|
||||
channelRet["output"] = ""
|
||||
err := wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
return
|
||||
}
|
||||
|
||||
wsChannel.WriteJSON(&channelRet)
|
||||
wsChannel.Refresh()
|
||||
}
|
||||
}
|
||||
|
||||
go func(runningId int) {
|
||||
defer util.Recover()
|
||||
|
||||
logger.Debugf("User [%s, %s] is running [id=%d, file=%s]", wSession.UserId, sid, runningId, filePath)
|
||||
|
||||
go func() {
|
||||
defer util.Recover()
|
||||
|
||||
buf := outputBuf{}
|
||||
count := 0
|
||||
|
||||
for {
|
||||
wsChannel := session.PlaygroundWS[sid]
|
||||
if nil == wsChannel {
|
||||
break
|
||||
}
|
||||
|
||||
r, _, err := outReader.ReadRune()
|
||||
count++
|
||||
|
||||
if nil != err {
|
||||
// remove the exited process from user process set
|
||||
output.Processes.Remove(wSession, cmd.Process)
|
||||
|
||||
logger.Debugf("User [%s, %s] 's running [id=%d, file=%s] has done [stdout %v], ", wSession.Username, sid, runningId, filePath, err)
|
||||
|
||||
channelRet["cmd"] = "run-done"
|
||||
channelRet["output"] = buf.content
|
||||
err := wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
break
|
||||
}
|
||||
|
||||
wsChannel.Refresh()
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
oneRuneStr := string(r)
|
||||
|
||||
buf.content += oneRuneStr
|
||||
|
||||
now := time.Now().UnixNano() / int64(time.Millisecond)
|
||||
|
||||
if 0 == buf.millisecond {
|
||||
buf.millisecond = now
|
||||
}
|
||||
|
||||
flood := count > outputCountMax
|
||||
|
||||
if "\n" == oneRuneStr && !flood {
|
||||
channelRet["cmd"] = "run"
|
||||
channelRet["output"] = buf.content
|
||||
|
||||
buf = outputBuf{} // a new buffer
|
||||
count = 0 // clear count
|
||||
|
||||
err = wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
break
|
||||
}
|
||||
|
||||
oneRuneStr = strings.Replace(oneRuneStr, "<", "<", -1)
|
||||
oneRuneStr = strings.Replace(oneRuneStr, ">", ">", -1)
|
||||
channelRet["cmd"] = "run"
|
||||
channelRet["output"] = oneRuneStr
|
||||
wsChannel := session.PlaygroundWS[sid]
|
||||
if nil != wsChannel {
|
||||
wsChannel.WriteJSON(&channelRet)
|
||||
wsChannel.Refresh()
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if now-outputTimeout >= buf.millisecond || len(buf.content) > outputBufMax {
|
||||
channelRet["cmd"] = "run"
|
||||
channelRet["output"] = buf.content
|
||||
|
||||
buf = outputBuf{} // a new buffer
|
||||
count = 0 // clear count
|
||||
|
||||
err = wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
break
|
||||
}
|
||||
|
||||
wsChannel.Refresh()
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
buf := outputBuf{}
|
||||
for {
|
||||
r, _, err := errReader.ReadRune()
|
||||
|
||||
wsChannel := session.PlaygroundWS[sid]
|
||||
if nil != err || nil == wsChannel {
|
||||
if nil != err {
|
||||
break
|
||||
}
|
||||
|
||||
oneRuneStr := string(r)
|
||||
|
||||
buf.content += oneRuneStr
|
||||
|
||||
now := time.Now().UnixNano() / int64(time.Millisecond)
|
||||
|
||||
if 0 == buf.millisecond {
|
||||
buf.millisecond = now
|
||||
}
|
||||
|
||||
if now-outputTimeout >= buf.millisecond || len(buf.content) > outputBufMax || oneRuneStr == "\n" {
|
||||
channelRet["cmd"] = "run"
|
||||
channelRet["output"] = buf.content
|
||||
|
||||
buf = outputBuf{} // a new buffer
|
||||
|
||||
err = wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
break
|
||||
}
|
||||
|
||||
oneRuneStr = strings.Replace(oneRuneStr, "<", "<", -1)
|
||||
oneRuneStr = strings.Replace(oneRuneStr, ">", ">", -1)
|
||||
channelRet["cmd"] = "run"
|
||||
channelRet["output"] = oneRuneStr
|
||||
wsChannel := session.PlaygroundWS[sid]
|
||||
if nil != wsChannel {
|
||||
wsChannel.WriteJSON(&channelRet)
|
||||
wsChannel.Refresh()
|
||||
}
|
||||
}
|
||||
|
||||
cmd.Wait()
|
||||
|
||||
// remove the exited process from user's process set
|
||||
output.Processes.Remove(wSession, cmd.Process)
|
||||
|
||||
channelRet["cmd"] = "run-done"
|
||||
if 124 == cmd.ProcessState.ExitCode() {
|
||||
channelRet["output"] = "\nrun program timeout in 5s\n"
|
||||
}
|
||||
if nil != wsChannel {
|
||||
wsChannel.WriteJSON(&channelRet)
|
||||
wsChannel.Refresh()
|
||||
}
|
||||
}(rand.Int())
|
||||
}
|
||||
|
||||
|
|
146
scm/git/clone.go
146
scm/git/clone.go
|
@ -1,146 +0,0 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package git
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/i18n"
|
||||
"github.com/b3log/wide/log"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
)
|
||||
|
||||
// Logger.
|
||||
var logger = log.NewLogger(os.Stdout)
|
||||
|
||||
// Clone handles request of git clone.
|
||||
func CloneHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
locale := conf.GetUser(username).Locale
|
||||
|
||||
var args map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
sid := args["sid"].(string)
|
||||
path := args["path"].(string)
|
||||
repository := args["repository"].(string)
|
||||
|
||||
cmd := exec.Command("git", "clone", repository)
|
||||
cmd.Dir = path
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !result.Succ {
|
||||
return
|
||||
}
|
||||
|
||||
channelRet := map[string]interface{}{}
|
||||
|
||||
if nil != session.OutputWS[sid] {
|
||||
// display "START [git clone]" in front-end browser
|
||||
|
||||
channelRet["output"] = "<span class='start-get'>" + i18n.Get(locale, "start-git_clone").(string) + "</span>\n"
|
||||
channelRet["cmd"] = "start-git_clone"
|
||||
|
||||
wsChannel := session.OutputWS[sid]
|
||||
|
||||
err := wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
return
|
||||
}
|
||||
|
||||
wsChannel.Refresh()
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(io.MultiReader(stdout, stderr))
|
||||
|
||||
if err := cmd.Start(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
go func(runningId int) {
|
||||
defer util.Recover()
|
||||
defer cmd.Wait()
|
||||
|
||||
logger.Debugf("User [%s, %s] is running [git clone] [runningId=%d]", username, sid, runningId)
|
||||
|
||||
channelRet := map[string]interface{}{}
|
||||
channelRet["cmd"] = "git clone"
|
||||
|
||||
// read all
|
||||
buf, err := ioutil.ReadAll(reader)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
|
||||
// TODO: handle clone error
|
||||
}
|
||||
|
||||
logger.Debugf("User [%s, %s] 's running [git clone] [runningId=%d] has done: %s", username, sid, runningId, string(buf))
|
||||
|
||||
channelRet["output"] = "<span class='get-succ'>" + i18n.Get(locale, "git_clone-done").(string) + "</span>\n"
|
||||
|
||||
if nil != session.OutputWS[sid] {
|
||||
wsChannel := session.OutputWS[sid]
|
||||
|
||||
err := wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
}
|
||||
|
||||
wsChannel.Refresh()
|
||||
}
|
||||
}(rand.Int())
|
||||
}
|
|
@ -0,0 +1,272 @@
|
|||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package session
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/parnurzeal/gorequest"
|
||||
)
|
||||
|
||||
var states = map[string]string{}
|
||||
|
||||
// RedirectGitHubHandler redirects to GitHub auth page.
|
||||
func RedirectGitHubHandler(w http.ResponseWriter, r *http.Request) {
|
||||
requestResult := util.NewResult()
|
||||
_, _, errs := gorequest.New().TLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
|
||||
Get("https://hacpai.com/oauth/wide/client").
|
||||
Set("user-agent", conf.UserAgent).Timeout(10 * time.Second).EndStruct(requestResult)
|
||||
if nil != errs {
|
||||
logger.Errorf("Get oauth client id failed: %+v", errs)
|
||||
http.Error(w, "Get oauth info failed", http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
}
|
||||
if 0 != requestResult.Code {
|
||||
logger.Errorf("get oauth client id failed [code=%d, msg=%s]", requestResult.Code, requestResult.Msg)
|
||||
http.Error(w, "Get oauth info failed", http.StatusNotFound)
|
||||
|
||||
return
|
||||
}
|
||||
data := requestResult.Data.(map[string]interface{})
|
||||
clientId := data["clientId"].(string)
|
||||
loginAuthURL := data["loginAuthURL"].(string)
|
||||
|
||||
referer := r.URL.Query().Get("referer")
|
||||
if "" == referer || !strings.Contains(referer, "://") {
|
||||
referer = conf.Wide.Server + referer
|
||||
}
|
||||
if strings.HasSuffix(referer, "/") {
|
||||
referer = referer[:len(referer)-1]
|
||||
}
|
||||
referer += "__1"
|
||||
state := util.Rand.String(16) + referer
|
||||
states[state] = state
|
||||
path := loginAuthURL + "?client_id=" + clientId + "&state=" + state + "&scope=public_repo,read:user,user:follow"
|
||||
|
||||
logger.Infof("redirect to github [" + path + "]")
|
||||
|
||||
http.Redirect(w, r, path, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func GithubCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||
logger.Infof("Github callback [" + r.URL.String() + "]")
|
||||
|
||||
state := r.URL.Query().Get("state")
|
||||
if _, exist := states[state]; !exist {
|
||||
http.Error(w, "Get state param failed", http.StatusBadRequest)
|
||||
|
||||
return
|
||||
}
|
||||
delete(states, state)
|
||||
|
||||
referer := state[16:]
|
||||
if strings.Contains(referer, "__0") || strings.Contains(referer, "__1") {
|
||||
referer = referer[:len(referer)-len("__0")]
|
||||
}
|
||||
accessToken := r.URL.Query().Get("ak")
|
||||
githubUser := GitHubUserInfo(accessToken)
|
||||
if nil == githubUser {
|
||||
logger.Warnf("Can not get user info with token [" + accessToken + "]")
|
||||
http.Error(w, "Get user info failed", http.StatusUnauthorized)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
githubId := githubUser["userId"].(string)
|
||||
userName := githubUser["userName"].(string)
|
||||
avatar := githubUser["userAvatarURL"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
user := conf.GetUser(githubId)
|
||||
if nil == user {
|
||||
msg := addUser(githubId, userName, avatar)
|
||||
if userCreated != msg {
|
||||
result.Succ = false
|
||||
result.Msg = msg
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// create a HTTP session
|
||||
httpSession, _ := HTTPSession.Get(r, CookieName)
|
||||
httpSession.Values["uid"] = githubId
|
||||
httpSession.Values["id"] = strconv.Itoa(rand.Int())
|
||||
httpSession.Options.MaxAge = conf.Wide.HTTPSessionMaxAge
|
||||
httpSession.Save(r, w)
|
||||
|
||||
logger.Debugf("Created a HTTP session [%s] for user [%s]", httpSession.Values["id"].(string), githubId)
|
||||
}
|
||||
|
||||
// GitHubUserInfo returns GitHub user info specified by the given access token.
|
||||
func GitHubUserInfo(accessToken string) (ret map[string]interface{}) {
|
||||
result := map[string]interface{}{}
|
||||
response, data, errors := gorequest.New().TLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
|
||||
Get("https://hacpai.com/github/user?ak="+accessToken).Timeout(7*time.Second).
|
||||
Set("User-Agent", conf.UserAgent).EndStruct(&result)
|
||||
if nil != errors || http.StatusOK != response.StatusCode {
|
||||
logger.Errorf("Get github user info failed: %+v, %s", errors, data)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if 0 != result["sc"].(float64) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return result["data"].(map[string]interface{})
|
||||
}
|
||||
|
||||
// LogoutHandler handles request of user logout (exit).
|
||||
func LogoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
httpSession, _ := HTTPSession.Get(r, CookieName)
|
||||
|
||||
httpSession.Options.MaxAge = -1
|
||||
httpSession.Save(r, w)
|
||||
}
|
||||
|
||||
// addUser add a user with the specified user id, username and avatar.
|
||||
//
|
||||
// 1. create the user's workspace
|
||||
// 2. generate 'Hello, 世界' demo code in the workspace (a console version and a HTTP version)
|
||||
// 3. update the user customized configurations, such as style.css
|
||||
// 4. serve files of the user's workspace via HTTP
|
||||
//
|
||||
// Note: user [playground] is a reserved mock user
|
||||
func addUser(userId, userName, userAvatar string) string {
|
||||
if "playground" == userId {
|
||||
return userExists
|
||||
}
|
||||
|
||||
addUserMutex.Lock()
|
||||
defer addUserMutex.Unlock()
|
||||
|
||||
for _, user := range conf.Users {
|
||||
if strings.ToLower(user.Id) == strings.ToLower(userId) {
|
||||
return userExists
|
||||
}
|
||||
}
|
||||
|
||||
workspace := filepath.Join(conf.Wide.Data, "workspaces", userId)
|
||||
newUser := conf.NewUser(userId, userName, userAvatar, workspace)
|
||||
conf.Users = append(conf.Users, newUser)
|
||||
if !newUser.Save() {
|
||||
return userCreateError
|
||||
}
|
||||
|
||||
conf.CreateWorkspaceDir(workspace)
|
||||
helloWorld(workspace)
|
||||
conf.UpdateCustomizedConf(userId)
|
||||
|
||||
logger.Infof("Created a user [%s]", userId)
|
||||
|
||||
return userCreated
|
||||
}
|
||||
|
||||
// helloWorld generates the 'Hello, 世界' source code.
|
||||
// 1. src/hello/main.go
|
||||
// 2. src/web/main.go
|
||||
func helloWorld(workspace string) {
|
||||
consoleHello(workspace)
|
||||
webHello(workspace)
|
||||
}
|
||||
|
||||
func consoleHello(workspace string) {
|
||||
dir := workspace + conf.PathSeparator + "src" + conf.PathSeparator + "hello"
|
||||
if err := os.MkdirAll(dir, 0755); nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
fout, err := os.Create(dir + conf.PathSeparator + "main.go")
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
fout.WriteString(conf.HelloWorld)
|
||||
|
||||
fout.Close()
|
||||
}
|
||||
|
||||
func webHello(workspace string) {
|
||||
dir := workspace + conf.PathSeparator + "src" + conf.PathSeparator + "web"
|
||||
if err := os.MkdirAll(dir, 0755); nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
fout, err := os.Create(dir + conf.PathSeparator + "main.go")
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
code := `package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("Hello, 世界"))
|
||||
})
|
||||
|
||||
port := getPort()
|
||||
|
||||
// you may need to change the address
|
||||
fmt.Println("Open https://wide.b3log.org:" + port + " in your browser to see the result")
|
||||
|
||||
if err := http.ListenAndServe(":"+port, nil); nil != err {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func getPort() string {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
return strconv.Itoa(7000 + rand.Intn(8000-7000))
|
||||
}
|
||||
|
||||
`
|
||||
|
||||
fout.WriteString(code)
|
||||
|
||||
fout.Close()
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -31,6 +31,7 @@ import (
|
|||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -38,14 +39,16 @@ import (
|
|||
"github.com/b3log/wide/event"
|
||||
"github.com/b3log/wide/log"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/go-fsnotify/fsnotify"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
const (
|
||||
sessionStateActive = iota
|
||||
sessionStateClosed // (not used so far)
|
||||
sessionStateClosed // (not used so far)
|
||||
|
||||
CookieName = "wide-sess"
|
||||
)
|
||||
|
||||
// Logger.
|
||||
|
@ -74,7 +77,7 @@ var HTTPSession = sessions.NewCookieStore([]byte("BEYOND"))
|
|||
// WideSession represents a session associated with a browser tab.
|
||||
type WideSession struct {
|
||||
ID string // id
|
||||
Username string // username
|
||||
UserId string // user id
|
||||
HTTPSession *sessions.Session // HTTP session related
|
||||
Processes []*os.Process // process set
|
||||
EventQueue *event.UserEventQueue // event queue
|
||||
|
@ -110,7 +113,7 @@ func FixedTimeRelease() {
|
|||
|
||||
for _, s := range WideSessions {
|
||||
if s.Updated.Before(threshold) {
|
||||
logger.Debugf("Removes a invalid session [%s], user [%s]", s.ID, s.Username)
|
||||
logger.Debugf("Removes a invalid session [%s], user [%s]", s.ID, s.UserId)
|
||||
|
||||
WideSessions.Remove(s.ID)
|
||||
}
|
||||
|
@ -121,7 +124,7 @@ func FixedTimeRelease() {
|
|||
|
||||
// Online user statistic report.
|
||||
type userReport struct {
|
||||
username string
|
||||
userId string
|
||||
sessionCnt int
|
||||
processCnt int
|
||||
updated time.Time
|
||||
|
@ -129,7 +132,7 @@ type userReport struct {
|
|||
|
||||
// report returns a online user statistics in pretty format.
|
||||
func (u *userReport) report() string {
|
||||
return "[" + u.username + "] has [" + strconv.Itoa(u.sessionCnt) + "] sessions and [" + strconv.Itoa(u.processCnt) +
|
||||
return "[" + u.userId + "] has [" + strconv.Itoa(u.sessionCnt) + "] sessions and [" + strconv.Itoa(u.processCnt) +
|
||||
"] running processes, latest activity [" + u.updated.Format("2006-01-02 15:04:05") + "]"
|
||||
}
|
||||
|
||||
|
@ -138,7 +141,7 @@ func FixedTimeReport() {
|
|||
go func() {
|
||||
defer util.Recover()
|
||||
|
||||
for _ = range time.Tick(10 * time.Minute) {
|
||||
for _ = range time.Tick(10*time.Minute) {
|
||||
users := userReports{}
|
||||
processSum := 0
|
||||
|
||||
|
@ -146,7 +149,7 @@ func FixedTimeReport() {
|
|||
processCnt := len(s.Processes)
|
||||
processSum += processCnt
|
||||
|
||||
if report, exists := contains(users, s.Username); exists {
|
||||
if report, exists := contains(users, s.UserId); exists {
|
||||
if s.Updated.After(report.updated) {
|
||||
report.updated = s.Updated
|
||||
}
|
||||
|
@ -154,7 +157,7 @@ func FixedTimeReport() {
|
|||
report.sessionCnt++
|
||||
report.processCnt += processCnt
|
||||
} else {
|
||||
users = append(users, &userReport{username: s.Username, sessionCnt: 1, processCnt: processCnt, updated: s.Updated})
|
||||
users = append(users, &userReport{userId: s.UserId, sessionCnt: 1, processCnt: processCnt, updated: s.Updated})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,9 +176,9 @@ func FixedTimeReport() {
|
|||
}()
|
||||
}
|
||||
|
||||
func contains(reports []*userReport, username string) (*userReport, bool) {
|
||||
func contains(reports []*userReport, userId string) (*userReport, bool) {
|
||||
for _, ur := range reports {
|
||||
if username == ur.username {
|
||||
if userId == ur.userId {
|
||||
return ur, true
|
||||
}
|
||||
}
|
||||
|
@ -219,7 +222,7 @@ func WSHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
wSession := WideSessions.Get(sid)
|
||||
if nil == wSession {
|
||||
httpSession, _ := HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := HTTPSession.Get(r, CookieName)
|
||||
|
||||
if httpSession.IsNew {
|
||||
return
|
||||
|
@ -230,7 +233,7 @@ func WSHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
wSession = WideSessions.new(httpSession, sid)
|
||||
|
||||
logger.Tracef("Created a wide session [%s] for websocket reconnecting, user [%s]", sid, wSession.Username)
|
||||
logger.Tracef("Created a wide session [%s] for websocket reconnecting, user [%s]", sid, wSession.UserId)
|
||||
}
|
||||
|
||||
logger.Tracef("Open a new [Session Channel] with session [%s], %d", sid, len(SessionWS))
|
||||
|
@ -262,7 +265,7 @@ func WSHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
for {
|
||||
if err := wsChan.ReadJSON(&input); err != nil {
|
||||
logger.Tracef("[Session Channel] of session [%s] disconnected, releases all resources with it, user [%s]", sid, wSession.Username)
|
||||
logger.Tracef("[Session Channel] of session [%s] disconnected, releases all resources with it, user [%s]", sid, wSession.UserId)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -306,7 +309,7 @@ func SaveContentHandler(w http.ResponseWriter, r *http.Request) {
|
|||
wSession.Content = args.LatestSessionContent
|
||||
|
||||
for _, user := range conf.Users {
|
||||
if user.Name == wSession.Username {
|
||||
if user.Id == wSession.UserId {
|
||||
// update the variable in-memory, session.FixedTimeSave() function will persist it periodically
|
||||
user.LatestSessionContent = wSession.Content
|
||||
|
||||
|
@ -375,9 +378,9 @@ func (sessions *wSessions) Remove(sid string) {
|
|||
// kill processes
|
||||
for _, p := range s.Processes {
|
||||
if err := p.Kill(); nil != err {
|
||||
logger.Errorf("Can't kill process [%d] of session [%s], user [%s]", p.Pid, sid, s.Username)
|
||||
logger.Errorf("Can't kill process [%d] of session [%s], user [%s]", p.Pid, sid, s.UserId)
|
||||
} else {
|
||||
logger.Debugf("Killed a process [%d] of session [%s], user [%s]", p.Pid, sid, s.Username)
|
||||
logger.Debugf("Killed a process [%d] of session [%s], user [%s]", p.Pid, sid, s.UserId)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -409,12 +412,12 @@ func (sessions *wSessions) Remove(sid string) {
|
|||
|
||||
cnt := 0 // count wide sessions associated with HTTP session
|
||||
for _, ses := range *sessions {
|
||||
if ses.Username == s.Username {
|
||||
if ses.UserId == s.UserId {
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
|
||||
logger.Debugf("Removed a session [%s] of user [%s], it has [%d] sessions currently", sid, s.Username, cnt)
|
||||
logger.Debugf("Removed a session [%s] of user [%s], it has [%d] sessions currently", sid, s.UserId, cnt)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -422,14 +425,14 @@ func (sessions *wSessions) Remove(sid string) {
|
|||
}
|
||||
|
||||
// GetByUsername gets wide sessions.
|
||||
func (sessions *wSessions) GetByUsername(username string) []*WideSession {
|
||||
func (sessions *wSessions) GetByUserId(userId string) []*WideSession {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
ret := []*WideSession{}
|
||||
|
||||
for _, s := range *sessions {
|
||||
if s.Username == username {
|
||||
if s.UserId == userId {
|
||||
ret = append(ret, s)
|
||||
}
|
||||
}
|
||||
|
@ -442,12 +445,12 @@ func (sessions *wSessions) new(httpSession *sessions.Session, sid string) *WideS
|
|||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
username := httpSession.Values["username"].(string)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
now := time.Now()
|
||||
|
||||
ret := &WideSession{
|
||||
ID: sid,
|
||||
Username: username,
|
||||
UserId: uid,
|
||||
HTTPSession: httpSession,
|
||||
EventQueue: nil,
|
||||
State: sessionStateActive,
|
||||
|
@ -458,7 +461,7 @@ func (sessions *wSessions) new(httpSession *sessions.Session, sid string) *WideS
|
|||
|
||||
*sessions = append(*sessions, ret)
|
||||
|
||||
if "playground" == username {
|
||||
if "playground" == uid {
|
||||
return ret
|
||||
}
|
||||
|
||||
|
@ -479,7 +482,7 @@ func (sessions *wSessions) new(httpSession *sessions.Session, sid string) *WideS
|
|||
for {
|
||||
ch := SessionWS[sid]
|
||||
if nil == ch {
|
||||
return // release this gorutine
|
||||
return // release this goroutine
|
||||
}
|
||||
|
||||
select {
|
||||
|
@ -505,17 +508,13 @@ func (sessions *wSessions) new(httpSession *sessions.Session, sid string) *WideS
|
|||
}
|
||||
}
|
||||
|
||||
cmd := map[string]interface{}{"path": path, "dir": dir,
|
||||
"cmd": "create-file", "type": fileType}
|
||||
cmd := map[string]interface{}{"path": path, "dir": dir, "cmd": "create-file", "type": fileType}
|
||||
ch.WriteJSON(&cmd)
|
||||
} else if event.Op&fsnotify.Remove == fsnotify.Remove {
|
||||
cmd := map[string]interface{}{"path": path, "dir": dir,
|
||||
"cmd": "remove-file", "type": ""}
|
||||
cmd := map[string]interface{}{"path": path, "dir": dir, "cmd": "remove-file", "type": ""}
|
||||
ch.WriteJSON(&cmd)
|
||||
|
||||
} else if event.Op&fsnotify.Rename == fsnotify.Rename {
|
||||
cmd := map[string]interface{}{"path": path, "dir": dir,
|
||||
"cmd": "rename-file", "type": ""}
|
||||
cmd := map[string]interface{}{"path": path, "dir": dir, "cmd": "rename-file", "type": ""}
|
||||
ch.WriteJSON(&cmd)
|
||||
}
|
||||
case err := <-watcher.Errors:
|
||||
|
@ -529,10 +528,10 @@ func (sessions *wSessions) new(httpSession *sessions.Session, sid string) *WideS
|
|||
go func() {
|
||||
defer util.Recover()
|
||||
|
||||
workspaces := filepath.SplitList(conf.GetUserWorkspace(username))
|
||||
workspaces := filepath.SplitList(conf.GetUserWorkspace(uid))
|
||||
for _, workspace := range workspaces {
|
||||
filepath.Walk(filepath.Join(workspace, "src"), func(dirPath string, f os.FileInfo, err error) error {
|
||||
if ".git" == f.Name() { // XXX: discard other unconcered dirs
|
||||
if strings.HasPrefix(f.Name(), ".") || "node_modules" == f.Name() || "vendor" == f.Name() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
|
|
315
session/users.go
315
session/users.go
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -15,15 +15,10 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
|
@ -38,10 +33,8 @@ const (
|
|||
// TODO: i18n
|
||||
|
||||
userExists = "user exists"
|
||||
emailExists = "email exists"
|
||||
userCreated = "user created"
|
||||
userCreateError = "user create error"
|
||||
notAllowRegister = "not allow register"
|
||||
)
|
||||
|
||||
// Exclusive lock for adding user.
|
||||
|
@ -49,22 +42,19 @@ var addUserMutex sync.Mutex
|
|||
|
||||
// PreferenceHandler handles request of preference page.
|
||||
func PreferenceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := HTTPSession.Get(r, "wide-session")
|
||||
httpSession, _ := HTTPSession.Get(r, CookieName)
|
||||
|
||||
if httpSession.IsNew {
|
||||
http.Redirect(w, r, conf.Wide.Context+"/login", http.StatusFound)
|
||||
http.Redirect(w, r, "/login", http.StatusFound)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
httpSession.Options.MaxAge = conf.Wide.HTTPSessionMaxAge
|
||||
if "" != conf.Wide.Context {
|
||||
httpSession.Options.Path = conf.Wide.Context
|
||||
}
|
||||
httpSession.Save(r, w)
|
||||
|
||||
username := httpSession.Values["username"].(string)
|
||||
user := conf.GetUser(username)
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
user := conf.GetUser(uid)
|
||||
|
||||
if "GET" == r.Method {
|
||||
tmpLinux := user.GoBuildArgsForLinux
|
||||
|
@ -116,8 +106,6 @@ func PreferenceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
Keymap string
|
||||
Workspace string
|
||||
Username string
|
||||
Password string
|
||||
Email string
|
||||
Locale string
|
||||
Theme string
|
||||
EditorFontFamily string
|
||||
|
@ -143,14 +131,6 @@ func PreferenceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
user.Keymap = args.Keymap
|
||||
// XXX: disallow change workspace at present
|
||||
// user.Workspace = args.Workspace
|
||||
if user.Password != args.Password {
|
||||
user.Password = conf.Salt(args.Password, user.Salt)
|
||||
}
|
||||
user.Email = args.Email
|
||||
|
||||
hash := md5.New()
|
||||
hash.Write([]byte(user.Email))
|
||||
user.Gravatar = hex.EncodeToString(hash.Sum(nil))
|
||||
|
||||
user.Locale = args.Locale
|
||||
user.Theme = args.Theme
|
||||
|
@ -160,7 +140,7 @@ func PreferenceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
user.Editor.Theme = args.EditorTheme
|
||||
user.Editor.TabSize = args.EditorTabSize
|
||||
|
||||
conf.UpdateCustomizedConf(username)
|
||||
conf.UpdateCustomizedConf(uid)
|
||||
|
||||
now := time.Now().UnixNano()
|
||||
user.Lived = now
|
||||
|
@ -169,137 +149,6 @@ func PreferenceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
result.Succ = user.Save()
|
||||
}
|
||||
|
||||
// LoginHandler handles request of user login.
|
||||
func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if "GET" == r.Method {
|
||||
// show the login page
|
||||
|
||||
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(conf.Wide.Locale),
|
||||
"locale": conf.Wide.Locale, "ver": conf.WideVersion, "year": time.Now().Year()}
|
||||
|
||||
t, err := template.ParseFiles("views/login.html")
|
||||
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
http.Error(w, err.Error(), 500)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
t.Execute(w, model)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// non-GET request as login request
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
args := struct {
|
||||
Username string
|
||||
Password string
|
||||
}{}
|
||||
|
||||
args.Username = r.FormValue("username")
|
||||
args.Password = r.FormValue("password")
|
||||
|
||||
result.Succ = false
|
||||
for _, user := range conf.Users {
|
||||
if user.Name == args.Username && user.Password == conf.Salt(args.Password, user.Salt) {
|
||||
result.Succ = true
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !result.Succ {
|
||||
return
|
||||
}
|
||||
|
||||
// create a HTTP session
|
||||
httpSession, _ := HTTPSession.Get(r, "wide-session")
|
||||
httpSession.Values["username"] = args.Username
|
||||
httpSession.Values["id"] = strconv.Itoa(rand.Int())
|
||||
httpSession.Options.MaxAge = conf.Wide.HTTPSessionMaxAge
|
||||
if "" != conf.Wide.Context {
|
||||
httpSession.Options.Path = conf.Wide.Context
|
||||
}
|
||||
httpSession.Save(r, w)
|
||||
|
||||
logger.Debugf("Created a HTTP session [%s] for user [%s]", httpSession.Values["id"].(string), args.Username)
|
||||
}
|
||||
|
||||
// LogoutHandler handles request of user logout (exit).
|
||||
func LogoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
httpSession, _ := HTTPSession.Get(r, "wide-session")
|
||||
|
||||
httpSession.Options.MaxAge = -1
|
||||
httpSession.Save(r, w)
|
||||
}
|
||||
|
||||
// SignUpUserHandler handles request of registering user.
|
||||
func SignUpUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if "GET" == r.Method {
|
||||
// show the user sign up page
|
||||
|
||||
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(conf.Wide.Locale),
|
||||
"locale": conf.Wide.Locale, "ver": conf.WideVersion, "dir": conf.Wide.UsersWorkspaces,
|
||||
"pathSeparator": conf.PathSeparator, "year": time.Now().Year()}
|
||||
|
||||
t, err := template.ParseFiles("views/sign_up.html")
|
||||
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
http.Error(w, err.Error(), 500)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
t.Execute(w, model)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// non-GET request as add user request
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
username := args["username"].(string)
|
||||
password := args["password"].(string)
|
||||
email := args["email"].(string)
|
||||
|
||||
msg := addUser(username, password, email)
|
||||
if userCreated != msg {
|
||||
result.Succ = false
|
||||
result.Msg = msg
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// create a HTTP session
|
||||
httpSession, _ := HTTPSession.Get(r, "wide-session")
|
||||
httpSession.Values["username"] = username
|
||||
httpSession.Values["id"] = strconv.Itoa(rand.Int())
|
||||
httpSession.Options.MaxAge = conf.Wide.HTTPSessionMaxAge
|
||||
if "" != conf.Wide.Context {
|
||||
httpSession.Options.Path = conf.Wide.Context
|
||||
}
|
||||
httpSession.Save(r, w)
|
||||
}
|
||||
|
||||
// FixedTimeSave saves online users' configurations periodically (1 minute).
|
||||
//
|
||||
// Main goal of this function is to save user session content, for restoring session content while user open Wide next time.
|
||||
|
@ -313,11 +162,11 @@ func FixedTimeSave() {
|
|||
}()
|
||||
}
|
||||
|
||||
// CanAccess determines whether the user specified by the given username can access the specified path.
|
||||
func CanAccess(username, path string) bool {
|
||||
// CanAccess determines whether the user specified by the given user id can access the specified path.
|
||||
func CanAccess(userId, path string) bool {
|
||||
path = filepath.FromSlash(path)
|
||||
|
||||
userWorkspace := conf.GetUserWorkspace(username)
|
||||
userWorkspace := conf.GetUserWorkspace(userId)
|
||||
workspaces := filepath.SplitList(userWorkspace)
|
||||
|
||||
for _, workspace := range workspaces {
|
||||
|
@ -342,20 +191,20 @@ func SaveOnlineUsers() {
|
|||
func getOnlineUsers() []*conf.User {
|
||||
ret := []*conf.User{}
|
||||
|
||||
usernames := map[string]string{} // distinct username
|
||||
uids := map[string]string{} // distinct uid
|
||||
for _, s := range WideSessions {
|
||||
usernames[s.Username] = s.Username
|
||||
uids[s.UserId] = s.UserId
|
||||
}
|
||||
|
||||
for _, username := range usernames {
|
||||
u := conf.GetUser(username)
|
||||
for _, uid := range uids {
|
||||
u := conf.GetUser(uid)
|
||||
|
||||
if "playground" == username { // user [playground] is a reserved mock user
|
||||
if "playground" == uid { // user [playground] is a reserved mock user
|
||||
continue
|
||||
}
|
||||
|
||||
if nil == u {
|
||||
logger.Warnf("Not found user [%s]", username)
|
||||
logger.Warnf("Not found user [%s]", uid)
|
||||
|
||||
continue
|
||||
}
|
||||
|
@ -365,135 +214,3 @@ func getOnlineUsers() []*conf.User {
|
|||
|
||||
return ret
|
||||
}
|
||||
|
||||
// addUser add a user with the specified username, password and email.
|
||||
//
|
||||
// 1. create the user's workspace
|
||||
// 2. generate 'Hello, 世界' demo code in the workspace (a console version and a HTTP version)
|
||||
// 3. update the user customized configurations, such as style.css
|
||||
// 4. serve files of the user's workspace via HTTP
|
||||
//
|
||||
// Note: user [playground] is a reserved mock user
|
||||
func addUser(username, password, email string) string {
|
||||
if !conf.Wide.AllowRegister {
|
||||
return notAllowRegister
|
||||
}
|
||||
|
||||
if "playground" == username {
|
||||
return userExists
|
||||
}
|
||||
|
||||
addUserMutex.Lock()
|
||||
defer addUserMutex.Unlock()
|
||||
|
||||
for _, user := range conf.Users {
|
||||
if strings.ToLower(user.Name) == strings.ToLower(username) {
|
||||
return userExists
|
||||
}
|
||||
|
||||
if strings.ToLower(user.Email) == strings.ToLower(email) {
|
||||
return emailExists
|
||||
}
|
||||
}
|
||||
|
||||
workspace := filepath.Join(conf.Wide.UsersWorkspaces, username)
|
||||
|
||||
newUser := conf.NewUser(username, password, email, workspace)
|
||||
conf.Users = append(conf.Users, newUser)
|
||||
|
||||
if !newUser.Save() {
|
||||
return userCreateError
|
||||
}
|
||||
|
||||
conf.CreateWorkspaceDir(workspace)
|
||||
helloWorld(workspace)
|
||||
conf.UpdateCustomizedConf(username)
|
||||
|
||||
http.Handle("/workspace/"+username+"/",
|
||||
http.StripPrefix("/workspace/"+username+"/", http.FileServer(http.Dir(newUser.WorkspacePath()))))
|
||||
|
||||
logger.Infof("Created a user [%s]", username)
|
||||
|
||||
return userCreated
|
||||
}
|
||||
|
||||
// helloWorld generates the 'Hello, 世界' source code.
|
||||
// 1. src/hello/main.go
|
||||
// 2. src/web/main.go
|
||||
func helloWorld(workspace string) {
|
||||
consoleHello(workspace)
|
||||
webHello(workspace)
|
||||
}
|
||||
|
||||
func consoleHello(workspace string) {
|
||||
dir := workspace + conf.PathSeparator + "src" + conf.PathSeparator + "hello"
|
||||
if err := os.MkdirAll(dir, 0755); nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
fout, err := os.Create(dir + conf.PathSeparator + "main.go")
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
fout.WriteString(conf.HelloWorld)
|
||||
|
||||
fout.Close()
|
||||
}
|
||||
|
||||
func webHello(workspace string) {
|
||||
dir := workspace + conf.PathSeparator + "src" + conf.PathSeparator + "web"
|
||||
if err := os.MkdirAll(dir, 0755); nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
fout, err := os.Create(dir + conf.PathSeparator + "main.go")
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
code := `package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("Hello, 世界"))
|
||||
})
|
||||
|
||||
port := getPort()
|
||||
|
||||
// you may need to change the address
|
||||
fmt.Println("Open http://wide.b3log.org:" + port + " in your browser to see the result")
|
||||
|
||||
if err := http.ListenAndServe(":"+port, nil); nil != err {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func getPort() string {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
return strconv.Itoa(7000 + rand.Intn(8000-7000))
|
||||
}
|
||||
|
||||
`
|
||||
|
||||
fout.WriteString(code)
|
||||
|
||||
fout.Close()
|
||||
}
|
||||
|
|
189
shell/shells.go
189
shell/shells.go
|
@ -1,189 +0,0 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package shell include shell related mainipulations.
|
||||
package shell
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/i18n"
|
||||
"github.com/b3log/wide/log"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// Shell channel.
|
||||
//
|
||||
// <sid, *util.WSChannel>>
|
||||
var ShellWS = map[string]*util.WSChannel{}
|
||||
|
||||
// Logger.
|
||||
var logger = log.NewLogger(os.Stdout)
|
||||
|
||||
// IndexHandler handles request of Shell index.
|
||||
func IndexHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
if httpSession.IsNew {
|
||||
http.Redirect(w, r, conf.Wide.Context+"/login", http.StatusFound)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
httpSession.Options.MaxAge = conf.Wide.HTTPSessionMaxAge
|
||||
if "" != conf.Wide.Context {
|
||||
httpSession.Options.Path = conf.Wide.Context
|
||||
}
|
||||
httpSession.Save(r, w)
|
||||
|
||||
username := httpSession.Values["username"].(string)
|
||||
locale := conf.GetUser(username).Locale
|
||||
|
||||
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(locale), "locale": locale,
|
||||
"sid": session.WideSessions.GenId()}
|
||||
|
||||
wideSessions := session.WideSessions.GetByUsername(username)
|
||||
|
||||
logger.Tracef("User [%s] has [%d] sessions", username, len(wideSessions))
|
||||
|
||||
t, err := template.ParseFiles("views/shell.html")
|
||||
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
http.Error(w, err.Error(), 500)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
t.Execute(w, model)
|
||||
}
|
||||
|
||||
// WSHandler handles request of creating Shell channel.
|
||||
func WSHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
username := httpSession.Values["username"].(string)
|
||||
|
||||
sid := r.URL.Query()["sid"][0]
|
||||
|
||||
conn, _ := websocket.Upgrade(w, r, nil, 1024, 1024)
|
||||
wsChan := util.WSChannel{Sid: sid, Conn: conn, Request: r, Time: time.Now()}
|
||||
|
||||
ret := map[string]interface{}{"output": "Shell initialized", "cmd": "init-shell"}
|
||||
err := wsChan.WriteJSON(&ret)
|
||||
if nil != err {
|
||||
return
|
||||
}
|
||||
|
||||
ShellWS[sid] = &wsChan
|
||||
|
||||
logger.Debugf("Open a new [Shell] with session [%s], %d", sid, len(ShellWS))
|
||||
|
||||
input := map[string]interface{}{}
|
||||
|
||||
for {
|
||||
if err := wsChan.ReadJSON(&input); err != nil {
|
||||
logger.Error("Shell WS ERROR: " + err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
inputCmd := input["cmd"].(string)
|
||||
|
||||
cmds := strings.Split(inputCmd, "|")
|
||||
commands := []*exec.Cmd{}
|
||||
for _, cmdWithArgs := range cmds {
|
||||
cmdWithArgs = strings.TrimSpace(cmdWithArgs)
|
||||
cmdWithArgs := strings.Split(cmdWithArgs, " ")
|
||||
args := []string{}
|
||||
if len(cmdWithArgs) > 1 {
|
||||
args = cmdWithArgs[1:]
|
||||
}
|
||||
|
||||
cmd := exec.Command(cmdWithArgs[0], args...)
|
||||
commands = append(commands, cmd)
|
||||
}
|
||||
|
||||
output := ""
|
||||
if !strings.Contains(inputCmd, "clear") {
|
||||
output = pipeCommands(username, commands...)
|
||||
}
|
||||
|
||||
ret = map[string]interface{}{"output": output, "cmd": "shell-output"}
|
||||
|
||||
if err := wsChan.WriteJSON(&ret); err != nil {
|
||||
logger.Error("Shell WS ERROR: " + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
wsChan.Refresh()
|
||||
}
|
||||
}
|
||||
|
||||
func pipeCommands(username string, commands ...*exec.Cmd) string {
|
||||
for i, command := range commands[:len(commands)-1] {
|
||||
setCmdEnv(command, username)
|
||||
|
||||
stdout, err := command.StdoutPipe()
|
||||
if nil != err {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
command.Start()
|
||||
|
||||
commands[i+1].Stdin = stdout
|
||||
}
|
||||
|
||||
last := commands[len(commands)-1]
|
||||
setCmdEnv(last, username)
|
||||
|
||||
out, err := last.CombinedOutput()
|
||||
|
||||
// release resources
|
||||
for _, command := range commands[:len(commands)-1] {
|
||||
command.Wait()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func setCmdEnv(cmd *exec.Cmd, username string) {
|
||||
userWorkspace := conf.GetUserWorkspace(username)
|
||||
|
||||
cmd.Env = append(cmd.Env,
|
||||
"TERM="+os.Getenv("TERM"),
|
||||
"GOPATH="+userWorkspace,
|
||||
"GOOS="+runtime.GOOS,
|
||||
"GOARCH="+runtime.GOARCH,
|
||||
"GOROOT="+runtime.GOROOT(),
|
||||
"PATH="+os.Getenv("PATH"))
|
||||
|
||||
cmd.Dir = userWorkspace
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -18,7 +18,7 @@
|
|||
* themes for base.
|
||||
*
|
||||
* @author <a href="http://vanessa.b3log.org">Liyuan Li</a>
|
||||
* @version 0.1.0.0, Dec 6, 2015
|
||||
* @version 0.2.0.0, Oct 5, 2018
|
||||
*/
|
||||
/* start reset & function */
|
||||
::-webkit-scrollbar {
|
||||
|
@ -140,18 +140,24 @@ button {
|
|||
/* start icon */
|
||||
@font-face {
|
||||
font-family: 'icomoon';
|
||||
src:url('fonts/icomoon.eot?35cb2z');
|
||||
src:url('fonts/icomoon.eot?#iefix35cb2z') format('embedded-opentype'),
|
||||
url('fonts/icomoon.woff?35cb2z') format('woff'),
|
||||
url('fonts/icomoon.ttf?35cb2z') format('truetype'),
|
||||
url('fonts/icomoon.svg?35cb2z#icomoon') format('svg');
|
||||
src: url('fonts/icomoon.eot?lqk80d');
|
||||
src: url('fonts/icomoon.eot?lqk80d#iefix') format('embedded-opentype'),
|
||||
url('fonts/icomoon.ttf?lqk80d') format('truetype'),
|
||||
url('fonts/icomoon.woff?lqk80d') format('woff'),
|
||||
url('fonts/icomoon.svg?lqk80d#icomoon') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.font-ico,
|
||||
[class^="ico-"] {
|
||||
font-family: 'icomoon';
|
||||
[class^="ico-"], [class*=" ico-"] {
|
||||
/* use !important to prevent issues with browser extensions that change fonts */
|
||||
font-family: 'icomoon' !important;
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
|
||||
/* Better Font Rendering =========== */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
@ -160,177 +166,143 @@ button {
|
|||
line-height: 20px;
|
||||
}
|
||||
|
||||
.ico-book:before {
|
||||
content: "\e623";
|
||||
.ico-qqz:before {
|
||||
content: "\e900";
|
||||
}
|
||||
|
||||
.ico-price:before {
|
||||
content: "\e616";
|
||||
}
|
||||
|
||||
.ico-start:before {
|
||||
content: "\e9d7";
|
||||
}
|
||||
|
||||
.ico-share:before {
|
||||
content: "\e61f";
|
||||
}
|
||||
|
||||
.ico-github:before {
|
||||
content: "\f00a";
|
||||
}
|
||||
|
||||
.ico-git:before {
|
||||
content: "\e624";
|
||||
}
|
||||
|
||||
.ico-tencent:before {
|
||||
content: "\e622";
|
||||
}
|
||||
|
||||
.ico-weibo:before {
|
||||
content: "\e621";
|
||||
}
|
||||
|
||||
.ico-googleplus:before {
|
||||
content: "\e61a";
|
||||
}
|
||||
|
||||
.ico-twitter:before {
|
||||
content: "\e61c";
|
||||
}
|
||||
|
||||
.ico-email:before {
|
||||
content: "\e619";
|
||||
}
|
||||
|
||||
.ico-facebook:before {
|
||||
content: "\e61b";
|
||||
}
|
||||
|
||||
.ico-moveup:before {
|
||||
content: "\f148";
|
||||
}
|
||||
|
||||
.ico-movedown:before {
|
||||
content: "\f149";
|
||||
}
|
||||
|
||||
.ico-keyboard:before {
|
||||
content: "\f11c";
|
||||
}
|
||||
|
||||
.ico-findfiles:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
.ico-find:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.ico-findfiles:before {
|
||||
content: "\e603";
|
||||
}
|
||||
.ico-editor:before {
|
||||
content: "\e604";
|
||||
}
|
||||
|
||||
.ico-tree:before {
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.ico-build:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.ico-notification:before {
|
||||
content: "\e607";
|
||||
}
|
||||
|
||||
.ico-price:before {
|
||||
content: "\e616";
|
||||
}
|
||||
.ico-report:before {
|
||||
content: "\e605";
|
||||
}
|
||||
|
||||
.ico-comment:before {
|
||||
content: "\e620";
|
||||
}
|
||||
|
||||
.ico-goline:before {
|
||||
content: "\e61e";
|
||||
}
|
||||
|
||||
.ico-info:before {
|
||||
content: "\e61d";
|
||||
}
|
||||
|
||||
.ico-signup:before {
|
||||
content: "\e606";
|
||||
}
|
||||
|
||||
.ico-signout:before {
|
||||
content: "\e618";
|
||||
.ico-git:before {
|
||||
content: "\e624";
|
||||
}
|
||||
|
||||
.ico-redo:before {
|
||||
content: "\e615";
|
||||
.ico-book:before {
|
||||
content: "\e623";
|
||||
}
|
||||
|
||||
.ico-undo:before {
|
||||
content: "\e60e";
|
||||
.ico-start:before {
|
||||
content: "\e9d7";
|
||||
text-shadow: 0 0 rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.ico-about:before {
|
||||
content: "\e60d";
|
||||
.ico-tree:before {
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.ico-import:before {
|
||||
content: "\f0ee";
|
||||
.ico-build:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.ico-export:before {
|
||||
content: "\f0ed";
|
||||
}
|
||||
|
||||
.ico-refresh:before {
|
||||
content: "\f021";
|
||||
.ico-import:before {
|
||||
content: "\f0ee";
|
||||
}
|
||||
|
||||
.ico-remove:before {
|
||||
content: "\e60b";
|
||||
.ico-keyboard:before {
|
||||
content: "\f11c";
|
||||
}
|
||||
|
||||
.ico-save:before {
|
||||
content: "\f0c7";
|
||||
.ico-moveup:before {
|
||||
content: "\f148";
|
||||
}
|
||||
.ico-movedown:before {
|
||||
content: "\f149";
|
||||
}
|
||||
.ico-weibo:before {
|
||||
content: "\e621";
|
||||
}
|
||||
.ico-uniE608:before {
|
||||
content: "\e608";
|
||||
}
|
||||
|
||||
.ico-max:before {
|
||||
content: "\e609";
|
||||
}
|
||||
|
||||
.ico-format:before {
|
||||
content: "\e612";
|
||||
.ico-remove:before {
|
||||
content: "\e60b";
|
||||
}
|
||||
|
||||
.ico-buildrun:before {
|
||||
content: "\e60c";
|
||||
}
|
||||
|
||||
.ico-about:before {
|
||||
content: "\e60d";
|
||||
}
|
||||
.ico-undo:before {
|
||||
content: "\e60e";
|
||||
}
|
||||
.ico-stop:before {
|
||||
content: "\e60f";
|
||||
}
|
||||
|
||||
.ico-close:before {
|
||||
content: "\e611";
|
||||
text-shadow: 0 0 rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
.ico-format:before {
|
||||
content: "\e612";
|
||||
}
|
||||
.ico-restore:before {
|
||||
content: "\e613";
|
||||
}
|
||||
|
||||
.toolbars .ico-restore:before {
|
||||
content: "\e60a";
|
||||
}
|
||||
|
||||
.ico-min:before {
|
||||
content: "\e614";
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.ico-close:before {
|
||||
content: "\e611";
|
||||
.ico-redo:before {
|
||||
content: "\e615";
|
||||
}
|
||||
.ico-uniE617:before {
|
||||
content: "\e617";
|
||||
}
|
||||
.ico-signout:before {
|
||||
content: "\e618";
|
||||
}
|
||||
.ico-email:before {
|
||||
content: "\e619";
|
||||
}
|
||||
.ico-googleplus:before {
|
||||
content: "\e61a";
|
||||
}
|
||||
.ico-facebook:before {
|
||||
content: "\e61b";
|
||||
}
|
||||
.ico-twitter:before {
|
||||
content: "\e61c";
|
||||
}
|
||||
.ico-info:before {
|
||||
content: "\e61d";
|
||||
}
|
||||
.ico-goline:before {
|
||||
content: "\e61e";
|
||||
}
|
||||
.ico-share:before {
|
||||
content: "\e61f";
|
||||
}
|
||||
.ico-comment:before {
|
||||
content: "\e620";
|
||||
}
|
||||
.ico-github:before {
|
||||
content: "\f00a";
|
||||
}
|
||||
.ico-refresh:before {
|
||||
content: "\f021";
|
||||
}
|
||||
.ico-save:before {
|
||||
content: "\f0c7";
|
||||
}
|
||||
/* end ico */
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -17,7 +17,7 @@
|
|||
/**
|
||||
* dialig style
|
||||
*
|
||||
* @author <a href="mailto:LLY219@gmail.com">Liyuan Li</a>
|
||||
* @author <a href="http://vanessa.b3log.org">Liyuan Li</a>
|
||||
* @version 0.0.0.6, Jun 3, 2012
|
||||
*/
|
||||
|
||||
|
|
Binary file not shown.
|
@ -6,52 +6,50 @@
|
|||
<font id="icomoon" horiz-adv-x="1024">
|
||||
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
||||
<missing-glyph horiz-adv-x="1024" />
|
||||
<glyph unicode=" " d="" horiz-adv-x="512" />
|
||||
<glyph unicode="" d="M0 886.858c0 40.396 32.747 73.143 73.143 73.143s73.143-32.747 73.143-73.143c0-40.396-32.747-73.143-73.143-73.143s-73.143 32.747-73.143 73.143zM292.572 960h877.714v-146.286h-877.714zM292.572 594.286c0 40.396 32.747 73.143 73.143 73.143s73.143-32.747 73.143-73.143c0-40.396-32.747-73.143-73.143-73.143s-73.143 32.747-73.143 73.143zM585.142 667.428h585.144v-146.286h-585.144zM292.572 9.142c0 40.396 32.747 73.143 73.143 73.143s73.143-32.747 73.143-73.143c0-40.396-32.747-73.143-73.143-73.143s-73.143 32.747-73.143 73.143zM585.142 82.286h585.144v-146.286h-585.144zM585.142 301.714c0 40.396 32.747 73.143 73.143 73.143s73.143-32.747 73.143-73.143c0-40.396-32.747-73.143-73.143-73.143s-73.143 32.747-73.143 73.143zM877.714 374.858h292.572v-146.286h-292.572z" horiz-adv-x="1170" />
|
||||
<glyph unicode="" d="M1009.996 131.024l-301.544 301.544c-18.668 18.668-49.214 18.668-67.882 0l-22.626-22.626-184 184 302.056 302.058h-320l-142.058-142.058-14.060 14.058h-67.882v-67.882l14.058-14.058-206.058-206.060 160-160 206.058 206.058 184-184-22.626-22.626c-18.668-18.668-18.668-49.214 0-67.882l301.544-301.544c18.668-18.668 49.214-18.668 67.882 0l113.136 113.136c18.67 18.666 18.67 49.214 0.002 67.882z" />
|
||||
<glyph unicode="" d="M632.576 661.376c46.080-10.666 82.752-49.92 93.418-92.8 3.648-20.054 21.12-35.2 42.048-35.2 23.466 0 42.666 19.2 42.666 42.666 0 30.72-25.814 77.44-61.014 112.426-34.56 34.134-75.734 58.24-109.654 58.24-23.466 0-42.666-19.84-42.666-43.306 0.002-20.884 15.148-38.4 35.202-42.026zM46.122 102.016c-33.066-33.046-33.066-86.826 0-119.872 33.066-33.088 86.826-33.088 119.68 0l245.098 244.906c57.194-35.67 124.586-56.342 197.12-56.342 206.294 0 373.334 167.040 373.334 373.334s-167.040 373.334-373.334 373.334-373.334-167.040-373.334-373.334c0-72.32 20.714-139.946 56.342-197.12l-244.906-244.906zM341.376 544.042c0 147.2 119.488 266.666 266.666 266.666 147.2 0 266.666-119.466 266.666-266.666s-119.466-266.666-266.666-266.666c-147.178 0.022-266.666 119.488-266.666 266.666z" />
|
||||
<glyph unicode="" d="M0 21.334c0-47.146 38.186-85.334 85.334-85.334h277.334c47.146 0 85.334 38.186 85.334 85.334l-0.002 341.332h128v-341.334c0-47.146 38.186-85.334 85.334-85.334h277.334c47.146 0 85.334 38.186 85.334 85.334l-0.002 554.668c0 47.146-38.186 85.334-85.334 85.334h-42.666v192h10.666c29.44 0 53.334 23.892 53.334 53.332s-23.894 53.334-53.334 53.334h-277.334c-29.438 0-53.332-23.894-53.332-53.334s23.894-53.332 53.334-53.332h10.666v-192h-256v192h10.666c29.44 0 53.334 23.892 53.334 53.332s-23.894 53.334-53.334 53.334h-277.334c-29.438 0-53.332-23.894-53.332-53.334s23.894-53.332 53.334-53.332h10.666v-192h-42.666c-47.146 0-85.334-38.186-85.334-85.334v-554.666zM554.666 469.334h-85.334c-23.466 0-42.666 19.2-42.666 42.666s19.2 42.666 42.666 42.666h85.334c23.466 0 42.666-19.2 42.666-42.666s-19.198-42.666-42.666-42.666z" />
|
||||
<glyph unicode="" d="M118.634 528.918c-20.886-20.886-30.934-50.774-36.032-81.066l-81.322-384.428c-11.52-68.288 56.96-136.982 126.102-126.314l384.874 80.234c28.16 5.098 58.666 13.866 79.574 34.774l407.68 408.128c32.64 32.832 32.64 85.952 0 118.806l-356.054 356.48c-32.854 32.64-85.974 32.64-118.634 0l-406.188-406.614zM509.888 118.678l-199.254-38.208-165.12 165.334 37.952 199.488 296.768 297.174c16.426 16.448 42.88 16.448 59.306 0 16.448-16.426 16.448-43.094 0-59.52l-274.368-274.774c-20.48-20.48-20.48-53.782 0-74.218 20.48-20.502 53.546-20.502 74.026 0l274.582 274.774c16.448 16.426 42.88 16.426 59.306 0 16.448-16.448 16.448-42.902 0-59.306l-274.368-274.774c-20.48-20.48-20.48-53.782 0-74.24 20.48-20.48 53.568-20.48 74.026 0l274.582 274.774c16.234 16.234 42.902 16.234 59.328 0 16.426-16.426 16.426-43.094 0-59.498l-296.766-297.006z" />
|
||||
<glyph unicode="" d="M622.858 778.475l-22.032 110.158h-495.715v-936.349h110.158v385.556h308.443l22.032-110.158h385.556v550.795z" />
|
||||
<glyph unicode="" d="M697.83 473.125c76.887 0 138.908 62.486 138.908 139.372s-62.021 139.372-138.908 139.372c-76.887 0-139.372-62.486-139.372-139.372s62.486-139.372 139.372-139.372zM326.17 473.125c76.887 0 138.908 62.486 138.908 139.372s-62.021 139.372-138.908 139.372c-76.887 0-139.372-62.486-139.372-139.372s62.486-139.372 139.372-139.372zM326.17 380.209c-108.479 0-325.203-54.355-325.203-162.601v-116.144h650.404v116.144c0 108.245-216.724 162.601-325.203 162.601zM697.83 380.209c-13.472 0-28.571-0.929-44.831-2.555 53.89-38.792 91.289-91.057 91.289-160.047v-116.144h278.744v116.144c0 108.245-216.724 162.601-325.203 162.601z" />
|
||||
<glyph unicode="" d="M977.76 152.992l-400.608 685.952c-33.408 33.408-87.616 33.408-121.024 0l-400.64-685.952c-33.408-33.376-33.408-87.552 0-120.992h922.24c33.472 33.44 33.472 87.616 0.032 120.992zM479.744 592.704c0 26.528 21.504 48 48 48s48-21.472 48-48v-224c0-26.496-21.504-48-48-48s-48 21.504-48 48v224zM528.032 160.448c-26.496 0-48 21.44-48 48 0 26.496 21.504 48 48 48s48-21.504 48-48c0-26.56-21.504-48-48-48z" />
|
||||
<glyph unicode="" d="M438.928 896.072q14.856 0 25.714-10.856t10.858-25.714v-128h168l98.856 98.856q10.856 10.856 25.714 10.856t25.714-10.856 10.856-25.714-10.856-25.714l-98.856-98.856v-482.286l98.856-98.856q10.856-10.856 10.856-25.714t-10.856-25.714-25.714-10.856-25.714 10.856l-98.856 98.856h-168v-128q0-14.856-10.856-25.714t-25.714-10.856-25.714 10.856-10.856 25.714v128q-97.714 0-165.714 38.286l-119.43-118.856q-10.856-10.856-25.714-10.856t-25.714 10.856q-10.856 10.286-10.856 25.714t10.856 25.714l112.57 113.144q-2.856 2.856-7.43 8.572t-16.286 24-20.856 37.144-16.57 46.856-7.43 55.428h512v73.144h-512q0 29.144 7.714 58t18.856 49.714 22.286 37.714 18.57 24.856l8 8.572-118.286 104.57q-12 11.43-12 27.43 0 13.714 9.144 24.57 10.286 10.858 25.43 11.714t26.57-8.856l129.714-115.428q65.144 33.142 156.57 33.142v128q0 14.858 10.858 25.714t25.714 10.856zM768.072 621.786q76 0 129.428-53.428t53.428-129.428-53.428-129.428-129.428-53.428v365.714z" horiz-adv-x="952" />
|
||||
<glyph unicode="" d="M1024 960v-384l-138.26 138.26-212-212-107.48 107.48 212 212-138.26 138.26zM245.74 821.74l212-212-107.48-107.48-212 212-138.26-138.26v384h384zM885.74 181.74l138.26 138.26v-384h-384l138.26 138.26-212 212 107.48 107.48zM457.74 286.26l-212-212 138.26-138.26h-384v384l138.26-138.26 212 212z" />
|
||||
<glyph unicode="" d="M64 384h384v-384l-138.26 138.26-202-202-107.48 107.48 202 202zM821.74 245.74l202-202-107.48-107.48-202 202-138.26-138.26v384h384zM960 512h-384v384l138.26-138.26 202 202 107.48-107.48-202-202zM309.74 757.74l138.26 138.26v-384h-384l138.26 138.26-202 202 107.48 107.48z" />
|
||||
<glyph unicode="" d="M800 832h-576c-53.020 0-96-42.98-96-96v-32h768v32c0 53.020-42.98 96-96 96zM632.32 896l14.116-101h-268.872l14.114 101h240.642zM640 960h-256c-26.4 0-50.99-21.392-54.642-47.538l-18.714-133.924c-3.654-26.146 14.956-47.538 41.356-47.538h320c26.4 0 45.010 21.392 41.358 47.538l-18.714 133.924c-3.654 26.146-28.244 47.538-54.644 47.538v0zM816 640h-608c-35.2 0-61.392-28.682-58.206-63.738l52.412-576.526c3.186-35.054 34.594-63.736 69.794-63.736h480c35.2 0 66.608 28.682 69.794 63.736l52.41 576.526c3.188 35.056-23.004 63.738-58.204 63.738zM384 64h-96l-32 448h128v-448zM576 64h-128v448h128v-448zM736 64h-96v448h128l-32-448z" />
|
||||
<glyph unicode="" d="M192 832l640-384-640-384z" />
|
||||
<glyph unicode="" d="M708.524 833.167c-54.823 39.545-123.584 59.295-206.423 59.295-63.041 0-116.185-13.935-159.382-41.708-68.567-43.534-104.989-117.434-109.41-221.702h158.852c0 30.367 8.841 59.629 26.572 87.787s47.81 42.236 90.238 42.236c43.101 0 72.844-11.436 89.084-34.26 16.289-22.92 24.41-48.242 24.41-76.015 0-24.169-12.108-46.272-26.714-66.405-8.024-11.726-18.644-22.488-31.759-32.387 0 0-86.154-55.258-124.016-99.657-21.959-25.755-23.929-64.291-25.851-119.598-0.144-3.94 1.346-12.059 15.136-12.059s111.332 0 123.584 0 14.8 9.083 14.991 13.069c0.865 20.133 3.123 30.416 6.823 42.044 6.967 21.959 25.803 41.129 47.042 57.614l43.726 30.176c39.447 30.752 70.97 55.978 84.855 75.775 23.738 32.578 40.409 72.651 40.409 120.171 0 77.601-27.437 136.126-82.166 175.623zM499.553 223.413c-54.777 1.633-99.944-36.231-101.672-95.619-1.73-59.342 41.227-98.549 96.004-100.184 57.18-1.682 101.145 34.981 102.875 94.322 1.682 59.39-40.026 99.8-97.205 101.481z" />
|
||||
<glyph unicode="" d="M761.862-64c113.726 206.032 132.888 520.306-313.862 509.824v-253.824l-384 384 384 384v-248.372c534.962 13.942 594.57-472.214 313.862-775.628z" />
|
||||
<glyph unicode="" d="M128 832h768v-768h-768z" />
|
||||
<glyph unicode="" d="M363.722 237.948l41.298 57.816-45.254 45.256-57.818-41.296c-10.722 5.994-22.204 10.774-34.266 14.192l-11.682 70.084h-64l-11.68-70.086c-12.062-3.418-23.544-8.198-34.266-14.192l-57.818 41.298-45.256-45.256 41.298-57.816c-5.994-10.72-10.774-22.206-14.192-34.266l-70.086-11.682v-64l70.086-11.682c3.418-12.060 8.198-23.544 14.192-34.266l-41.298-57.816 45.254-45.256 57.818 41.296c10.722-5.994 22.204-10.774 34.266-14.192l11.682-70.084h64l11.68 70.086c12.062 3.418 23.544 8.198 34.266 14.192l57.818-41.296 45.254 45.256-41.298 57.816c5.994 10.72 10.774 22.206 14.192 34.266l70.088 11.68v64l-70.086 11.682c-3.418 12.060-8.198 23.544-14.192 34.266zM224 96c-35.348 0-64 28.654-64 64s28.652 64 64 64 64-28.654 64-64-28.652-64-64-64zM1024 576v64l-67.382 12.25c-1.242 8.046-2.832 15.978-4.724 23.79l57.558 37.1-24.492 59.128-66.944-14.468c-4.214 6.91-8.726 13.62-13.492 20.13l39.006 56.342-45.256 45.254-56.342-39.006c-6.512 4.766-13.22 9.276-20.13 13.494l14.468 66.944-59.128 24.494-37.1-57.558c-7.812 1.892-15.744 3.482-23.79 4.724l-12.252 67.382h-64l-12.252-67.382c-8.046-1.242-15.976-2.832-23.79-4.724l-37.098 57.558-59.128-24.492 14.468-66.944c-6.91-4.216-13.62-8.728-20.13-13.494l-56.342 39.006-45.254-45.254 39.006-56.342c-4.766-6.51-9.278-13.22-13.494-20.13l-66.944 14.468-24.492-59.128 57.558-37.1c-1.892-7.812-3.482-15.742-4.724-23.79l-67.384-12.252v-64l67.382-12.25c1.242-8.046 2.832-15.978 4.724-23.79l-57.558-37.1 24.492-59.128 66.944 14.468c4.216-6.91 8.728-13.618 13.494-20.13l-39.006-56.342 45.254-45.256 56.342 39.006c6.51-4.766 13.22-9.276 20.13-13.492l-14.468-66.944 59.128-24.492 37.102 57.558c7.81-1.892 15.742-3.482 23.788-4.724l12.252-67.384h64l12.252 67.382c8.044 1.242 15.976 2.832 23.79 4.724l37.1-57.558 59.128 24.492-14.468 66.944c6.91 4.216 13.62 8.726 20.13 13.492l56.342-39.006 45.256 45.256-39.006 56.342c4.766 6.512 9.276 13.22 13.492 20.13l66.944-14.468 24.492 59.13-57.558 37.1c1.892 7.812 3.482 15.742 4.724 23.79l67.382 12.25zM672 468.8c-76.878 0-139.2 62.322-139.2 139.2s62.32 139.2 139.2 139.2 139.2-62.322 139.2-139.2c0-76.878-62.32-139.2-139.2-139.2z" />
|
||||
<glyph unicode="" d="M734.668 299.418l-141.21 161.382 141.21 161.382c24.014 24.014 24.014 62.926 0 86.886s-62.924 23.962-86.886 0l-135.782-155.186-135.73 155.136c-24.012 24.012-62.926 24.012-86.886 0s-23.962-62.926 0-86.886l141.158-161.332-141.21-161.382c-23.962-24.014-23.962-62.822 0-86.784 24.012-24.014 62.926-24.014 86.886 0l135.782 155.086 135.73-155.086c24.014-24.014 62.924-24.014 86.886 0s24.014 62.77 0.052 86.784z" />
|
||||
<glyph unicode="" d="M448 165.49l-205.254 237.254 58.508 58.51 146.746-114.744 274.744 242.744 58.512-58.508zM831.772 832c0.078-0.066 0.162-0.15 0.228-0.23v-767.542c-0.066-0.078-0.15-0.162-0.228-0.228h-639.544c-0.080 0.066-0.162 0.15-0.228 0.228v767.544c0.066 0.080 0.15 0.162 0.23 0.228h-128.23v-768c0-70.4 57.6-128 128-128h640c70.4 0 128 57.6 128 128v768h-128.228zM640 832v64c0 35.346-28.654 64-64 64h-128c-35.346 0-64-28.654-64-64v-64h-128v-128h512v128h-128zM576 832h-128v64h128v-64z" />
|
||||
<glyph unicode="" d="M128 682.666v128h896v-640h-128v-128h-896v640h128zM896 256h42.668v469.334h-725.332v-42.666h682.668v-426.668zM85.332 128h725.332v469.334h-725.332v-469.334z" />
|
||||
<glyph unicode="" d="M0 544v-192c0-17.672 14.328-32 32-32h960c17.672 0 32 14.328 32 32v192c0 17.672-14.328 32-32 32h-960c-17.672 0-32-14.328-32-32z" />
|
||||
<glyph unicode="" d="M576 711.628v248.372l384-384-384-384v253.824c-446.75 10.482-427.588-303.792-313.86-509.824-280.712 303.414-221.1 789.57 313.86 775.628z" />
|
||||
<glyph unicode="" d="M501.443 484.729c-119.819 31.143-158.353 63.078-158.353 113.223 0 57.535 53.047 97.916 142.518 97.916 93.957 0 128.794-44.867 131.961-110.848h116.654c-3.431 91.053-59.119 173.925-169.439 201.109v115.599h-158.353v-114.015c-102.402-22.433-184.746-88.413-184.746-190.553 0-121.933 101.082-182.636 248.086-217.999 132.225-31.671 158.353-77.856 158.353-127.474 0-36.159-25.601-94.219-142.518-94.219-108.736 0-151.755 48.826-157.297 110.848h-116.389c6.597-115.599 92.901-180.26 194.511-202.165v-114.544h158.353v113.487c102.667 19.794 184.746 79.178 184.746 187.65 0 149.38-128.266 200.581-248.086 231.987z" />
|
||||
<glyph unicode="" d="M384 448h-320v128h320v128l192-192-192-192zM1024 960v-832l-384-192v192h-384v256h64v-192h320v576l256 128h-576v-256h-64v320z" />
|
||||
<glyph unicode="" d="M768 320v128h-320v128h320v128l192-192zM704 384v-256h-320v-192l-384 192v832h704v-320h-64v256h-512l256-128v-576h256v192z" />
|
||||
<glyph unicode="" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM256 704h512c9.138 0 18.004-1.962 26.144-5.662l-282.144-329.168-282.144 329.17c8.14 3.696 17.006 5.66 26.144 5.66zM192 256v384c0 1.34 0.056 2.672 0.14 4l187.664-218.942-185.598-185.598c-1.444 5.336-2.206 10.886-2.206 16.54zM768 192h-512c-5.654 0-11.202 0.762-16.54 2.208l182.118 182.118 90.422-105.498 90.424 105.494 182.116-182.12c-5.34-1.44-10.886-2.202-16.54-2.202zM832 256c0-5.654-0.762-11.2-2.206-16.54l-185.6 185.598 187.666 218.942c0.084-1.328 0.14-2.66 0.14-4v-384z" />
|
||||
<glyph unicode="" d="M437.006 141.838c0-75.068-46.39-134.392-177.758-139.176-76.984 43.786-141.49 106.952-186.908 182.866 23.69 58.496 97.692 103.046 182.316 102.114 24.022-0.252 46.41-4.114 66.744-10.7 55.908-38.866 101-63.152 112.324-107.448 2.114-8.964 3.282-18.206 3.282-27.656zM512 960c-147.94 0-281.196-62.77-374.666-163.098 36.934 20.452 80.538 32.638 126.902 32.638 67.068 0 256.438 0 256.438 0l-57.304-60.14h-67.31c47.496-27.212 72.752-83.248 72.752-145.012 0-56.692-31.416-102.38-75.78-137.058-43.28-33.802-51.492-47.966-51.492-76.734 0-24.542 51.722-61.098 75.5-78.936 82.818-62.112 99.578-101.184 99.578-178.87 0-78.726-68.936-157.104-185.866-183.742 56.348-21.338 117.426-33.048 181.248-33.048 282.77 0 512 229.23 512 512s-229.23 512-512 512zM768 576v-128h-64v128h-128v64h128v128h64v-128h128v-64h-128zM365.768 620.528c11.922-90.776-27.846-149.19-96.934-147.134-69.126 2.082-134.806 65.492-146.74 156.242-11.928 90.788 34.418 160.254 103.53 158.196 69.090-2.074 128.22-76.542 140.144-167.304zM220.886 317.932c-74.68 0-138.128-25.768-182.842-63.864-24.502 59.82-38.044 125.29-38.044 193.932 0 56.766 9.256 111.368 26.312 162.396 7.374-99.442 77.352-176.192 192.97-176.192 8.514 0 16.764 0.442 24.874 1.022-7.95-15.23-13.622-32.19-13.622-49.982 0-29.97 16.488-47.070 36.868-66.894-15.402 0-30.27-0.418-46.516-0.418z" />
|
||||
<glyph unicode="" d="M512 960c282.77 0 512-229.23 512-512 0-261.094-195.438-476.53-448-508.026v380.026h176l16 128h-192v64c0 35.346 28.654 64 64 64h128v128h-128c-106.040 0-192-85.96-192-192v-64h-96v-128h96v-380.026c-252.562 31.496-448 246.932-448 508.026 0 282.77 229.23 512 512 512z" />
|
||||
<glyph unicode="" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM806.242 598.912c0.292-6.508 0.442-13.056 0.442-19.638 0-200.622-152.708-431.964-431.958-431.964-85.736 0-165.536 25.136-232.726 68.214 11.876-1.408 23.962-2.126 36.216-2.126 71.13 0 136.59 24.276 188.55 64.994-66.434 1.22-122.5 45.122-141.824 105.432 9.274-1.768 18.784-2.722 28.566-2.722 13.846 0 27.258 1.856 39.998 5.324-69.452 13.952-121.786 75.312-121.786 148.868 0 0.64 0 1.278 0.016 1.91 20.47-11.37 43.878-18.2 68.764-18.988-40.74 27.222-67.54 73.692-67.54 126.368 0 27.822 7.488 53.904 20.556 76.324 74.878-91.854 186.748-152.292 312.924-158.628-2.588 11.118-3.93 22.702-3.93 34.604 0 83.84 67.98 151.812 151.818 151.812 43.666 0 83.124-18.436 110.818-47.94 34.58 6.808 67.074 19.442 96.412 36.84-11.336-35.454-35.41-65.206-66.752-83.994 30.71 3.668 59.968 11.832 87.194 23.904-20.35-30.448-46.090-57.186-75.758-78.594z" />
|
||||
<glyph unicode="" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512 32c-229.75 0-416 186.25-416 416s186.25 416 416 416 416-186.25 416-416-186.25-416-416-416zM448 704h128v-128h-128zM640 192h-256v64h64v192h-64v64h192v-256h64z" />
|
||||
<glyph unicode="" d="M384 128h640v-128h-640zM384 512h640v-128h-640zM384 896h640v-128h-640zM192 960v-256h-64v192h-64v64zM128 434v-50h128v-64h-192v146l128 60v50h-128v64h192v-146zM256 256v-320h-192v64h128v64h-128v64h128v64h-128v64z" />
|
||||
<glyph unicode="" d="M864 256c-45.16 0-85.92-18.738-115.012-48.83l-431.004 215.502c1.314 8.252 2.016 16.706 2.016 25.328s-0.702 17.076-2.016 25.326l431.004 215.502c29.092-30.090 69.852-48.828 115.012-48.828 88.366 0 160 71.634 160 160s-71.634 160-160 160-160-71.634-160-160c0-8.622 0.704-17.076 2.016-25.326l-431.004-215.504c-29.092 30.090-69.852 48.83-115.012 48.83-88.366 0-160-71.636-160-160 0-88.368 71.634-160 160-160 45.16 0 85.92 18.738 115.012 48.828l431.004-215.502c-1.312-8.25-2.016-16.704-2.016-25.326 0-88.368 71.634-160 160-160s160 71.632 160 160c0 88.364-71.634 160-160 160z" />
|
||||
<glyph unicode="" d="M0 343.808l321.344-206.624v149.152l-191.328 118.144 191.328 118.144v150.176l-321.344-207.68v-121.312zM389.312 64h110.592l162.048 768h-111.328l-161.312-768zM702.688 672.8v-150.176l191.264-118.144-191.264-118.112v-149.152l321.312 206.592v121.312l-321.312 207.68z" />
|
||||
<glyph unicode="" d="M428.222 493.19c-144.194-6.656-260.742-83.888-260.742-180.224 0-96.202 116.574-168.528 260.742-161.792 144.302 6.576 261.094 96.876 261.094 193.078 0 96.12-116.79 155.594-261.094 148.938zM526.472 250.88c-44.168-56.994-131.53-84.802-216.36-38.858-40.394 21.908-38.884 64.916-38.884 64.916s-16.76 135.842 128.27 152.818c145.192 16.816 171.116-121.856 126.976-178.876zM429.19 341.854c-9.298-6.736-11.182-19.618-6.144-27.62 4.85-8.22 16.142-9.162 25.276-2.318 8.974 7.086 12.45 19.428 7.572 27.62-4.798 7.976-15.952 10.294-26.704 2.318zM360.448 323.154c-27.108-2.802-46.484-26.408-46.484-48.99 0-22.636 21.826-38.264 48.882-35.086 26.974 3.072 48.908 23.928 48.908 46.484 0.054 22.636-20.184 40.582-51.308 37.592zM868.082 960h-712.22c-86.096 0-155.89-69.794-155.89-155.89v-712.22c0-86.096 69.794-155.89 155.89-155.89h712.22c86.096 0 155.89 69.794 155.89 155.89v712.22c0 86.096-69.768 155.89-155.89 155.89zM818.202 280.386c-59.446-126.274-255.462-187.716-400.734-176.344-138.050 10.86-315.526 56.724-333.878 223.798 0 0-9.7 75.668 63.65 173.568 0 0 105.498 147.322 228.378 189.36 122.988 41.85 137.35-28.968 137.35-70.818-6.548-35.49-18.782-56.374 27.38-42.038 0 0 120.886 56.076 170.658 6.332 40.126-40.152 6.63-95.42 6.63-95.42s-16.654-18.404 17.624-25.034c34.358-6.872 142.362-56.914 82.944-183.404zM698.988 629.274c-13.15 0-23.714 10.644-23.714 23.688 0 13.286 10.562 23.956 23.714 23.956 0 0 148.212 27.404 130.48-131.852 0-0.942-0.108-1.698-0.322-2.534-1.672-11.29-11.586-19.94-23.256-19.94-13.204 0-23.956 10.562-23.956 23.74 0-0.026 23.498 106.416-82.944 82.944zM949.518 501.894h-0.216c-3.908-26.948-17.274-29.104-33.198-29.104-19.052 0-34.438 11.964-34.438 31.044 0 16.52 6.846 33.308 6.846 33.308 2.020 6.952 18.136 50.176-10.644 114.796-52.708 88.522-158.856 89.816-171.384 84.776-12.638-4.958-31.286-7.436-31.286-7.436-19.188 0-34.548 15.602-34.548 34.572 0 15.926 10.644 29.4 25.196 33.524 0 0 0.322 0.538 0.808 0.62 1.052 0.216 2.13 1.268 3.26 1.374 14.794 2.83 67.476 13.178 118.702 1.186 91.648-21.396 217.52-110.026 160.904-298.658z" />
|
||||
<glyph unicode="" d="M1023.972 804.11c0 86.096-69.794 155.89-155.89 155.89h-712.22c-86.096 0-155.89-69.794-155.89-155.89v-712.22c0-86.096 69.794-155.89 155.89-155.89h712.22c86.096 0 155.89 69.794 155.89 155.89v712.22zM133.524 60.794c1.024-12.316-8.218-43.952-20.562-43.952h-2.264c-11.426 0-21.18 28.24-22.284 39.962-17.058 190.14 42.982 344.172 96.66 423.692 19.32 28.916 39.128 52.708 57.074 71.626-4.474 10.24-6.98 21.558-6.98 33.524 0 46.216 37.646 83.592 83.86 83.592 46.484 0 83.7-37.376 83.7-83.592 0-46.51-37.24-83.86-83.7-83.86-17.838 0-34.276 5.632-47.94 15.092-15.872-16.95-33.064-47.884-49.746-73.054-71.114-106.442-100.892-241.986-87.82-383.030zM315.31 328.004c-19.080 0-38.4 2.102-56.832 6.198-12.18 2.884-19.43 15.010-16.924 26.894 2.938 12.26 14.794 19.832 26.892 16.976 15.226-3.504 31.016-5.202 46.86-5.202 114.878 0 208.194 93.32 208.194 207.926 0 114.634-93.32 207.952-208.194 207.952-114.606 0-208.088-93.318-208.088-207.952 0-33.254 7.6-65.268 22.824-94.856 5.848-10.94 1.482-24.522-9.862-30.1-11.076-5.902-24.414-1.536-30.154 9.566-18.296 35.382-27.756 75.508-27.756 115.362 0 139.534 113.474 253.036 253.036 253.036 139.642 0 253.196-113.502 253.196-253.036-0.028-139.292-113.582-252.766-253.198-252.766zM785.866 622.162c-22.42-0.486-45.218 4.204-65.698 13.932-71.464 34.008-101.996 119.726-67.988 191.272 33.9 71.49 119.726 101.996 191.272 67.988 71.49-33.874 102.024-119.836 67.852-191.112-4.958-9.836-10.428-19.212-17.14-27.674-4.23-5.47-12.45-6.466-17.948-2.102s-6.36 12.45-1.994 17.948c5.496 6.846 10.212 14.712 13.958 22.798 28.024 58.718 3.1 129.346-55.808 156.968-58.798 28.024-129.186 3.126-156.968-55.942-28.294-58.664-3.26-129.052 55.7-157.076 17.058-8.004 35.462-11.992 54.056-11.236 7.086 0.134 13.068-5.336 13.204-12.45 0.322-7.114-5.308-12.934-12.504-13.312zM1001.284 534.448c-0.162-0.648-0.432-0.862-0.432-1.24-2.938-5.9-9.674-8.73-16.062-6.466-101.538 37.484-155.972 101.026-183.646 147.86-9.944 16.95-17.164 33.038-22.42 46.7-6.576 0.162-12.854 1.886-18.782 4.5-24.064 11.454-34.062 39.614-22.69 63.408 11.21 23.688 39.478 33.792 63.272 22.42 23.688-11.318 33.658-39.64 22.582-63.272-4.366-9-11.346-16.194-19.482-20.696 5.012-12.476 11.48-26.302 20.318-40.986 37.16-62.41 94.316-108.168 169.58-135.924 6.71-2.614 9.972-9.702 7.76-16.302z" />
|
||||
<glyph unicode="" d="M512 768c0 0-128 128-512 128v-768c388 0 512-128 512-128s124 128 512 128v768c-384 0-512-128-512-128zM128 768c162.688-13.632 262.496-51.264 320-81.76v-515.488c-57.504 30.368-157.312 68-320 81.76v515.488zM896 252.512c-162.752-13.76-262.496-51.328-320-81.76v515.488c57.504 30.496 157.248 68.128 320 81.76v-515.488z" />
|
||||
<glyph unicode="" d="M1004.692 493.606l-447.096 447.080c-25.738 25.754-67.496 25.754-93.268 0l-103.882-103.876 78.17-78.17c12.532 5.996 26.564 9.36 41.384 9.36 53.020 0 96-42.98 96-96 0-14.82-3.364-28.854-9.362-41.386l127.976-127.974c12.532 5.996 26.566 9.36 41.386 9.36 53.020 0 96-42.98 96-96s-42.98-96-96-96-96 42.98-96 96c0 14.82 3.364 28.854 9.362 41.386l-127.976 127.974c-3.042-1.456-6.176-2.742-9.384-3.876v-266.968c37.282-13.182 64-48.718 64-90.516 0-53.020-42.98-96-96-96s-96 42.98-96 96c0 41.796 26.718 77.334 64 90.516v266.968c-37.282 13.18-64 48.72-64 90.516 0 14.82 3.364 28.852 9.36 41.384l-78.17 78.17-295.892-295.876c-25.75-25.776-25.75-67.534 0-93.288l447.12-447.080c25.738-25.75 67.484-25.75 93.268 0l445.006 445.006c25.758 25.762 25.758 67.54-0.002 93.29z" />
|
||||
<glyph unicode="" d="M1024 562.95l-353.78 51.408-158.22 320.582-158.216-320.582-353.784-51.408 256-249.538-60.432-352.352 316.432 166.358 316.432-166.358-60.434 352.352 256.002 249.538zM512 206.502l-223.462-117.48 42.676 248.83-180.786 176.222 249.84 36.304 111.732 226.396 111.736-226.396 249.836-36.304-180.788-176.222 42.678-248.83-223.462 117.48z" />
|
||||
<glyph unicode="" d="M512 960c-282.75 0-512-229.25-512-512 0-226.25 146.688-418.126 350.156-485.812 25.594-4.688 34.938 11.126 34.938 24.626 0 12.188-0.468 52.562-0.718 95.312-142.376-30.938-172.468 60.376-172.468 60.376-23.312 59.126-56.844 74.876-56.844 74.876-46.532 31.75 3.53 31.126 3.53 31.126 51.406-3.562 78.47-52.75 78.47-52.75 45.688-78.25 119.876-55.626 149-42.5 4.654 33 17.904 55.626 32.5 68.376-113.656 12.938-233.218 56.876-233.218 253.062 0 55.938 19.968 101.562 52.656 137.406-5.218 13-22.844 65.094 5.062 135.562 0 0 42.938 13.75 140.812-52.5 40.812 11.406 84.594 17.032 128.126 17.22 43.5-0.188 87.312-5.876 128.188-17.28 97.688 66.312 140.688 52.5 140.688 52.5 28-70.532 10.376-122.562 5.126-135.5 32.812-35.844 52.626-81.47 52.626-137.406 0-196.688-119.75-240-233.812-252.688 18.438-15.876 34.75-47 34.75-94.75 0-68.438-0.688-123.626-0.688-140.5 0-13.626 9.312-29.562 35.25-24.562 203.312 67.812 349.876 259.688 349.876 485.812 0 282.75-229.25 512-512 512z" />
|
||||
<glyph unicode="" d="M863.428 356.572q0-2.856-0.572-4-36.572-153.144-153.144-248.286t-273.142-95.144q-83.43 0-161.43 31.428t-139.144 89.714l-73.714-73.714q-10.856-10.856-25.714-10.856t-25.714 10.856-10.856 25.714v256q0 14.856 10.856 25.714t25.714 10.856h256q14.856 0 25.714-10.856t10.858-25.714-10.856-25.714l-78.286-78.286q40.57-37.714 92-58.286t106.858-20.572q76.572 0 142.856 37.144t106.286 102.286q6.286 9.714 30.286 66.856 4.572 13.144 17.144 13.144h109.714q7.428 0 12.856-5.428t5.428-12.856zM877.714 813.714v-256q0-14.856-10.856-25.714t-25.714-10.856h-256q-14.856 0-25.714 10.856t-10.856 25.714 10.856 25.714l78.856 78.856q-84.572 78.286-199.428 78.286-76.572 0-142.856-37.142t-106.286-102.286q-6.286-9.714-30.286-66.858-4.57-13.144-17.144-13.144h-113.714q-7.43 0-12.856 5.428t-5.43 12.856v4q37.144 153.144 154.286 248.286t274.286 95.142q83.428 0 162.286-31.714t140-89.428l74.286 73.714q10.856 10.856 25.714 10.856t25.714-10.856 10.856-25.714z" />
|
||||
<glyph unicode="" d="M684 374.856h-62.286q-14.856 0-25.714 10.856t-10.856 25.714v73.144q0 14.856 10.856 25.714t25.714 10.858h62.286q-18.286 61.714-64.286 107.714t-107.714 64.286v-62.286q0-14.858-10.858-25.714t-25.714-10.856h-73.142q-14.856 0-25.714 10.856t-10.858 25.714v62.286q-61.714-18.286-107.714-64.286t-64.286-107.714h62.286q14.858 0 25.714-10.856t10.856-25.714v-73.142q0-14.856-10.856-25.714t-25.714-10.856h-62.286q18.286-61.714 64.286-107.714t107.714-64.286v62.286q0 14.856 10.856 25.714t25.714 10.856h73.142q14.856 0 25.714-10.856t10.858-25.714v-62.286q61.714 18.286 107.714 64.286t64.286 107.714zM877.714 484.572v-73.144q0-14.856-10.856-25.714t-25.714-10.856h-81.714q-21.144-92-88.286-159.144t-159.144-88.286v-81.714q0-14.856-10.856-25.714t-25.714-10.856h-73.142q-14.856 0-25.714 10.856t-10.858 25.714v81.714q-92 21.144-159.144 88.286t-88.286 159.144h-81.714q-14.856 0-25.714 10.856t-10.856 25.714v73.144q0 14.856 10.856 25.714t25.714 10.858h81.714q21.144 92 88.286 159.144t159.144 88.286v81.714q0 14.856 10.856 25.714t25.714 10.856h73.142q14.856 0 25.714-10.856t10.858-25.714v-81.714q92-21.142 159.144-88.286t88.286-159.144h81.714q14.856 0 25.714-10.856t10.856-25.714z" />
|
||||
<glyph unicode="" d="M219.43 82.286h438.858v219.428h-438.858v-219.428zM731.428 82.286h73.144v512q0 8-5.714 22t-11.428 19.714l-160.572 160.57q-5.714 5.714-19.428 11.43t-22.286 5.714v-237.714q0-22.858-16-38.858t-38.856-16h-329.142q-22.856 0-38.856 16t-16 38.856v237.714h-73.144v-731.43h73.144v237.714q0 22.856 16 38.856t38.856 16h475.43q22.856 0 38.856-16t16-38.856v-237.714zM512 612.572v182.856q0 7.428-5.428 12.858t-12.856 5.428h-109.714q-7.428 0-12.858-5.428t-5.428-12.858v-182.856q0-7.428 5.428-12.856t12.856-5.428h109.714q7.428 0 12.858 5.428t5.428 12.856zM877.714 594.286v-530.286q0-22.856-16-38.856t-38.856-16h-768q-22.856 0-38.856 16t-16 38.856v768q0 22.856 16 38.856t38.856 16h530.286q22.856 0 50.286-11.428t43.428-27.428l160-160q16-16 27.428-43.428t11.428-50.286z" />
|
||||
<glyph unicode="" d="M731.429 420.571q0 8-5.143 13.143t-13.143 5.143h-128v201.143q0 7.429-5.429 12.857t-12.857 5.429h-109.714q-7.429 0-12.857-5.429t-5.429-12.857v-201.143h-128q-7.429 0-12.857-5.429t-5.429-12.857q0-8 5.143-13.143l201.143-201.143q5.143-5.143 13.143-5.143t13.143 5.143l200.571 200.571q5.714 6.857 5.714 13.714zM1097.143 292.571q0-90.857-64.286-155.143t-155.143-64.286h-621.714q-105.714 0-180.857 75.143t-75.143 180.857q0 74.286 40 137.143t107.429 94.286q-1.143 17.143-1.143 24.571 0 121.143 85.714 206.857t206.857 85.714q89.143 0 163.143-49.714t107.714-132q40.571 35.429 94.857 35.429 60.571 0 103.429-42.857t42.857-103.429q0-43.429-23.429-78.857 74.286-17.714 122-77.429t47.714-136.286z" horiz-adv-x="1097" />
|
||||
<glyph unicode="" d="M731.429 457.143q0 8-5.143 13.143l-201.143 201.143q-5.143 5.143-13.143 5.143t-13.143-5.143l-200.571-200.571q-5.714-6.857-5.714-13.714 0-8 5.143-13.143t13.143-5.143h128v-201.143q0-7.429 5.429-12.857t12.857-5.429h109.714q7.429 0 12.857 5.429t5.429 12.857v201.143h128q7.429 0 12.857 5.429t5.429 12.857zM1097.143 292.571q0-90.857-64.286-155.143t-155.143-64.286h-621.714q-105.714 0-180.857 75.143t-75.143 180.857q0 74.286 40 137.143t107.429 94.286q-1.143 17.143-1.143 24.571 0 121.143 85.714 206.857t206.857 85.714q89.143 0 163.143-49.714t107.714-132q40.571 35.429 94.857 35.429 60.571 0 103.429-42.857t42.857-103.429q0-43.429-23.429-78.857 74.286-17.714 122-77.429t47.714-136.286z" horiz-adv-x="1097" />
|
||||
<glyph unicode="" d="M219.429 283.428v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM292.571 429.714v-54.857q0-9.143-9.143-9.143h-128q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h128q9.143 0 9.143-9.143zM219.429 576v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM804.571 283.428v-54.857q0-9.143-9.143-9.143h-493.714q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h493.714q9.143 0 9.143-9.143zM438.857 429.714v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM365.714 576v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM585.143 429.714v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM512 576v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM731.429 429.714v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM950.857 283.428v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM658.286 576v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM804.571 576v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM950.857 576v-201.143q0-9.143-9.143-9.143h-128q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h64v137.143q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM1024 146.286v512h-950.857v-512h950.857zM1097.143 658.286v-512q0-30.286-21.429-51.714t-51.714-21.429h-950.857q-30.286 0-51.714 21.429t-21.429 51.714v512q0 30.286 21.429 51.714t51.714 21.429h950.857q30.286 0 51.714-21.429t21.429-51.714z" horiz-adv-x="1097" />
|
||||
<glyph unicode="" d="M581.714 606.286q-10.286-21.143-33.143-21.143h-109.714v-493.714q0-8-5.143-13.143t-13.143-5.143h-402.286q-12 0-16.571 10.286-4.571 11.429 2.286 20l91.429 109.714q5.143 6.286 14.286 6.286h182.857v365.714h-109.714q-22.857 0-33.143 21.143-9.714 21.143 5.143 38.857l182.857 219.429q10.286 12.571 28 12.571t28-12.571l182.857-219.429q15.429-18.286 5.143-38.857z" horiz-adv-x="585" />
|
||||
<glyph unicode="" d="M18.286 804.571h402.286q7.429 0 12.857-5.429t5.429-13.429v-493.143h109.714q22.857 0 33.143-21.143t-5.143-39.429l-182.857-219.429q-10.286-12.571-28-12.571t-28 12.571l-182.857 219.429q-14.857 17.714-5.143 39.429 10.286 21.143 33.143 21.143h109.714v365.714h-182.857q-8 0-14.286 6.286l-91.429 109.714q-7.429 8-2.286 19.429 5.143 10.857 16.571 10.857z" horiz-adv-x="585" />
|
||||
<glyph unicode=" " horiz-adv-x="512" d="" />
|
||||
<glyph unicode="" glyph-name="tree" horiz-adv-x="1170" d="M0 886.858c0 40.396 32.747 73.143 73.143 73.143s73.143-32.747 73.143-73.143c0-40.396-32.747-73.143-73.143-73.143s-73.143 32.747-73.143 73.143zM292.572 960h877.714v-146.286h-877.714zM292.572 594.286c0 40.396 32.747 73.143 73.143 73.143s73.143-32.747 73.143-73.143c0-40.396-32.747-73.143-73.143-73.143s-73.143 32.747-73.143 73.143zM585.142 667.428h585.144v-146.286h-585.144zM292.572 9.142c0 40.396 32.747 73.143 73.143 73.143s73.143-32.747 73.143-73.143c0-40.396-32.747-73.143-73.143-73.143s-73.143 32.747-73.143 73.143zM585.142 82.286h585.144v-146.286h-585.144zM585.142 301.714c0 40.396 32.747 73.143 73.143 73.143s73.143-32.747 73.143-73.143c0-40.396-32.747-73.143-73.143-73.143s-73.143 32.747-73.143 73.143zM877.714 374.858h292.572v-146.286h-292.572z" />
|
||||
<glyph unicode="" glyph-name="build" d="M1009.996 131.024l-301.544 301.544c-18.668 18.668-49.214 18.668-67.882 0l-22.626-22.626-184 184 302.056 302.058h-320l-142.058-142.058-14.060 14.058h-67.882v-67.882l14.058-14.058-206.058-206.060 160-160 206.058 206.058 184-184-22.626-22.626c-18.668-18.668-18.668-49.214 0-67.882l301.544-301.544c18.668-18.668 49.214-18.668 67.882 0l113.136 113.136c18.67 18.666 18.67 49.214 0.002 67.882z" />
|
||||
<glyph unicode="" glyph-name="find" d="M632.576 661.376c46.080-10.666 82.752-49.92 93.418-92.8 3.648-20.054 21.12-35.2 42.048-35.2 23.466 0 42.666 19.2 42.666 42.666 0 30.72-25.814 77.44-61.014 112.426-34.56 34.134-75.734 58.24-109.654 58.24-23.466 0-42.666-19.84-42.666-43.306 0.002-20.884 15.148-38.4 35.202-42.026zM46.122 102.016c-33.066-33.046-33.066-86.826 0-119.872 33.066-33.088 86.826-33.088 119.68 0l245.098 244.906c57.194-35.67 124.586-56.342 197.12-56.342 206.294 0 373.334 167.040 373.334 373.334s-167.040 373.334-373.334 373.334-373.334-167.040-373.334-373.334c0-72.32 20.714-139.946 56.342-197.12l-244.906-244.906zM341.376 544.042c0 147.2 119.488 266.666 266.666 266.666 147.2 0 266.666-119.466 266.666-266.666s-119.466-266.666-266.666-266.666c-147.178 0.022-266.666 119.488-266.666 266.666z" />
|
||||
<glyph unicode="" glyph-name="findfiles" d="M0 21.334c0-47.146 38.186-85.334 85.334-85.334h277.334c47.146 0 85.334 38.186 85.334 85.334l-0.002 341.332h128v-341.334c0-47.146 38.186-85.334 85.334-85.334h277.334c47.146 0 85.334 38.186 85.334 85.334l-0.002 554.668c0 47.146-38.186 85.334-85.334 85.334h-42.666v192h10.666c29.44 0 53.334 23.892 53.334 53.332s-23.894 53.334-53.334 53.334h-277.334c-29.438 0-53.332-23.894-53.332-53.334s23.894-53.332 53.334-53.332h10.666v-192h-256v192h10.666c29.44 0 53.334 23.892 53.334 53.332s-23.894 53.334-53.334 53.334h-277.334c-29.438 0-53.332-23.894-53.332-53.334s23.894-53.332 53.334-53.332h10.666v-192h-42.666c-47.146 0-85.334-38.186-85.334-85.334v-554.666zM554.666 469.334h-85.334c-23.466 0-42.666 19.2-42.666 42.666s19.2 42.666 42.666 42.666h85.334c23.466 0 42.666-19.2 42.666-42.666s-19.198-42.666-42.666-42.666z" />
|
||||
<glyph unicode="" glyph-name="editor" d="M118.634 528.918c-20.886-20.886-30.934-50.774-36.032-81.066l-81.322-384.428c-11.52-68.288 56.96-136.982 126.102-126.314l384.874 80.234c28.16 5.098 58.666 13.866 79.574 34.774l407.68 408.128c32.64 32.832 32.64 85.952 0 118.806l-356.054 356.48c-32.854 32.64-85.974 32.64-118.634 0l-406.188-406.614zM509.888 118.678l-199.254-38.208-165.12 165.334 37.952 199.488 296.768 297.174c16.426 16.448 42.88 16.448 59.306 0 16.448-16.426 16.448-43.094 0-59.52l-274.368-274.774c-20.48-20.48-20.48-53.782 0-74.218 20.48-20.502 53.546-20.502 74.026 0l274.582 274.774c16.448 16.426 42.88 16.426 59.306 0 16.448-16.448 16.448-42.902 0-59.306l-274.368-274.774c-20.48-20.48-20.48-53.782 0-74.24 20.48-20.48 53.568-20.48 74.026 0l274.582 274.774c16.234 16.234 42.902 16.234 59.328 0 16.426-16.426 16.426-43.094 0-59.498l-296.766-297.006z" />
|
||||
<glyph unicode="" glyph-name="report" d="M622.858 799.808l-22.032 110.158h-495.715v-936.349h110.158v385.556h308.443l22.032-110.158h385.556v550.795z" />
|
||||
<glyph unicode="" glyph-name="signup" d="M697.83 494.458c76.887 0 138.908 62.486 138.908 139.372s-62.021 139.372-138.908 139.372c-76.887 0-139.372-62.486-139.372-139.372s62.486-139.372 139.372-139.372zM326.17 494.458c76.887 0 138.908 62.486 138.908 139.372s-62.021 139.372-138.908 139.372c-76.887 0-139.372-62.486-139.372-139.372s62.486-139.372 139.372-139.372zM326.17 401.542c-108.479 0-325.203-54.355-325.203-162.601v-116.144h650.404v116.144c0 108.245-216.724 162.601-325.203 162.601zM697.83 401.542c-13.472 0-28.571-0.929-44.831-2.555 53.89-38.792 91.289-91.057 91.289-160.047v-116.144h278.744v116.144c0 108.245-216.724 162.601-325.203 162.601z" />
|
||||
<glyph unicode="" glyph-name="notification" d="M977.76 152.992l-400.608 685.952c-33.408 33.408-87.616 33.408-121.024 0l-400.64-685.952c-33.408-33.376-33.408-87.552 0-120.992h922.24c33.472 33.44 33.472 87.616 0.032 120.992zM479.744 592.704c0 26.528 21.504 48 48 48s48-21.472 48-48v-224c0-26.496-21.504-48-48-48s-48 21.504-48 48v224zM528.032 160.448c-26.496 0-48 21.44-48 48 0 26.496 21.504 48 48 48s48-21.504 48-48c0-26.56-21.504-48-48-48z" />
|
||||
<glyph unicode="" glyph-name="uniE608" horiz-adv-x="952" d="M438.928 896.072q14.856 0 25.714-10.856t10.858-25.714v-128h168l98.856 98.856q10.856 10.856 25.714 10.856t25.714-10.856 10.856-25.714-10.856-25.714l-98.856-98.856v-482.286l98.856-98.856q10.856-10.856 10.856-25.714t-10.856-25.714-25.714-10.856-25.714 10.856l-98.856 98.856h-168v-128q0-14.856-10.856-25.714t-25.714-10.856-25.714 10.856-10.856 25.714v128q-97.714 0-165.714 38.286l-119.43-118.856q-10.856-10.856-25.714-10.856t-25.714 10.856q-10.856 10.286-10.856 25.714t10.856 25.714l112.57 113.144q-2.856 2.856-7.43 8.572t-16.286 24-20.856 37.144-16.57 46.856-7.43 55.428h512v73.144h-512q0 29.144 7.714 58t18.856 49.714 22.286 37.714 18.57 24.856l8 8.572-118.286 104.57q-12 11.43-12 27.43 0 13.714 9.144 24.57 10.286 10.858 25.43 11.714t26.57-8.856l129.714-115.428q65.144 33.142 156.57 33.142v128q0 14.858 10.858 25.714t25.714 10.856zM768.072 621.786q76 0 129.428-53.428t53.428-129.428-53.428-129.428-129.428-53.428v365.714z" />
|
||||
<glyph unicode="" glyph-name="max" d="M1024 960v-384l-138.26 138.26-212-212-107.48 107.48 212 212-138.26 138.26zM245.74 821.74l212-212-107.48-107.48-212 212-138.26-138.26v384h384zM885.74 181.74l138.26 138.26v-384h-384l138.26 138.26-212 212 107.48 107.48zM457.74 286.26l-212-212 138.26-138.26h-384v384l138.26-138.26 212 212z" />
|
||||
<glyph unicode="" glyph-name="uniE60A" d="M64 384h384v-384l-138.26 138.26-202-202-107.48 107.48 202 202zM821.74 245.74l202-202-107.48-107.48-202 202-138.26-138.26v384h384zM960 512h-384v384l138.26-138.26 202 202 107.48-107.48-202-202zM309.74 757.74l138.26 138.26v-384h-384l138.26 138.26-202 202 107.48 107.48z" />
|
||||
<glyph unicode="" glyph-name="remove" d="M800 832h-576c-53.020 0-96-42.98-96-96v-32h768v32c0 53.020-42.98 96-96 96zM632.32 896l14.116-101h-268.872l14.114 101h240.642zM640 960h-256c-26.4 0-50.99-21.392-54.642-47.538l-18.714-133.924c-3.654-26.146 14.956-47.538 41.356-47.538h320c26.4 0 45.010 21.392 41.358 47.538l-18.714 133.924c-3.654 26.146-28.244 47.538-54.644 47.538v0zM816 640h-608c-35.2 0-61.392-28.682-58.206-63.738l52.412-576.526c3.186-35.054 34.594-63.736 69.794-63.736h480c35.2 0 66.608 28.682 69.794 63.736l52.41 576.526c3.188 35.056-23.004 63.738-58.204 63.738zM384 64h-96l-32 448h128v-448zM576 64h-128v448h128v-448zM736 64h-96v448h128l-32-448z" />
|
||||
<glyph unicode="" glyph-name="buildrun" d="M192 832l640-384-640-384z" />
|
||||
<glyph unicode="" glyph-name="about" d="M708.524 833.167c-54.823 39.545-123.584 59.295-206.423 59.295-63.041 0-116.185-13.935-159.382-41.708-68.567-43.534-104.989-117.434-109.41-221.702h158.852c0 30.367 8.841 59.629 26.572 87.787s47.81 42.236 90.238 42.236c43.101 0 72.844-11.436 89.084-34.26 16.289-22.92 24.41-48.242 24.41-76.015 0-24.169-12.108-46.272-26.714-66.405-8.024-11.726-18.644-22.488-31.759-32.387 0 0-86.154-55.258-124.016-99.657-21.959-25.755-23.929-64.291-25.851-119.598-0.144-3.94 1.346-12.059 15.136-12.059s111.332 0 123.584 0 14.8 9.083 14.991 13.069c0.865 20.133 3.123 30.416 6.823 42.044 6.967 21.959 25.803 41.129 47.042 57.614l43.726 30.176c39.447 30.752 70.97 55.978 84.855 75.775 23.738 32.578 40.409 72.651 40.409 120.171 0 77.601-27.437 136.126-82.166 175.623zM499.553 223.413c-54.777 1.633-99.944-36.231-101.672-95.619-1.73-59.342 41.227-98.549 96.004-100.184 57.18-1.682 101.145 34.981 102.875 94.322 1.682 59.39-40.026 99.8-97.205 101.481z" />
|
||||
<glyph unicode="" glyph-name="undo" d="M761.862-64c113.726 206.032 132.888 520.306-313.862 509.824v-253.824l-384 384 384 384v-248.372c534.962 13.942 594.57-472.214 313.862-775.628z" />
|
||||
<glyph unicode="" glyph-name="stop" d="M128 832h768v-768h-768z" />
|
||||
<glyph unicode="" glyph-name="close" d="M734.668 299.418l-141.21 161.382 141.21 161.382c24.014 24.014 24.014 62.926 0 86.886s-62.924 23.962-86.886 0l-135.782-155.186-135.73 155.136c-24.012 24.012-62.926 24.012-86.886 0s-23.962-62.926 0-86.886l141.158-161.332-141.21-161.382c-23.962-24.014-23.962-62.822 0-86.784 24.012-24.014 62.926-24.014 86.886 0l135.782 155.086 135.73-155.086c24.014-24.014 62.924-24.014 86.886 0s24.014 62.77 0.052 86.784z" />
|
||||
<glyph unicode="" glyph-name="format" d="M448 165.49l-205.254 237.254 58.508 58.51 146.746-114.744 274.744 242.744 58.512-58.508zM831.772 832c0.078-0.066 0.162-0.15 0.228-0.23v-767.542c-0.066-0.078-0.15-0.162-0.228-0.228h-639.544c-0.080 0.066-0.162 0.15-0.228 0.228v767.544c0.066 0.080 0.15 0.162 0.23 0.228h-128.23v-768c0-70.4 57.6-128 128-128h640c70.4 0 128 57.6 128 128v768h-128.228zM640 832v64c0 35.346-28.654 64-64 64h-128c-35.346 0-64-28.654-64-64v-64h-128v-128h512v128h-128zM576 832h-128v64h128v-64z" />
|
||||
<glyph unicode="" glyph-name="restore" d="M128 682.666v128h896v-640h-128v-128h-896v640h128zM896 256h42.668v469.334h-725.332v-42.666h682.668v-426.668zM85.332 128h725.332v469.334h-725.332v-469.334z" />
|
||||
<glyph unicode="" glyph-name="min" d="M0 544v-192c0-17.672 14.328-32 32-32h960c17.672 0 32 14.328 32 32v192c0 17.672-14.328 32-32 32h-960c-17.672 0-32-14.328-32-32z" />
|
||||
<glyph unicode="" glyph-name="redo" d="M576 711.628v248.372l384-384-384-384v253.824c-446.75 10.482-427.588-303.792-313.86-509.824-280.712 303.414-221.1 789.57 313.86 775.628z" />
|
||||
<glyph unicode="" glyph-name="price" d="M501.443 506.062c-119.819 31.143-158.353 63.078-158.353 113.223 0 57.535 53.047 97.916 142.518 97.916 93.957 0 128.794-44.867 131.961-110.848h116.654c-3.431 91.053-59.119 173.925-169.439 201.109v115.599h-158.353v-114.015c-102.402-22.433-184.746-88.413-184.746-190.553 0-121.933 101.082-182.636 248.086-217.999 132.225-31.671 158.353-77.856 158.353-127.474 0-36.159-25.601-94.219-142.518-94.219-108.736 0-151.755 48.826-157.297 110.848h-116.389c6.597-115.599 92.901-180.26 194.511-202.165v-114.544h158.353v113.487c102.667 19.794 184.746 79.178 184.746 187.65 0 149.38-128.266 200.581-248.086 231.987z" />
|
||||
<glyph unicode="" glyph-name="uniE617" d="M384 448h-320v128h320v128l192-192-192-192zM1024 960v-832l-384-192v192h-384v256h64v-192h320v576l256 128h-576v-256h-64v320z" />
|
||||
<glyph unicode="" glyph-name="signout" d="M768 320v128h-320v128h320v128l192-192zM704 384v-256h-320v-192l-384 192v832h704v-320h-64v256h-512l256-128v-576h256v192z" />
|
||||
<glyph unicode="" glyph-name="email" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM256 704h512c9.138 0 18.004-1.962 26.144-5.662l-282.144-329.168-282.144 329.17c8.14 3.696 17.006 5.66 26.144 5.66zM192 256v384c0 1.34 0.056 2.672 0.14 4l187.664-218.942-185.598-185.598c-1.444 5.336-2.206 10.886-2.206 16.54zM768 192h-512c-5.654 0-11.202 0.762-16.54 2.208l182.118 182.118 90.422-105.498 90.424 105.494 182.116-182.12c-5.34-1.44-10.886-2.202-16.54-2.202zM832 256c0-5.654-0.762-11.2-2.206-16.54l-185.6 185.598 187.666 218.942c0.084-1.328 0.14-2.66 0.14-4v-384z" />
|
||||
<glyph unicode="" glyph-name="googleplus" d="M437.006 141.838c0-75.068-46.39-134.392-177.758-139.176-76.984 43.786-141.49 106.952-186.908 182.866 23.69 58.496 97.692 103.046 182.316 102.114 24.022-0.252 46.41-4.114 66.744-10.7 55.908-38.866 101-63.152 112.324-107.448 2.114-8.964 3.282-18.206 3.282-27.656zM512 960c-147.94 0-281.196-62.77-374.666-163.098 36.934 20.452 80.538 32.638 126.902 32.638 67.068 0 256.438 0 256.438 0l-57.304-60.14h-67.31c47.496-27.212 72.752-83.248 72.752-145.012 0-56.692-31.416-102.38-75.78-137.058-43.28-33.802-51.492-47.966-51.492-76.734 0-24.542 51.722-61.098 75.5-78.936 82.818-62.112 99.578-101.184 99.578-178.87 0-78.726-68.936-157.104-185.866-183.742 56.348-21.338 117.426-33.048 181.248-33.048 282.77 0 512 229.23 512 512s-229.23 512-512 512zM768 576v-128h-64v128h-128v64h128v128h64v-128h128v-64h-128zM365.768 620.528c11.922-90.776-27.846-149.19-96.934-147.134-69.126 2.082-134.806 65.492-146.74 156.242-11.928 90.788 34.418 160.254 103.53 158.196 69.090-2.074 128.22-76.542 140.144-167.304zM220.886 317.932c-74.68 0-138.128-25.768-182.842-63.864-24.502 59.82-38.044 125.29-38.044 193.932 0 56.766 9.256 111.368 26.312 162.396 7.374-99.442 77.352-176.192 192.97-176.192 8.514 0 16.764 0.442 24.874 1.022-7.95-15.23-13.622-32.19-13.622-49.982 0-29.97 16.488-47.070 36.868-66.894-15.402 0-30.27-0.418-46.516-0.418z" />
|
||||
<glyph unicode="" glyph-name="facebook" d="M512 960c282.77 0 512-229.23 512-512 0-261.094-195.438-476.53-448-508.026v380.026h176l16 128h-192v64c0 35.346 28.654 64 64 64h128v128h-128c-106.040 0-192-85.96-192-192v-64h-96v-128h96v-380.026c-252.562 31.496-448 246.932-448 508.026 0 282.77 229.23 512 512 512z" />
|
||||
<glyph unicode="" glyph-name="twitter" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM806.242 598.912c0.292-6.508 0.442-13.056 0.442-19.638 0-200.622-152.708-431.964-431.958-431.964-85.736 0-165.536 25.136-232.726 68.214 11.876-1.408 23.962-2.126 36.216-2.126 71.13 0 136.59 24.276 188.55 64.994-66.434 1.22-122.5 45.122-141.824 105.432 9.274-1.768 18.784-2.722 28.566-2.722 13.846 0 27.258 1.856 39.998 5.324-69.452 13.952-121.786 75.312-121.786 148.868 0 0.64 0 1.278 0.016 1.91 20.47-11.37 43.878-18.2 68.764-18.988-40.74 27.222-67.54 73.692-67.54 126.368 0 27.822 7.488 53.904 20.556 76.324 74.878-91.854 186.748-152.292 312.924-158.628-2.588 11.118-3.93 22.702-3.93 34.604 0 83.84 67.98 151.812 151.818 151.812 43.666 0 83.124-18.436 110.818-47.94 34.58 6.808 67.074 19.442 96.412 36.84-11.336-35.454-35.41-65.206-66.752-83.994 30.71 3.668 59.968 11.832 87.194 23.904-20.35-30.448-46.090-57.186-75.758-78.594z" />
|
||||
<glyph unicode="" glyph-name="info" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512 32c-229.75 0-416 186.25-416 416s186.25 416 416 416 416-186.25 416-416-186.25-416-416-416zM448 704h128v-128h-128zM640 192h-256v64h64v192h-64v64h192v-256h64z" />
|
||||
<glyph unicode="" glyph-name="goline" d="M384 128h640v-128h-640zM384 512h640v-128h-640zM384 896h640v-128h-640zM192 960v-256h-64v192h-64v64zM128 434v-50h128v-64h-192v146l128 60v50h-128v64h192v-146zM256 256v-320h-192v64h128v64h-128v64h128v64h-128v64z" />
|
||||
<glyph unicode="" glyph-name="share" d="M864 256c-45.16 0-85.92-18.738-115.012-48.83l-431.004 215.502c1.314 8.252 2.016 16.706 2.016 25.328s-0.702 17.076-2.016 25.326l431.004 215.502c29.092-30.090 69.852-48.828 115.012-48.828 88.366 0 160 71.634 160 160s-71.634 160-160 160-160-71.634-160-160c0-8.622 0.704-17.076 2.016-25.326l-431.004-215.504c-29.092 30.090-69.852 48.83-115.012 48.83-88.366 0-160-71.636-160-160 0-88.368 71.634-160 160-160 45.16 0 85.92 18.738 115.012 48.828l431.004-215.502c-1.312-8.25-2.016-16.704-2.016-25.326 0-88.368 71.634-160 160-160s160 71.632 160 160c0 88.364-71.634 160-160 160z" />
|
||||
<glyph unicode="" glyph-name="comment" d="M0 343.808l321.344-206.624v149.152l-191.328 118.144 191.328 118.144v150.176l-321.344-207.68v-121.312zM389.312 64h110.592l162.048 768h-111.328l-161.312-768zM702.688 672.8v-150.176l191.264-118.144-191.264-118.112v-149.152l321.312 206.592v121.312l-321.312 207.68z" />
|
||||
<glyph unicode="" glyph-name="weibo" d="M428.222 493.19c-144.194-6.656-260.742-83.888-260.742-180.224 0-96.202 116.574-168.528 260.742-161.792 144.302 6.576 261.094 96.876 261.094 193.078 0 96.12-116.79 155.594-261.094 148.938zM526.472 250.88c-44.168-56.994-131.53-84.802-216.36-38.858-40.394 21.908-38.884 64.916-38.884 64.916s-16.76 135.842 128.27 152.818c145.192 16.816 171.116-121.856 126.976-178.876zM429.19 341.854c-9.298-6.736-11.182-19.618-6.144-27.62 4.85-8.22 16.142-9.162 25.276-2.318 8.974 7.086 12.45 19.428 7.572 27.62-4.798 7.976-15.952 10.294-26.704 2.318zM360.448 323.154c-27.108-2.802-46.484-26.408-46.484-48.99 0-22.636 21.826-38.264 48.882-35.086 26.974 3.072 48.908 23.928 48.908 46.484 0.054 22.636-20.184 40.582-51.308 37.592zM868.082 960h-712.22c-86.096 0-155.89-69.794-155.89-155.89v-712.22c0-86.096 69.794-155.89 155.89-155.89h712.22c86.096 0 155.89 69.794 155.89 155.89v712.22c0 86.096-69.768 155.89-155.89 155.89zM818.202 280.386c-59.446-126.274-255.462-187.716-400.734-176.344-138.050 10.86-315.526 56.724-333.878 223.798 0 0-9.7 75.668 63.65 173.568 0 0 105.498 147.322 228.378 189.36 122.988 41.85 137.35-28.968 137.35-70.818-6.548-35.49-18.782-56.374 27.38-42.038 0 0 120.886 56.076 170.658 6.332 40.126-40.152 6.63-95.42 6.63-95.42s-16.654-18.404 17.624-25.034c34.358-6.872 142.362-56.914 82.944-183.404zM698.988 629.274c-13.15 0-23.714 10.644-23.714 23.688 0 13.286 10.562 23.956 23.714 23.956 0 0 148.212 27.404 130.48-131.852 0-0.942-0.108-1.698-0.322-2.534-1.672-11.29-11.586-19.94-23.256-19.94-13.204 0-23.956 10.562-23.956 23.74 0-0.026 23.498 106.416-82.944 82.944zM949.518 501.894h-0.216c-3.908-26.948-17.274-29.104-33.198-29.104-19.052 0-34.438 11.964-34.438 31.044 0 16.52 6.846 33.308 6.846 33.308 2.020 6.952 18.136 50.176-10.644 114.796-52.708 88.522-158.856 89.816-171.384 84.776-12.638-4.958-31.286-7.436-31.286-7.436-19.188 0-34.548 15.602-34.548 34.572 0 15.926 10.644 29.4 25.196 33.524 0 0 0.322 0.538 0.808 0.62 1.052 0.216 2.13 1.268 3.26 1.374 14.794 2.83 67.476 13.178 118.702 1.186 91.648-21.396 217.52-110.026 160.904-298.658z" />
|
||||
<glyph unicode="" glyph-name="book" d="M512 768c0 0-128 128-512 128v-768c388 0 512-128 512-128s124 128 512 128v768c-384 0-512-128-512-128zM128 768c162.688-13.632 262.496-51.264 320-81.76v-515.488c-57.504 30.368-157.312 68-320 81.76v515.488zM896 252.512c-162.752-13.76-262.496-51.328-320-81.76v515.488c57.504 30.496 157.248 68.128 320 81.76v-515.488z" />
|
||||
<glyph unicode="" glyph-name="git" d="M1004.692 493.606l-447.096 447.080c-25.738 25.754-67.496 25.754-93.268 0l-103.882-103.876 78.17-78.17c12.532 5.996 26.564 9.36 41.384 9.36 53.020 0 96-42.98 96-96 0-14.82-3.364-28.854-9.362-41.386l127.976-127.974c12.532 5.996 26.566 9.36 41.386 9.36 53.020 0 96-42.98 96-96s-42.98-96-96-96-96 42.98-96 96c0 14.82 3.364 28.854 9.362 41.386l-127.976 127.974c-3.042-1.456-6.176-2.742-9.384-3.876v-266.968c37.282-13.182 64-48.718 64-90.516 0-53.020-42.98-96-96-96s-96 42.98-96 96c0 41.796 26.718 77.334 64 90.516v266.968c-37.282 13.18-64 48.72-64 90.516 0 14.82 3.364 28.852 9.36 41.384l-78.17 78.17-295.892-295.876c-25.75-25.776-25.75-67.534 0-93.288l447.12-447.080c25.738-25.75 67.484-25.75 93.268 0l445.006 445.006c25.758 25.762 25.758 67.54-0.002 93.29z" />
|
||||
<glyph unicode="" glyph-name="qqz" d="M761.562 521.546l-305.314-229.928s122.534-19.085 307.335-16.875l-8.413 38.021 263.313 239.505c4.84 4.404 6.694 11.413 4.708 17.804-1.974 6.394-7.405 10.93-13.783 11.494l-347.126 31.289-135.62 336.932c-2.479 6.184-8.268 10.213-14.657 10.213-6.397 0-12.184-4.029-14.665-10.213l-135.621-336.932-347.128-31.289c-6.374-0.563-11.801-5.1-13.781-11.494-1.987-6.392-0.13-13.401 4.713-17.804l263.31-239.505-78.925-356.295c-1.445-6.521 0.962-13.347 6.142-17.317 5.196-3.9 12.107-4.202 17.608-0.752l298.345 188.885 298.347-188.885c2.554-1.655 5.395-2.401 8.235-2.401 3.299 0 6.583 1.049 9.366 3.146 5.182 3.98 7.593 10.803 6.149 17.325l-62.412 281.762c26.77 14.131 56.254 38.051 56.254 38.051s-116.838-59.919-536.289-30.65l303.994 231.311s-11.952 19.514-392.923 33.442c-25.494 0.938 310.6 66.909 558.84 11.159z" />
|
||||
<glyph unicode="" glyph-name="start" d="M1024 562.95l-353.78 51.408-158.22 320.582-158.216-320.582-353.784-51.408 256-249.538-60.432-352.352 316.432 166.358 316.432-166.358-60.434 352.352 256.002 249.538zM512 206.502l-223.462-117.48 42.676 248.83-180.786 176.222 249.84 36.304 111.732 226.396 111.736-226.396 249.836-36.304-180.788-176.222 42.678-248.83-223.462 117.48z" />
|
||||
<glyph unicode="" glyph-name="github" d="M512 960c-282.75 0-512-229.25-512-512 0-226.25 146.688-418.126 350.156-485.812 25.594-4.688 34.938 11.126 34.938 24.626 0 12.188-0.468 52.562-0.718 95.312-142.376-30.938-172.468 60.376-172.468 60.376-23.312 59.126-56.844 74.876-56.844 74.876-46.532 31.75 3.53 31.126 3.53 31.126 51.406-3.562 78.47-52.75 78.47-52.75 45.688-78.25 119.876-55.626 149-42.5 4.654 33 17.904 55.626 32.5 68.376-113.656 12.938-233.218 56.876-233.218 253.062 0 55.938 19.968 101.562 52.656 137.406-5.218 13-22.844 65.094 5.062 135.562 0 0 42.938 13.75 140.812-52.5 40.812 11.406 84.594 17.032 128.126 17.22 43.5-0.188 87.312-5.876 128.188-17.28 97.688 66.312 140.688 52.5 140.688 52.5 28-70.532 10.376-122.562 5.126-135.5 32.812-35.844 52.626-81.47 52.626-137.406 0-196.688-119.75-240-233.812-252.688 18.438-15.876 34.75-47 34.75-94.75 0-68.438-0.688-123.626-0.688-140.5 0-13.626 9.312-29.562 35.25-24.562 203.312 67.812 349.876 259.688 349.876 485.812 0 282.75-229.25 512-512 512z" />
|
||||
<glyph unicode="" glyph-name="refresh" d="M863.428 356.572q0-2.856-0.572-4-36.572-153.144-153.144-248.286t-273.142-95.144q-83.43 0-161.43 31.428t-139.144 89.714l-73.714-73.714q-10.856-10.856-25.714-10.856t-25.714 10.856-10.856 25.714v256q0 14.856 10.856 25.714t25.714 10.856h256q14.856 0 25.714-10.856t10.858-25.714-10.856-25.714l-78.286-78.286q40.57-37.714 92-58.286t106.858-20.572q76.572 0 142.856 37.144t106.286 102.286q6.286 9.714 30.286 66.856 4.572 13.144 17.144 13.144h109.714q7.428 0 12.856-5.428t5.428-12.856zM877.714 813.714v-256q0-14.856-10.856-25.714t-25.714-10.856h-256q-14.856 0-25.714 10.856t-10.856 25.714 10.856 25.714l78.856 78.856q-84.572 78.286-199.428 78.286-76.572 0-142.856-37.142t-106.286-102.286q-6.286-9.714-30.286-66.858-4.57-13.144-17.144-13.144h-113.714q-7.43 0-12.856 5.428t-5.43 12.856v4q37.144 153.144 154.286 248.286t274.286 95.142q83.428 0 162.286-31.714t140-89.428l74.286 73.714q10.856 10.856 25.714 10.856t25.714-10.856 10.856-25.714z" />
|
||||
<glyph unicode="" glyph-name="save" d="M219.43 82.286h438.858v219.428h-438.858v-219.428zM731.428 82.286h73.144v512q0 8-5.714 22t-11.428 19.714l-160.572 160.57q-5.714 5.714-19.428 11.43t-22.286 5.714v-237.714q0-22.858-16-38.858t-38.856-16h-329.142q-22.856 0-38.856 16t-16 38.856v237.714h-73.144v-731.43h73.144v237.714q0 22.856 16 38.856t38.856 16h475.43q22.856 0 38.856-16t16-38.856v-237.714zM512 612.572v182.856q0 7.428-5.428 12.858t-12.856 5.428h-109.714q-7.428 0-12.858-5.428t-5.428-12.858v-182.856q0-7.428 5.428-12.856t12.856-5.428h109.714q7.428 0 12.858 5.428t5.428 12.856zM877.714 594.286v-530.286q0-22.856-16-38.856t-38.856-16h-768q-22.856 0-38.856 16t-16 38.856v768q0 22.856 16 38.856t38.856 16h530.286q22.856 0 50.286-11.428t43.428-27.428l160-160q16-16 27.428-43.428t11.428-50.286z" />
|
||||
<glyph unicode="" glyph-name="export" horiz-adv-x="1097" d="M731.429 429.714q0 8-5.143 13.143t-13.143 5.143h-128v201.143q0 7.429-5.429 12.857t-12.857 5.429h-109.714q-7.429 0-12.857-5.429t-5.429-12.857v-201.143h-128q-7.429 0-12.857-5.429t-5.429-12.857q0-8 5.143-13.143l201.143-201.143q5.143-5.143 13.143-5.143t13.143 5.143l200.571 200.571q5.714 6.857 5.714 13.714zM1097.143 301.714q0-90.857-64.286-155.143t-155.143-64.286h-621.714q-105.714 0-180.857 75.143t-75.143 180.857q0 74.286 40 137.143t107.429 94.286q-1.143 17.143-1.143 24.571 0 121.143 85.714 206.857t206.857 85.714q89.143 0 163.143-49.714t107.714-132q40.571 35.429 94.857 35.429 60.571 0 103.429-42.857t42.857-103.429q0-43.429-23.429-78.857 74.286-17.714 122-77.429t47.714-136.286z" />
|
||||
<glyph unicode="" glyph-name="import" horiz-adv-x="1097" d="M731.429 466.286q0 8-5.143 13.143l-201.143 201.143q-5.143 5.143-13.143 5.143t-13.143-5.143l-200.571-200.571q-5.714-6.857-5.714-13.714 0-8 5.143-13.143t13.143-5.143h128v-201.143q0-7.429 5.429-12.857t12.857-5.429h109.714q7.429 0 12.857 5.429t5.429 12.857v201.143h128q7.429 0 12.857 5.429t5.429 12.857zM1097.143 301.714q0-90.857-64.286-155.143t-155.143-64.286h-621.714q-105.714 0-180.857 75.143t-75.143 180.857q0 74.286 40 137.143t107.429 94.286q-1.143 17.143-1.143 24.571 0 121.143 85.714 206.857t206.857 85.714q89.143 0 163.143-49.714t107.714-132q40.571 35.429 94.857 35.429 60.571 0 103.429-42.857t42.857-103.429q0-43.429-23.429-78.857 74.286-17.714 122-77.429t47.714-136.286z" />
|
||||
<glyph unicode="" glyph-name="keyboard" horiz-adv-x="1097" d="M219.429 292.571v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM292.571 438.857v-54.857q0-9.143-9.143-9.143h-128q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h128q9.143 0 9.143-9.143zM219.429 585.143v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM804.571 292.571v-54.857q0-9.143-9.143-9.143h-493.714q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h493.714q9.143 0 9.143-9.143zM438.857 438.857v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM365.714 585.143v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM585.143 438.857v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM512 585.143v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM731.429 438.857v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM950.857 292.571v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM658.286 585.143v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM804.571 585.143v-54.857q0-9.143-9.143-9.143h-54.857q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM950.857 585.143v-201.143q0-9.143-9.143-9.143h-128q-9.143 0-9.143 9.143v54.857q0 9.143 9.143 9.143h64v137.143q0 9.143 9.143 9.143h54.857q9.143 0 9.143-9.143zM1024 155.429v512h-950.857v-512h950.857zM1097.143 667.429v-512q0-30.286-21.429-51.714t-51.714-21.429h-950.857q-30.286 0-51.714 21.429t-21.429 51.714v512q0 30.286 21.429 51.714t51.714 21.429h950.857q30.286 0 51.714-21.429t21.429-51.714z" />
|
||||
<glyph unicode="" glyph-name="moveup" horiz-adv-x="585" d="M580.891 578.932q-10.269-21.109-33.090-21.109h-109.537v-492.917q0-7.987-5.135-13.122t-13.122-5.135h-401.637q-11.981 0-16.544 10.269-4.564 11.411 2.282 19.968l91.282 109.537q5.135 6.276 14.263 6.276h182.562v365.124h-109.537q-22.82 0-33.090 21.109-9.698 21.109 5.135 38.794l182.562 219.075q10.269 12.551 27.955 12.551t27.955-12.551l182.562-219.075q15.404-18.257 5.135-38.794z" />
|
||||
<glyph unicode="" glyph-name="movedown" horiz-adv-x="585" d="M18.286 813.714h402.286q7.429 0 12.857-5.429t5.429-13.429v-493.143h109.714q22.857 0 33.143-21.143t-5.143-39.429l-182.857-219.429q-10.286-12.571-28-12.571t-28 12.571l-182.857 219.429q-14.857 17.714-5.143 39.429 10.286 21.143 33.143 21.143h109.714v365.714h-182.857q-8 0-14.286 6.286l-91.429 109.714q-7.429 8-2.286 19.429 5.143 10.857 16.571 10.857z" />
|
||||
</font></defs></svg>
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 28 KiB |
Binary file not shown.
Binary file not shown.
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.dialog-close-icon,.dialog-close-icon:hover{text-decoration:none}.dialog-background{height:100%;left:0;opacity:.3;position:absolute;top:0;width:100%;filter:alpha(opacity=30);display:none;background-color:#000;z-index:99}.dialog-panel{position:absolute;z-index:100;display:none;-moz-user-select:none;user-select:none;box-shadow:0 2px 10px 1px #000}.dialog-title{float:left;line-height:22px;margin-left:3px;font-weight:700}.dialog-header-bg{height:23px;background-color:#bbb;cursor:move;width:100%}.dialog-close-icon{float:right;margin:3px}.dialog-main>div{width:100%}.dialog-footer{padding:10px;text-align:right}#dialogCloseEditor button,.dialog-footer button{margin:0 5px}#dialogAlert,#dialogRemoveConfirm,.dialog-form,.dialog-prompt{padding:10px 15px 0;overflow:hidden}.dialog-main input,.dialog-main select{width:100%;margin:2px auto}#dialogGoFilePrompt>ul{position:relative;height:260px;overflow:auto;margin-top:5px;background-color:#FFF;border:1px solid #919191}#dialogPreference{margin:10px}#dialogPreference .tabs-panel{padding:10px}#dialogPreference .preference{margin-bottom:10px}#dialogPreference img.gravatar{width:48px;height:48px}
|
||||
body,ul{margin:0}body,button,input{font-family:Helvetica}.list li,body{overflow:hidden}::-webkit-scrollbar{background:0 0;width:16px;height:16px}::-webkit-scrollbar-corner{display:none;background-color:transparent}::-webkit-scrollbar-thumb{border:0 solid transparent;border-right-width:4px;border-left-width:4px;border-radius:9px;box-shadow:inset 0 0 0 1px rgba(128,128,128,.2),inset 0 0 0 4px rgba(128,128,128,.2)}::-webkit-scrollbar-thumb:horizontal{border-bottom-width:4px;border-top-width:4px}body{font-size:13px;color:#000}ul{padding:0;list-style:none}*{box-sizing:border-box}a{color:#4183c4;text-decoration:none}a:hover{text-decoration:underline}img{vertical-align:middle}.fn-left{float:left}.fn-right{float:right}.fn-clear:after,.fn-clear:before{display:table;content:""}.fn-clear:after{clear:both}.fn-none{display:none}.ft-small{color:#999;font-size:12px}.ft-red{color:#9d0000}.list li{cursor:pointer;line-height:20px;padding:0 3px;word-wrap:normal;word-break:normal;white-space:nowrap;text-overflow:ellipsis}.list li.selected,.list li:hover{background-color:#3875d7;color:#FFF}.list li.selected .ft-small,.list li:hover .ft-small{color:#FFF}@font-face{font-family:icomoon;src:url(fonts/icomoon.eot?35cb2z);src:url(fonts/icomoon.eot?#iefix35cb2z) format('embedded-opentype'),url(fonts/icomoon.woff?35cb2z) format('woff'),url(fonts/icomoon.ttf?35cb2z) format('truetype'),url(fonts/icomoon.svg?35cb2z#icomoon) format('svg');font-weight:400;font-style:normal}.font-ico,[class^=ico-]{font-family:icomoon;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;cursor:pointer;font-size:13px;line-height:20px}.ico-book:before{content:"\e623"}.ico-price:before{content:"\e616"}.ico-start:before{content:"\e9d7"}.ico-share:before{content:"\e61f"}.ico-github:before{content:"\f00a"}.ico-git:before{content:"\e624"}.ico-tencent:before{content:"\e622"}.ico-weibo:before{content:"\e621"}.ico-googleplus:before{content:"\e61a"}.ico-twitter:before{content:"\e61c"}.ico-email:before{content:"\e619"}.ico-facebook:before{content:"\e61b"}.ico-moveup:before{content:"\f148"}.ico-movedown:before{content:"\f149"}.ico-keyboard:before{content:"\f11c"}.ico-findfiles:before{content:"\e603"}.ico-find:before{content:"\e602"}.ico-editor:before{content:"\e604"}.ico-tree:before{content:"\e600"}.ico-build:before{content:"\e601"}.ico-notification:before{content:"\e607"}.ico-report:before{content:"\e605"}.ico-comment:before{content:"\e620"}.ico-goline:before{content:"\e61e"}.ico-info:before{content:"\e61d"}.ico-signup:before{content:"\e606"}.ico-signout:before{content:"\e618"}.ico-redo:before{content:"\e615"}.ico-undo:before{content:"\e60e"}.ico-about:before{content:"\e60d"}.ico-import:before{content:"\f0ee"}.ico-export:before{content:"\f0ed"}.ico-refresh:before{content:"\f021"}.ico-remove:before{content:"\e60b"}.ico-save:before{content:"\f0c7"}.ico-max:before{content:"\e609"}.ico-format:before{content:"\e612"}.ico-buildrun:before{content:"\e60c"}.ico-stop:before{content:"\e60f"}.ico-restore:before{content:"\e613"}.toolbars .ico-restore:before{content:"\e60a"}.ico-min:before{content:"\e614";position:absolute;right:5px}.ico-close:before{content:"\e611"}
|
||||
body,ul{margin:0}body,button,input{font-family:Helvetica}.list li,body{overflow:hidden}::-webkit-scrollbar{background:0 0;width:16px;height:16px}::-webkit-scrollbar-corner{display:none;background-color:transparent}::-webkit-scrollbar-thumb{border:0 solid transparent;border-right-width:4px;border-left-width:4px;border-radius:9px;box-shadow:inset 0 0 0 1px rgba(128,128,128,.2),inset 0 0 0 4px rgba(128,128,128,.2)}::-webkit-scrollbar-thumb:horizontal{border-bottom-width:4px;border-top-width:4px}body{font-size:13px;color:#000}ul{padding:0;list-style:none}*{box-sizing:border-box}a{color:#4183c4;text-decoration:none}a:hover{text-decoration:underline}img{vertical-align:middle}.fn-left{float:left}.fn-right{float:right}.fn-clear:after,.fn-clear:before{display:table;content:""}.fn-clear:after{clear:both}.fn-none{display:none}.ft-small{color:#999;font-size:12px}.ft-red{color:#9d0000}.list li{cursor:pointer;line-height:20px;padding:0 3px;word-wrap:normal;word-break:normal;white-space:nowrap;text-overflow:ellipsis}.list li.selected,.list li:hover{background-color:#3875d7;color:#FFF}.list li.selected .ft-small,.list li:hover .ft-small{color:#FFF}@font-face{font-family:icomoon;src:url(fonts/icomoon.eot?lqk80d);src:url(fonts/icomoon.eot?lqk80d#iefix) format('embedded-opentype'),url(fonts/icomoon.ttf?lqk80d) format('truetype'),url(fonts/icomoon.woff?lqk80d) format('woff'),url(fonts/icomoon.svg?lqk80d#icomoon) format('svg');font-weight:400;font-style:normal}[class*=" ico-"],[class^=ico-]{font-family:icomoon!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;cursor:pointer;font-size:13px;line-height:20px}.ico-qqz:before{content:"\e900"}.ico-find:before{content:"\e602"}.ico-findfiles:before{content:"\e603"}.ico-editor:before{content:"\e604"}.ico-notification:before{content:"\e607"}.ico-price:before{content:"\e616"}.ico-report:before{content:"\e605"}.ico-signup:before{content:"\e606"}.ico-git:before{content:"\e624"}.ico-book:before{content:"\e623"}.ico-start:before{content:"\e9d7";text-shadow:0 0 rgba(0,0,0,.4)}.ico-tree:before{content:"\e600"}.ico-build:before{content:"\e601"}.ico-export:before{content:"\f0ed"}.ico-import:before{content:"\f0ee"}.ico-keyboard:before{content:"\f11c"}.ico-moveup:before{content:"\f148"}.ico-movedown:before{content:"\f149"}.ico-weibo:before{content:"\e621"}.ico-uniE608:before{content:"\e608"}.ico-max:before{content:"\e609"}.ico-remove:before{content:"\e60b"}.ico-buildrun:before{content:"\e60c"}.ico-about:before{content:"\e60d"}.ico-undo:before{content:"\e60e"}.ico-stop:before{content:"\e60f"}.ico-close:before{content:"\e611";text-shadow:0 0 rgba(0,0,0,.4)}.ico-format:before{content:"\e612"}.ico-restore:before{content:"\e613"}.toolbars .ico-restore:before{content:"\e60a"}.ico-min:before{content:"\e614";position:absolute;right:5px}.ico-redo:before{content:"\e615"}.ico-uniE617:before{content:"\e617"}.ico-signout:before{content:"\e618"}.ico-email:before{content:"\e619"}.ico-googleplus:before{content:"\e61a"}.ico-facebook:before{content:"\e61b"}.ico-twitter:before{content:"\e61c"}.ico-info:before{content:"\e61d"}.ico-goline:before{content:"\e61e"}.ico-share:before{content:"\e61f"}.ico-comment:before{content:"\e620"}.ico-github:before{content:"\f00a"}.ico-refresh:before{content:"\f021"}.ico-save:before{content:"\f0c7"}
|
||||
.frame li,.tabs>div{padding:0 5px;cursor:pointer}.footer .cursor,.frame li,.menu>ul>li>span,.notification-count,.tabs>div{cursor:pointer}.ico,.menu .split,.menu>ul>li,.tabs>div{float:left}.frame{position:absolute;width:320px;z-index:21;display:none}.frame li{line-height:25px}.frame li.disabled,.frame li.disabled .font-ico,.frame li.disabled:hover .font-ico{color:#999}.frame a{color:#000;text-decoration:none}.frame a:hover,.frame li:hover a{color:#FFF}.frame .space{display:inline-block;width:20px;height:15px}.frame .font-ico{margin-right:5px;width:15px;display:inline-block;text-align:center}.tabs{height:21px;overflow:hidden;width:100%}.tabs>div{line-height:20px;height:20px}.tabs>div>span.changed{font-weight:700}.tabs-panel{overflow:auto;flex:1;height:100%}.edit-exprinfo,.edit-panel{position:absolute;overflow:hidden}.menu{display:block!important}.menu>ul>li>span{font-size:12px;line-height:21px;padding:4px 7px}.menu .split{border-left:1px solid #919191;height:21px;margin:0 5px 0 0}.menu img.gravatar{float:left;margin:2px 8px;height:17px;width:17px;border-radius:9px}#buildRun{color:#6DB14C;font-size:19px}#buildRun.ico-stop{color:#9d0000;font-size:16px}.share-panel{position:absolute;z-index:20;width:226px;padding:5px 0;right:0;top:21px}.share-panel .font-ico{font-size:20px;transition:all .2s ease-out 0s;margin:0 5px;width:24px}.share-panel .font-ico:hover{transform:rotate(360deg)}.edit-panel{left:20%;width:60%;height:70%;flex-flow:column;display:flex}.toolbars{position:absolute;right:5px;top:1px}.ico{background-image:url(../images/ico-file.png);height:16px;margin:2px 0 0 -2px;width:16px}.edit-exprinfo{z-index:10;list-style:none;margin:0;padding:2px;-webkit-box-shadow:2px 3px 5px rgba(0,0,0,.2);-moz-box-shadow:2px 3px 5px rgba(0,0,0,.2);box-shadow:2px 3px 5px rgba(0,0,0,.2);border-radius:3px;border:1px solid silver;background:#fff;font-size:90%;max-height:20em;overflow-y:auto}.CodeMirror,.CodeMirror-hints{font-family:Consolas,'Courier New',monospace}.CodeMirror-hints .ico{margin:-1px 2px 0 -1px}.CodeMirror-focused .cm-matchhighlight{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);background-position:bottom;background-repeat:repeat-x}.CodeMirror-hint{padding-right:18px;max-width:none}.CodeMirror-hint:hover{background:#08f;color:#fff}.CodeMirror div.CodeMirror-cursor{border-left:2px solid #333}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:transparent}.bottom-window-group{background-color:#fff;flex-flow:column}.bottom-window-group .output{font-family:Consolas,Courier New,monospace;padding:0 5px;line-height:16px;font-size:12px;overflow-x:scroll;outline:0}.bottom-window-group .output pre{margin:0;font-family:Consolas,'Courier New',monospace}.bottom-window-group .output .start-build,.bottom-window-group .output .start-get,.bottom-window-group .output .start-install,.bottom-window-group .output .start-test,.start-vet{color:#999}.bottom-window-group .output .build-succ,.bottom-window-group .output .get-succ,.bottom-window-group .output .install-succ,.bottom-window-group .output .test-succ,.vet-succ{color:#090}.bottom-window-group .output .build-error,.bottom-window-group .output .get-error,.bottom-window-group .output .install-error,.bottom-window-group .output .test-error,.vet-error{color:#9d0000}.bottom-window-group .output .stderr{color:gray;font-style:italic}.bottom-window-group .output .path{text-decoration:underline;cursor:pointer}.bottom-window-group table{width:100%}.bottom-window-group td{border-bottom:1px solid #919191;font-size:12px;line-height:19px}.bottom-window-group .notification{outline:0}.bottom-window-group .notification .severity,.bottom-window-group .notification .type{width:50px;padding:0 5px}.bottom-window-group .search{display:flex;flex-flow:column;outline:0}.footer{box-shadow:0 1px 0 0 rgba(255,255,255,.06) inset;padding-left:5px;line-height:18px;display:block!important}.notification-count{float:right;display:none;background-color:#9d0000;color:#FFF;margin:1px 5px;padding:0 2px;border-radius:3px;line-height:16px}
|
||||
.side{width:20%;position:absolute;height:100%;z-index:8;flex-flow:column;display:flex}.side-max{width:100%;z-index:11}.side-right .tabs-panel>div{overflow:auto}.side-right{flex-flow:column}#outline .ico{margin:1px 5px 0}.ico-func{background-position:-123px -21px}.ico-interface{background-position:-143px -21px}.ico-const{background-position:-103px -21px}.ico-var{background-position:-63px -21px}.ico-struct{background-position:-83px -21px}.ico-type{background-position:-163px -21px}.ico-package{background-position:-183px -21px}.ztree{width:100%;padding:0;outline:0;border:0}.ztree li a.curSelectedNode{background-color:#3875d7;border-width:0;color:#fff;height:18px;opacity:1}.ztree li a:hover{text-decoration:none}.ztree li>a>span.button,.ztree li>a>span.button.ico-ztree-dir,.ztree li>a>span.button.ico-ztree-dir-api,.ztree li>a>span.button.ico-ztree-dir-workspace{margin-right:2px}.ztree li>a>span.button{background-image:url(../images/ico-file.png);margin-right:0}.ico-ztree-dir{background-position:-2px -23px}.ico-ztree-dir-api{background-position:-22px -23px}.ico-ztree-dir-workspace{background-position:-42px -23px}.ico-ztree-html{background-position:-4px -2px}.ico-ztree-go{background-position:-22px -2px}.ico-ztree-css{background-position:-42px -2px}.ico-ztree-img{background-position:-63px -2px}.ico-ztree-other{background-position:-83px -2px}.ico-ztree-text{background-position:-103px -2px}.ico-ztree-sql{background-position:-123px -2px}.ico-ztree-pro{background-position:-142px -2px}.ico-ztree-md{background-position:-162px -2px}.ico-ztree-js{background-position:-182px -2px}.ico-ztree-xml{background-position:-202px -2px}
|
||||
#startPage{padding:50px 70px;line-height:28px;white-space:normal;word-wrap:break-word;overflow:auto}#startPage a{color:#4183c4;text-decoration:none}#startPage a:hover{text-decoration:underline}#startPage .title{background-color:#BBB;border-bottom-width:0!important;border-radius:3px 3px 0 0;font-size:15px;margin-bottom:10px;padding:5px 10px;color:#FFF}#startPage .details li.border,#startPage .news li{border-bottom:1px solid #919191}#startPage .details{width:30%;float:left}#startPage .details label{color:#666}#startPage .details li.border{padding-bottom:5px;margin-bottom:5px}#startPage .details li.border.workspace{line-height:18px;padding-bottom:10px!important;word-wrap:break-word;white-space:normal;word-break:break-all}#startPage .news{width:60%;float:right;border-left:1px solid #f1f1f1;margin-left:10%;padding-left:10%;white-space:nowrap;overflow:hidden}#startPage .date{color:#bbb;font-size:13px;word-wrap:normal;white-space:nowrap}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -24,7 +24,7 @@
|
|||
$.fn.extend({
|
||||
dialog: {
|
||||
version: "0.0.1.7",
|
||||
author: "lly219@gmail.com"
|
||||
author: "v@b3log.org"
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -246,7 +246,7 @@ var editors = {
|
|||
+ '"><span class="ico-start font-ico"></span> ' + config.label.start_page + '</span>',
|
||||
content: '<div id="startPage"></div>',
|
||||
after: function () {
|
||||
$("#startPage").load(config.context + '/start?sid=' + config.wideSessionId);
|
||||
$("#startPage").load('/start?sid=' + config.wideSessionId);
|
||||
$.ajax({
|
||||
url: "https://hacpai.com/apis/articles?tags=wide,golang&p=1&size=20",
|
||||
type: "GET",
|
||||
|
@ -329,7 +329,7 @@ var editors = {
|
|||
$.ajax({
|
||||
async: false, // 同步执行
|
||||
type: 'POST',
|
||||
url: config.context + '/autocomplete',
|
||||
url: '/autocomplete',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
|
@ -435,7 +435,7 @@ var editors = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/exprinfo',
|
||||
url: '/exprinfo',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -583,7 +583,7 @@ var editors = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/find/decl',
|
||||
url: '/find/decl',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -613,7 +613,7 @@ var editors = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/find/usages',
|
||||
url: '/find/usages',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -73,7 +73,7 @@ xquery version "1.0-ml";
|
|||
: you may not use this file except in compliance with the License.
|
||||
: You may obtain a copy of the License at
|
||||
:
|
||||
: http://www.apache.org/licenses/LICENSE-2.0
|
||||
: https://www.apache.org/licenses/LICENSE-2.0
|
||||
:
|
||||
: Unless required by applicable law or agreed to in writing, software
|
||||
: distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -19,7 +19,7 @@
|
|||
*
|
||||
* @author <a href="http://vanessa.b3log.org">Liyuan Li</a>
|
||||
* @author <a href="http://88250.b3log.org">Liang Ding</a>
|
||||
* @version 1.0.1.2, Mar 27, 2017
|
||||
* @version 1.0.1.3, Oct 5, 2018
|
||||
*/
|
||||
var menu = {
|
||||
init: function () {
|
||||
|
@ -55,14 +55,13 @@ var menu = {
|
|||
var title = encodeURIComponent($('title').text() + '. \n' + $('meta[name=description]').attr('content')
|
||||
+ " #golang#");
|
||||
urls.weibo = "http://v.t.sina.com.cn/share/share.php?title=" + title + "&url=" + url + "&pic=" + pic;
|
||||
urls.tencent = "http://share.v.t.qq.com/index.php?c=share&a=index&title=" + title +
|
||||
"&url=" + url + "&pic=" + pic;
|
||||
urls.qqz = "https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=" + url + "&sharesource=qzone&title=" + title+ "&pics=" + pic;
|
||||
|
||||
window.open(urls[key], "_blank", "top=100,left=200,width=648,height=618");
|
||||
});
|
||||
},
|
||||
_initAbout: function () {
|
||||
$("#dialogAbout").load(config.context + '/about', function () {
|
||||
$("#dialogAbout").load('/about', function () {
|
||||
$("#dialogAbout").dialog({
|
||||
"modal": true,
|
||||
"title": config.label.about,
|
||||
|
@ -160,12 +159,12 @@ var menu = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/logout',
|
||||
url: '/logout',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (result.succ) {
|
||||
window.location.href = config.context + "/login";
|
||||
window.location.href = "/login";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -190,7 +189,7 @@ var menu = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/go/get',
|
||||
url: '/go/get',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
beforeSend: function () {
|
||||
|
@ -217,7 +216,7 @@ var menu = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/go/install',
|
||||
url: '/go/install',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
beforeSend: function () {
|
||||
|
@ -245,7 +244,7 @@ var menu = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/go/test',
|
||||
url: '/go/test',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
beforeSend: function () {
|
||||
|
@ -273,7 +272,7 @@ var menu = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/go/vet',
|
||||
url: '/go/vet',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
beforeSend: function () {
|
||||
|
@ -308,7 +307,7 @@ var menu = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/build',
|
||||
url: '/build',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
beforeSend: function () {
|
||||
|
@ -341,7 +340,7 @@ var menu = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/build',
|
||||
url: '/build',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
beforeSend: function () {
|
||||
|
@ -352,7 +351,7 @@ var menu = {
|
|||
});
|
||||
},
|
||||
_initPreference: function () {
|
||||
$("#dialogPreference").load(config.context + '/preference', function () {
|
||||
$("#dialogPreference").load('/preference', function () {
|
||||
$("#dialogPreference input").keyup(function () {
|
||||
var isChange = false,
|
||||
emptys = [],
|
||||
|
@ -466,7 +465,7 @@ var menu = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/preference',
|
||||
url: '/preference',
|
||||
data: JSON.stringify(request),
|
||||
success: function (result, textStatus, jqXHR) {
|
||||
if (!result.succ) {
|
||||
|
@ -497,7 +496,7 @@ var menu = {
|
|||
var $okBtn = $("#dialogPreference").closest(".dialog-main").find(".dialog-footer > button:eq(0)");
|
||||
$okBtn.prop("disabled", true);
|
||||
|
||||
$("#themesLink").attr("href", config.staticServer + '/static/css/themes/' + $theme.val() + '.css');
|
||||
$("#themesLink").attr("href", '/static/css/themes/' + $theme.val() + '.css');
|
||||
|
||||
config.editorTheme = $editorTheme.val();
|
||||
for (var i = 0, ii = editors.data.length; i < ii; i++) {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -19,7 +19,7 @@
|
|||
*
|
||||
* @author <a href="http://vanessa.b3log.org">Liyuan Li</a>
|
||||
* @author <a href="http://88250.b3log.org">Liang Ding</a>
|
||||
* @version 1.0.0.1, Dec 8, 2015
|
||||
* @version 1.0.0.2, Oct 5, 2018
|
||||
*/
|
||||
var playground = {
|
||||
autocompleteMutex: false,
|
||||
|
@ -53,10 +53,9 @@ var playground = {
|
|||
var title = encodeURIComponent($('title').text() + '. \n' + $('meta[name=description]').attr('content')
|
||||
+ " #golang#");
|
||||
urls.weibo = "http://v.t.sina.com.cn/share/share.php?title=" + title + "&url=" + url + "&pic=" + pic;
|
||||
urls.tencent = "http://share.v.t.qq.com/index.php?c=share&a=index&title=" + title +
|
||||
"&url=" + url + "&pic=" + pic;
|
||||
urls.qqz = "https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=" + url + "&sharesource=qzone&title=" + title+ "&pics=" + pic;
|
||||
|
||||
window.open(urls[key], "_blank", "top=100,left=200,width=648,height=618");
|
||||
window.open(urls[key], "_blank", "top=100,left=200,width=648,height=618");
|
||||
|
||||
$(".menu .share-panel").hide();
|
||||
});
|
||||
|
@ -92,7 +91,7 @@ var playground = {
|
|||
$.ajax({
|
||||
async: false, // 同步执行
|
||||
type: 'POST',
|
||||
url: config.context + '/playground/autocomplete',
|
||||
url: '/playground/autocomplete',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
|
@ -357,7 +356,7 @@ var playground = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/playground/save',
|
||||
url: '/playground/save',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -376,7 +375,7 @@ var playground = {
|
|||
request.url = url;
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/playground/short-url',
|
||||
url: '/playground/short-url',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -421,7 +420,7 @@ var playground = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/playground/stop',
|
||||
url: '/playground/stop',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json"
|
||||
});
|
||||
|
@ -444,7 +443,7 @@ var playground = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/playground/save',
|
||||
url: '/playground/save',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -463,7 +462,7 @@ var playground = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/playground/build',
|
||||
url: '/playground/build',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -483,7 +482,7 @@ var playground = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/playground/run',
|
||||
url: '/playground/run',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -510,7 +509,7 @@ var playground = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/playground/save',
|
||||
url: '/playground/save',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -74,7 +74,7 @@ var session = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/session/save',
|
||||
url: '/session/save',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @file shell.js
|
||||
*
|
||||
* @author <a href="http://88250.b3log.org">Liang Ding</a>
|
||||
* @version 1.0.0.1, Dec 8, 2015
|
||||
*/
|
||||
var shell = {
|
||||
_shellWS: undefined,
|
||||
_initWS: function () {
|
||||
shell.shellWS = new ReconnectingWebSocket(config.channel + '/shell/ws?sid=' + config.wideSessionId);
|
||||
shell.shellWS.onopen = function () {
|
||||
console.log('[shell onopen] connected');
|
||||
};
|
||||
shell.shellWS.onmessage = function (e) {
|
||||
console.log('[shell onmessage]' + e.data);
|
||||
var data = JSON.parse(e.data);
|
||||
if ('init-shell' !== data.cmd) {
|
||||
$('#shellOutput').val(data.output);
|
||||
}
|
||||
};
|
||||
shell.shellWS.onclose = function (e) {
|
||||
console.log('[shell onclose] disconnected (' + e.code + ')');
|
||||
};
|
||||
shell.shellWS.onerror = function (e) {
|
||||
console.log('[shell onerror] ' + e);
|
||||
};
|
||||
},
|
||||
init: function () {
|
||||
this._initWS();
|
||||
|
||||
$('#shellInput').keydown(function (event) {
|
||||
if (13 === event.which) {
|
||||
var input = {
|
||||
cmd: $('#shellInput').val()
|
||||
};
|
||||
shell.shellWS.send(JSON.stringify(input));
|
||||
$('#shellInput').val('');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function () {
|
||||
shell.init();
|
||||
});
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -160,7 +160,7 @@ var tree = {
|
|||
$.ajax({
|
||||
async: false,
|
||||
type: 'POST',
|
||||
url: config.context + '/file/zip/new',
|
||||
url: '/file/zip/new',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -175,7 +175,7 @@ var tree = {
|
|||
});
|
||||
|
||||
if (isSucc) {
|
||||
window.open(config.context + '/file/zip?path=' + wide.curNode.path + ".zip");
|
||||
window.open('/file/zip?path=' + wide.curNode.path + ".zip");
|
||||
}
|
||||
},
|
||||
crossCompile: function (platform) {
|
||||
|
@ -186,7 +186,7 @@ var tree = {
|
|||
$.ajax({
|
||||
async: false,
|
||||
type: 'POST',
|
||||
url: config.context + '/cross',
|
||||
url: '/cross',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -198,28 +198,6 @@ var tree = {
|
|||
}
|
||||
});
|
||||
},
|
||||
decompress: function () {
|
||||
var request = newWideRequest();
|
||||
request.path = wide.curNode.path;
|
||||
|
||||
$.ajax({
|
||||
async: false,
|
||||
type: 'POST',
|
||||
url: config.context + '/file/decompress',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
$("#dialogAlert").dialog("open", result.msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var dir = wide.curNode.getParentNode();
|
||||
tree.fileTree.reAsyncChildNodes(dir, "refresh");
|
||||
}
|
||||
});
|
||||
},
|
||||
refresh: function (it) {
|
||||
if (it) {
|
||||
if ($(it).hasClass("disabled")) {
|
||||
|
@ -229,31 +207,6 @@ var tree = {
|
|||
|
||||
tree.fileTree.reAsyncChildNodes(wide.curNode, "refresh", true);
|
||||
},
|
||||
gitClone: function (it) {
|
||||
if (it) {
|
||||
if ($(it).hasClass("disabled")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$("#dialogGitClonePrompt").dialog('open');
|
||||
},
|
||||
import: function () {
|
||||
var request = newWideRequest();
|
||||
request.path = wide.curNode.path;
|
||||
|
||||
$('#importFileupload').fileupload({
|
||||
url: "/file/upload?path=" + request.path,
|
||||
dataType: 'json',
|
||||
formData: request,
|
||||
done: function (e, result) {
|
||||
tree.fileTree.reAsyncChildNodes(wide.curNode, "refresh");
|
||||
},
|
||||
fail: function () {
|
||||
console.log(arguments);
|
||||
}
|
||||
});
|
||||
},
|
||||
init: function () {
|
||||
$("#file").click(function () {
|
||||
$(this).focus();
|
||||
|
@ -263,7 +216,7 @@ var tree = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/files',
|
||||
url: '/files',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -282,7 +235,7 @@ var tree = {
|
|||
},
|
||||
async: {
|
||||
enable: true,
|
||||
url: config.context + "/file/refresh",
|
||||
url: "/file/refresh",
|
||||
autoParam: ["path"]
|
||||
},
|
||||
callback: {
|
||||
|
@ -417,7 +370,7 @@ var tree = {
|
|||
$.ajax({
|
||||
async: false,
|
||||
type: 'POST',
|
||||
url: config.context + '/file',
|
||||
url: '/file',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -444,7 +397,7 @@ var tree = {
|
|||
|
||||
if ("img" === data.mode) { // 是图片文件的话新建 tab 打开
|
||||
// 最好是开 tab,但这个最终取决于浏览器设置
|
||||
var w = window.open(config.context + data.path);
|
||||
var w = window.open(data.path);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -506,7 +459,7 @@ var tree = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/file/search/text',
|
||||
url: '/file/search/text',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -542,7 +495,7 @@ var tree = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/file/rename',
|
||||
url: '/file/rename',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -38,7 +38,7 @@ var wide = {
|
|||
$.ajax({
|
||||
type: 'POST',
|
||||
async: false,
|
||||
url: config.context + '/outline',
|
||||
url: '/outline',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -121,7 +121,7 @@ var wide = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/file/remove',
|
||||
url: '/file/remove',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -159,7 +159,7 @@ var wide = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/file/new',
|
||||
url: '/file/new',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -203,7 +203,7 @@ var wide = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/file/new',
|
||||
url: '/file/new',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -264,7 +264,7 @@ var wide = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/file/find/name',
|
||||
url: '/file/find/name',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -339,35 +339,6 @@ var wide = {
|
|||
editor.focus();
|
||||
}
|
||||
});
|
||||
|
||||
$("#dialogGitClonePrompt").dialog({
|
||||
"modal": true,
|
||||
"height": 52,
|
||||
"width": 360,
|
||||
"title": config.label.git_clone,
|
||||
"okText": config.label.confirm,
|
||||
"cancelText": config.label.cancel,
|
||||
"afterOpen": function () {
|
||||
$("#dialogGitClonePrompt > input").val('').focus();
|
||||
$("#dialogGitClonePrompt").closest(".dialog-main").find(".dialog-footer > button:eq(0)").prop("disabled", true);
|
||||
},
|
||||
"ok": function () {
|
||||
$("#dialogGitClonePrompt").dialog("close");
|
||||
|
||||
var request = newWideRequest();
|
||||
request.path = wide.curNode.path;
|
||||
request.repository = $("#dialogGitClonePrompt > input").val();
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/git/clone',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
_initWS: function () {
|
||||
var outputWS = new ReconnectingWebSocket(config.channel + '/output/ws?sid=' + config.wideSessionId);
|
||||
|
@ -389,7 +360,7 @@ var wide = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/run',
|
||||
url: '/run',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json"
|
||||
});
|
||||
|
@ -420,7 +391,6 @@ var wide = {
|
|||
case 'start-vet':
|
||||
case 'start-install':
|
||||
case 'start-get':
|
||||
case 'start-git_clone':
|
||||
bottomGroup.fillOutput(data.output);
|
||||
|
||||
break;
|
||||
|
@ -471,7 +441,7 @@ var wide = {
|
|||
$.ajax({
|
||||
async: false,
|
||||
type: 'POST',
|
||||
url: config.context + '/file/zip/new',
|
||||
url: '/file/zip/new',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -486,7 +456,7 @@ var wide = {
|
|||
});
|
||||
|
||||
if (path) {
|
||||
window.open(config.context + '/file/zip?path=' + path + ".zip");
|
||||
window.open('/file/zip?path=' + path + ".zip");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -551,7 +521,7 @@ var wide = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/file/save',
|
||||
url: '/file/save',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -587,7 +557,7 @@ var wide = {
|
|||
request.nextCmd = ""; // build only, no following operation
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/build',
|
||||
url: '/build',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
beforeSend: function () {
|
||||
|
@ -620,7 +590,7 @@ var wide = {
|
|||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.context + '/stop',
|
||||
url: '/stop',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -642,7 +612,7 @@ var wide = {
|
|||
$.ajax({
|
||||
async: false, // sync
|
||||
type: 'POST',
|
||||
url: config.context + '/go/fmt',
|
||||
url: '/go/fmt',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
@ -675,7 +645,7 @@ var wide = {
|
|||
$.ajax({
|
||||
async: false, // sync
|
||||
type: 'POST',
|
||||
url: config.context + '/go/fmt',
|
||||
url: '/go/fmt',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
* Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
This directory is used to hold user _admin_ customized style file `style.css`, it will be generated when wide startup automatically.
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
||||
// Copyright (c) 2014-2019, b3log.org & hacpai.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue