Merge remote-tracking branch 'origin/master'

# Conflicts:
#	package-lock.json
This commit is contained in:
Van 2019-05-17 09:48:47 +08:00
commit 7167b83c9e
No known key found for this signature in database
GPG Key ID: 7059B8783A78F16C
125 changed files with 1657 additions and 2924 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
static/js/lib/* linguist-vendored

46
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -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]
### 其他信息
请提供其他附加信息帮助我们诊断问题。

View File

@ -0,0 +1,20 @@
---
name: 请求新功能
about: 提出你期待的功能特性
---
### 你在什么场景下需要该功能?
请尽量清晰精准地描述你碰到的问题。
### 描述可能的解决方案
请尽量清晰精准地描述你期待我们要做的,描述你想到的实现方案。
### 描述你认为的候选方案
请尽量清晰精准地描述你能接受的候选解决方案。
### 其他信息
请提供关于该功能建议的其他附加信息。

2
.gitignore vendored
View File

@ -1,8 +1,6 @@
/wide.exe
/wide
/static/user/admin/style.css
/header
/header.exe

View File

@ -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"
}
}

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -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 toolgo 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 &copy; 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)

View File

@ -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

View File

@ -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))
}

View File

@ -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
}
}
}
}

View File

@ -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)

View File

@ -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
}

View File

@ -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

BIN
deps/github.com.zip vendored

Binary file not shown.

BIN
deps/golang.org.zip vendored

Binary file not shown.

View File

@ -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)

View File

@ -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,

View File

@ -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...)

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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]
}

View File

@ -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)
}

View File

@ -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,

21
go.mod Normal file
View File

@ -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
)

43
go.sum Normal file
View File

@ -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=

View File

@ -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)))

View File

@ -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",

View File

@ -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": "解凍する",

View File

@ -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": "압축풀기",

View File

@ -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,

View File

@ -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": "解压缩",

View File

@ -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": "解壓縮",

View File

@ -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,

View File

@ -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
View File

@ -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()}

View File

@ -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

View File

@ -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"

View File

@ -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 {

View File

@ -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"
}

View File

@ -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)

View File

@ -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
}

View File

@ -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}}
}

View File

@ -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"))
}
}

View File

@ -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

View File

@ -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, "<", "&lt;", -1)
oneRuneStr = strings.Replace(oneRuneStr, ">", "&gt;", -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, "<", "&lt;", -1)
oneRuneStr = strings.Replace(oneRuneStr, ">", "&gt;", -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())
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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"
}
}

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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")

View File

@ -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, "<", "&lt;", -1)
oneRuneStr = strings.Replace(oneRuneStr, ">", "&gt;", -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, "<", "&lt;", -1)
oneRuneStr = strings.Replace(oneRuneStr, ">", "&gt;", -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())
}

View File

@ -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())
}

272
session/oauthctl.go Normal file
View File

@ -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()
}

View File

@ -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
}

View File

@ -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()
}

View File

@ -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
}

View File

@ -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,

View File

@ -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 */

View File

@ -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
*/

BIN
static/css/fonts/icomoon.eot Normal file → Executable file

Binary file not shown.

94
static/css/fonts/icomoon.svg Normal file → Executable file
View File

@ -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="&#x20;" d="" horiz-adv-x="512" />
<glyph unicode="&#xe600;" 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="&#xe601;" 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="&#xe602;" 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="&#xe603;" 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="&#xe604;" 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="&#xe605;" d="M622.858 778.475l-22.032 110.158h-495.715v-936.349h110.158v385.556h308.443l22.032-110.158h385.556v550.795z" />
<glyph unicode="&#xe606;" 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="&#xe607;" 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="&#xe608;" 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="&#xe609;" 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="&#xe60a;" 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="&#xe60b;" 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="&#xe60c;" d="M192 832l640-384-640-384z" />
<glyph unicode="&#xe60d;" 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="&#xe60e;" 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="&#xe60f;" d="M128 832h768v-768h-768z" />
<glyph unicode="&#xe610;" 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="&#xe611;" 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="&#xe612;" 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="&#xe613;" 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="&#xe614;" 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="&#xe615;" 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="&#xe616;" 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="&#xe617;" d="M384 448h-320v128h320v128l192-192-192-192zM1024 960v-832l-384-192v192h-384v256h64v-192h320v576l256 128h-576v-256h-64v320z" />
<glyph unicode="&#xe618;" d="M768 320v128h-320v128h320v128l192-192zM704 384v-256h-320v-192l-384 192v832h704v-320h-64v256h-512l256-128v-576h256v192z" />
<glyph unicode="&#xe619;" 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="&#xe61a;" 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="&#xe61b;" 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="&#xe61c;" 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="&#xe61d;" 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="&#xe61e;" 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="&#xe61f;" 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="&#xe620;" 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="&#xe621;" 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="&#xe622;" 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="&#xe623;" 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="&#xe624;" 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="&#xe9d7;" 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="&#xf00a;" 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="&#xf021;" 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="&#xf05b;" 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="&#xf0c7;" 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="&#xf0ed;" 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="&#xf0ee;" 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="&#xf11c;" 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="&#xf148;" 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="&#xf149;" 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="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#xe600;" 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="&#xe601;" 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="&#xe602;" 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="&#xe603;" 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="&#xe604;" 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="&#xe605;" 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="&#xe606;" 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="&#xe607;" 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="&#xe608;" 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="&#xe609;" 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="&#xe60a;" 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="&#xe60b;" 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="&#xe60c;" glyph-name="buildrun" d="M192 832l640-384-640-384z" />
<glyph unicode="&#xe60d;" 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="&#xe60e;" 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="&#xe60f;" glyph-name="stop" d="M128 832h768v-768h-768z" />
<glyph unicode="&#xe611;" 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="&#xe612;" 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="&#xe613;" 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="&#xe614;" 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="&#xe615;" 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="&#xe616;" 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="&#xe617;" glyph-name="uniE617" d="M384 448h-320v128h320v128l192-192-192-192zM1024 960v-832l-384-192v192h-384v256h64v-192h320v576l256 128h-576v-256h-64v320z" />
<glyph unicode="&#xe618;" glyph-name="signout" d="M768 320v128h-320v128h320v128l192-192zM704 384v-256h-320v-192l-384 192v832h704v-320h-64v256h-512l256-128v-576h256v192z" />
<glyph unicode="&#xe619;" 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="&#xe61a;" 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="&#xe61b;" 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="&#xe61c;" 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="&#xe61d;" 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="&#xe61e;" 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="&#xe61f;" 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="&#xe620;" 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="&#xe621;" 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="&#xe623;" 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="&#xe624;" 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="&#xe900;" 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="&#xe9d7;" 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="&#xf00a;" 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="&#xf021;" 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="&#xf0c7;" 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="&#xf0ed;" 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="&#xf0ee;" 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="&#xf11c;" 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="&#xf148;" 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="&#xf149;" 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

BIN
static/css/fonts/icomoon.ttf Normal file → Executable file

Binary file not shown.

BIN
static/css/fonts/icomoon.woff Normal file → Executable file

Binary file not shown.

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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}

View File

@ -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,

View File

@ -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"
}
});

View File

@ -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) {

View File

@ -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,

124
static/js/lib.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -73,7 +73,7 @@ xquery version &quot;1.0-ml&quot;;
: 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 &quot;AS IS&quot; BASIS,

View File

@ -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++) {

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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) {

View File

@ -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) {

View File

@ -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();
});

View File

@ -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,

View File

@ -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) {

View File

@ -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) {

22
static/js/wide.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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,

View File

@ -1 +0,0 @@
This directory is used to hold user _admin_ customized style file `style.css`, it will be generated when wide startup automatically.

View File

@ -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,

View File

@ -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