mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-26 01:40:36 +00:00
Merge remote-tracking branch 'upstream/master'
Conflicts: conf/app.ini
This commit is contained in:
commit
ba1270df2d
289 changed files with 129324 additions and 2885 deletions
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"paths": ["."],
|
|
||||||
"depth": 2,
|
|
||||||
"exclude": [],
|
|
||||||
"include": ["\\.go$", "\\.ini$"],
|
|
||||||
"command": [
|
|
||||||
"bash", "-c", "go build && ./gogs web"
|
|
||||||
],
|
|
||||||
"env": {
|
|
||||||
"POWERED_BY": "github.com/shxsun/fswatch"
|
|
||||||
}
|
|
||||||
}
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -39,3 +39,6 @@ __pycache__
|
||||||
output*
|
output*
|
||||||
config.codekit
|
config.codekit
|
||||||
.brackets.json
|
.brackets.json
|
||||||
|
docker/fig.yml
|
||||||
|
docker/docker/Dockerfile
|
||||||
|
docker/docker/init_gogs.sh
|
||||||
|
|
|
@ -10,3 +10,12 @@ filesets:
|
||||||
- README_ZH.md
|
- README_ZH.md
|
||||||
excludes:
|
excludes:
|
||||||
- \.git
|
- \.git
|
||||||
|
settings:
|
||||||
|
build: |
|
||||||
|
if test "$GOOS" = "windows" -a "$GOARCH" = "386"
|
||||||
|
then
|
||||||
|
go install -v
|
||||||
|
else
|
||||||
|
go get -v -tags "sqlite redis memecache" github.com/gogits/gogs
|
||||||
|
go install -v -tags "sqlite redis memecache"
|
||||||
|
fi
|
||||||
|
|
36
.gopmfile
36
.gopmfile
|
@ -2,29 +2,29 @@
|
||||||
path = github.com/gogits/gogs
|
path = github.com/gogits/gogs
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
code.google.com/p/mahonia =
|
github.com/beego/memcache = commit:2aea774416
|
||||||
github.com/Unknwon/cae =
|
github.com/beego/redigo = commit:856744a0d5
|
||||||
github.com/Unknwon/com =
|
github.com/Unknwon/cae = commit:2e70a1351b
|
||||||
github.com/Unknwon/goconfig =
|
github.com/Unknwon/com = commit:2cbcbc6916
|
||||||
github.com/Unknwon/i18n =
|
github.com/Unknwon/goconfig = commit:0f8d8dc1c0
|
||||||
|
github.com/Unknwon/i18n = commit:47baeff8d0
|
||||||
github.com/Unknwon/macaron =
|
github.com/Unknwon/macaron =
|
||||||
github.com/codegangsta/cli =
|
github.com/codegangsta/cli = commit:7381bc4e62
|
||||||
github.com/go-sql-driver/mysql =
|
github.com/go-sql-driver/mysql = commit:8111ee3ec3
|
||||||
github.com/go-xorm/core =
|
github.com/go-xorm/core = commit:750aae0fa5
|
||||||
github.com/go-xorm/xorm =
|
github.com/go-xorm/xorm = commit:2d8b3135b1
|
||||||
github.com/gogits/gfm =
|
github.com/gogits/gfm = commit:40f747a9c0
|
||||||
github.com/gogits/git =
|
github.com/gogits/oauth2 = commit:99cbec870a
|
||||||
github.com/gogits/oauth2 =
|
github.com/lib/pq = commit:b021d0ef20
|
||||||
github.com/juju2013/goldap =
|
github.com/macaron-contrib/cache = commit:204d8e5137
|
||||||
github.com/lib/pq =
|
|
||||||
github.com/macaron-contrib/cache =
|
|
||||||
github.com/macaron-contrib/captcha =
|
github.com/macaron-contrib/captcha =
|
||||||
github.com/macaron-contrib/csrf =
|
github.com/macaron-contrib/csrf =
|
||||||
github.com/macaron-contrib/i18n =
|
github.com/macaron-contrib/i18n =
|
||||||
github.com/macaron-contrib/session =
|
github.com/macaron-contrib/session =
|
||||||
github.com/macaron-contrib/toolbox =
|
github.com/macaron-contrib/toolbox = commit:57127bcc89
|
||||||
github.com/nfnt/resize =
|
github.com/mattn/go-sqlite3 = commit:a80c27ba33
|
||||||
github.com/saintfish/chardet =
|
github.com/nfnt/resize = commit:581d15cb53
|
||||||
|
github.com/saintfish/chardet = commit:3af4cd4741
|
||||||
|
|
||||||
[res]
|
[res]
|
||||||
include = conf|etc|public|scripts|templates
|
include = conf|etc|public|scripts|templates
|
||||||
|
|
15
.pkgr.yml
Normal file
15
.pkgr.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
targets:
|
||||||
|
ubuntu-14.04:
|
||||||
|
ubuntu-12.04:
|
||||||
|
debian-7:
|
||||||
|
build_dependencies:
|
||||||
|
- mercurial
|
||||||
|
- bzr
|
||||||
|
dependencies:
|
||||||
|
- git
|
||||||
|
before:
|
||||||
|
- mv packager/Procfile .
|
||||||
|
- mv packager/.godir .
|
||||||
|
after:
|
||||||
|
- mv bin/main gogs
|
||||||
|
after_install: ./packager/debian/postinst
|
|
@ -3,4 +3,3 @@ language: go
|
||||||
go:
|
go:
|
||||||
- 1.2
|
- 1.2
|
||||||
- 1.3
|
- 1.3
|
||||||
- tip
|
|
|
@ -1,14 +1,54 @@
|
||||||
# Contributing to Gogs
|
# Contributing to Gogs
|
||||||
|
|
||||||
> Thanks [drone](https://github.com/drone/drone) because this guidelines sheet is forked from its [CONTRIBUTING.md](https://github.com/drone/drone/blob/master/CONTRIBUTING.md).
|
> This guidelines sheet is forked from [CONTRIBUTING.md](https://github.com/drone/drone/blob/master/CONTRIBUTING.md).
|
||||||
|
|
||||||
Want to hack on Gogs? Awesome! Here are instructions to get you started. They are probably not perfect, please let us know if anything feels wrong or incomplete.
|
Gogs is not perfect and it has bugs, or incomplete features for rare cases. You're welcome to tell us or contribute some code. This document describles details about how can you contribute to Gogs project.
|
||||||
|
|
||||||
## Contribution guidelines
|
## Contribution guidelines
|
||||||
|
|
||||||
### Pull requests are always welcome
|
Depends on the situation, you will:
|
||||||
|
|
||||||
**ALL PULL REQUESTS MUST SEND TO `DEV` BRANCH**
|
- Find bug, create an issue
|
||||||
|
- Need more functionality, make a feature request
|
||||||
|
- Want to contribute code, open a pull request
|
||||||
|
- Run into issue, need help
|
||||||
|
|
||||||
|
### Bug Report
|
||||||
|
|
||||||
|
If you find or consider something is a bug, please create a issue on [GitHub](https://github.com/gogits/gogs/issues). To reduce unnecessary time wasting of interacting and waiting with team members, please use following form as template in the first place:
|
||||||
|
|
||||||
|
```
|
||||||
|
- **Bug Description**:
|
||||||
|
- **Gogs Version**:
|
||||||
|
- **Git Version**:
|
||||||
|
- **System Type**:
|
||||||
|
- **Error Log**:
|
||||||
|
- **Other information**:
|
||||||
|
```
|
||||||
|
|
||||||
|
Please take a moment to check that an issue on [GitHub](https://github.com/gogits/gogs/issues) doesn't already exist documenting your bug report or improvement proposal. If it does, it never hurts to add a quick "+1" or "I have this problem too". This will help prioritize the most common problems and requests.
|
||||||
|
|
||||||
|
#### Bug Report Example
|
||||||
|
|
||||||
|
- **Bug Description**: Crash when create repository with license|
|
||||||
|
- **Gogs Version**: `v0.4.9.0901`
|
||||||
|
- **Git Version**: `1.9.0`
|
||||||
|
- **System Type**: `Ubuntu 12.04`
|
||||||
|
- **Error Log**:
|
||||||
|
|
||||||
|
```
|
||||||
|
2014/09/01 07:21:49 [E] nil pointer
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Other information**: Use SQLite3 as database
|
||||||
|
|
||||||
|
### Feature Request
|
||||||
|
|
||||||
|
There is no standard form of making a feature request, just try to describle the feature as clear as possible because team members may not have experience with the functionality you're talking about.
|
||||||
|
|
||||||
|
### Pull Request
|
||||||
|
|
||||||
|
Pull requests are always welcome, but note that **ALL PULL REQUESTS MUST SEND TO `DEV` BRANCH**.
|
||||||
|
|
||||||
We are always thrilled to receive pull requests, and do our best to process them as fast as possible. Not sure if that typo is worth a pull request? Do it! We will appreciate it.
|
We are always thrilled to receive pull requests, and do our best to process them as fast as possible. Not sure if that typo is worth a pull request? Do it! We will appreciate it.
|
||||||
|
|
||||||
|
@ -16,16 +56,16 @@ If your pull request is not accepted on the first try, don't be discouraged! If
|
||||||
|
|
||||||
We're trying very hard to keep Gogs lean and focused. We don't want it to do everything for everybody. This means that we might decide against incorporating a new feature.
|
We're trying very hard to keep Gogs lean and focused. We don't want it to do everything for everybody. This means that we might decide against incorporating a new feature.
|
||||||
|
|
||||||
|
### Ask For Help
|
||||||
|
|
||||||
|
Before open any new issue, please check your problem on [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.md) and [FAQs](http://gogs.io/docs/intro/faqs.html) pages.
|
||||||
|
|
||||||
|
## Things To Notice
|
||||||
|
|
||||||
|
Please take a moment to check that an issue on [GitHub](https://github.com/gogits/gogs/issues) or card on [Trello](https://trello.com/b/uxAoeLUl/gogs-go-git-service) doesn't already exist documenting your bug report or improvement proposal. If it does, it never hurts to add a quick "+1" or "I have this problem too". This will help prioritize the most common problems and requests.
|
||||||
|
|
||||||
### Discuss your design on the mailing list
|
### Discuss your design on the mailing list
|
||||||
|
|
||||||
We recommend discussing your plans [on the mailing list](https://groups.google.com/forum/#!forum/gogits) before starting to code - especially for more ambitious contributions. This gives other contributors a chance to point you in the right direction, give feedback on your design, and maybe point out if someone else is working on the same thing.
|
We recommend discussing your plans [on the mailing list](https://groups.google.com/forum/#!forum/gogits) before starting to code - especially for more ambitious contributions. This gives other contributors a chance to point you in the right direction, give feedback on your design, and maybe point out if someone else is working on the same thing.
|
||||||
|
|
||||||
We may close your pull request if not first discussed on the mailing list. We aren't doing this to be jerks. We are doing this to prevent people from spending large amounts of time on changes that may need to be designed or architected in a specific way, or may not align with the vision of the project.
|
We may close your pull request if not first discussed on the mailing list. We aren't doing this to be jerks. We are doing this to prevent people from spending large amounts of time on changes that may need to be designed or architected in a specific way, or may not align with the vision of the project.
|
||||||
|
|
||||||
### Create issues...
|
|
||||||
|
|
||||||
Any significant improvement should be documented as [a GitHub issue](https://github.com/gogits/gogs/issues) before anybody starts working on it.
|
|
||||||
|
|
||||||
### ...but check for existing issues first!
|
|
||||||
|
|
||||||
Please take a moment to check that an issue or card on [Trello](https://trello.com/b/uxAoeLUl/gogs-go-git-service) doesn't already exist documenting your bug report or improvement proposal. If it does, it never hurts to add a quick "+1" or "I have this problem too". This will help prioritize the most common problems and requests.
|
|
21
README.md
21
README.md
|
@ -3,14 +3,14 @@ Gogs - Go Git Service [![wercker status](https://app.wercker.com/status/ad0bdb0b
|
||||||
|
|
||||||
Gogs(Go Git Service) is a painless self-hosted Git Service written in Go.
|
Gogs(Go Git Service) is a painless self-hosted Git Service written in Go.
|
||||||
|
|
||||||
![Demo](http://gowalker.org/public/gogs_demo.gif)
|
![Demo](https://gowalker.org/public/gogs_demo.gif)
|
||||||
|
|
||||||
##### Current version: 0.4.9 Beta
|
##### Current version: 0.5.4 Beta
|
||||||
|
|
||||||
### NOTICES
|
### NOTICES
|
||||||
|
|
||||||
- Due to testing purpose, data of [try.gogits.org](http://try.gogits.org) has been reset in **June 21, 2014** and will reset multiple times after. Please do **NOT** put your important data on the site.
|
- Due to testing purpose, data of [try.gogs.io](https://try.gogs.io) has been reset in **June 21, 2014** and will reset multiple times after. Please do **NOT** put your important data on the site.
|
||||||
- Demo site [try.gogits.org](http://try.gogits.org) is running under `dev` branch.
|
- Demo site [try.gogs.io](https://try.gogs.io) is running under `dev` branch.
|
||||||
|
|
||||||
#### Other language version
|
#### Other language version
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ The goal of this project is to make the easiest, fastest and most painless way t
|
||||||
|
|
||||||
- Please see [Documentation](http://gogs.io/docs/intro/) for project design, known issues, and change log.
|
- Please see [Documentation](http://gogs.io/docs/intro/) for project design, known issues, and change log.
|
||||||
- See [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) to follow the develop team.
|
- See [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) to follow the develop team.
|
||||||
- Try it before anything? Do it [online](http://try.gogits.org/Unknown/gogs) or go down to **Installation -> Install from binary** section!
|
- Try it before anything? Do it [online](https://try.gogs.io/Unknown/gogs) or go down to **Installation -> Install from binary** section!
|
||||||
- Having troubles? Get help from [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.md).
|
- Having troubles? Get help from [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.md).
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
@ -35,14 +35,16 @@ The goal of this project is to make the easiest, fastest and most painless way t
|
||||||
- Register/delete/rename account
|
- Register/delete/rename account
|
||||||
- Create/manage/delete organization with team management
|
- Create/manage/delete organization with team management
|
||||||
- Create/migrate/mirror/delete/watch/rename/transfer public/private repository
|
- Create/migrate/mirror/delete/watch/rename/transfer public/private repository
|
||||||
- Repository viewer/release/issue tracker/webhooks
|
- Repository viewer/release/issue tracker
|
||||||
|
- Repository and Organization level webhooks
|
||||||
- Add/remove repository collaborators
|
- Add/remove repository collaborators
|
||||||
- Gravatar and cache support
|
- Gravatar and cache support
|
||||||
- Mail service(register, issue)
|
- Mail service(register, issue)
|
||||||
- Administration panel
|
- Administration panel
|
||||||
|
- Slack webhook integration
|
||||||
- Supports MySQL, PostgreSQL and SQLite3
|
- Supports MySQL, PostgreSQL and SQLite3
|
||||||
- Social account login(GitHub, Google, QQ, Weibo)
|
- Social account login(GitHub, Google, QQ, Weibo)
|
||||||
- Multi-language support(English, Chinese, Germany etc.)
|
- Multi-language support(English, Chinese, Germany, French etc.)
|
||||||
|
|
||||||
## System Requirements
|
## System Requirements
|
||||||
|
|
||||||
|
@ -58,18 +60,17 @@ There are 5 ways to install Gogs:
|
||||||
- [Install from binary](http://gogs.io/docs/installation/install_from_binary.md): **STRONGLY RECOMMENDED**
|
- [Install from binary](http://gogs.io/docs/installation/install_from_binary.md): **STRONGLY RECOMMENDED**
|
||||||
- [Install from source](http://gogs.io/docs/installation/install_from_source.md)
|
- [Install from source](http://gogs.io/docs/installation/install_from_source.md)
|
||||||
- [Install from packages](http://gogs.io/docs/installation/install_from_packages.md)
|
- [Install from packages](http://gogs.io/docs/installation/install_from_packages.md)
|
||||||
- [Ship with Docker](https://github.com/gogits/gogs/tree/master/dockerfiles)
|
- [Ship with Docker](https://github.com/gogits/gogs/tree/master/docker)
|
||||||
- [Install with Vagrant](https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs)
|
- [Install with Vagrant](https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs)
|
||||||
|
|
||||||
## Acknowledgments
|
## Acknowledgments
|
||||||
|
|
||||||
- Router and middleware mechanism of [martini](http://martini.codegangsta.io/).
|
- Router and middleware mechanism of [Macaron](https://github.com/Unknwon/macaron).
|
||||||
- Mail Service, modules design is inspired by [WeTalk](https://github.com/beego/wetalk).
|
- Mail Service, modules design is inspired by [WeTalk](https://github.com/beego/wetalk).
|
||||||
- System Monitor Status is inspired by [GoBlog](https://github.com/fuxiaohei/goblog).
|
- System Monitor Status is inspired by [GoBlog](https://github.com/fuxiaohei/goblog).
|
||||||
- Usage and modification from [beego](http://beego.me) modules.
|
- Usage and modification from [beego](http://beego.me) modules.
|
||||||
- Thanks [lavachen](http://www.lavachen.cn/) and [Rocker](http://weibo.com/rocker1989) for designing Logo.
|
- Thanks [lavachen](http://www.lavachen.cn/) and [Rocker](http://weibo.com/rocker1989) for designing Logo.
|
||||||
- Thanks [gobuild.io](http://gobuild.io) for providing binary compile and download service.
|
- Thanks [gobuild.io](http://gobuild.io) for providing binary compile and download service.
|
||||||
- Great thanks to [Docker China](http://www.dockboard.org/) for providing [dockerfiles](https://github.com/gogits/gogs/tree/master/dockerfiles).
|
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
|
|
19
README_ZH.md
19
README_ZH.md
|
@ -3,9 +3,9 @@ Gogs - Go Git Service [![wercker status](https://app.wercker.com/status/ad0bdb0b
|
||||||
|
|
||||||
Gogs(Go Git Service) 是一个基于 Go 语言的自助 Git 服务。
|
Gogs(Go Git Service) 是一个基于 Go 语言的自助 Git 服务。
|
||||||
|
|
||||||
![Demo](http://gowalker.org/public/gogs_demo.gif)
|
![Demo](https://gowalker.org/public/gogs_demo.gif)
|
||||||
|
|
||||||
##### 当前版本:0.4.9 Beta
|
##### 当前版本:0.5.4 Beta
|
||||||
|
|
||||||
## 开发目的
|
## 开发目的
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||||
|
|
||||||
- 有关项目设计、已知问题和变更日志,请通过 [使用手册](http://gogs.io/docs/intro/) 查看。
|
- 有关项目设计、已知问题和变更日志,请通过 [使用手册](http://gogs.io/docs/intro/) 查看。
|
||||||
- 您可以到 [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) 跟随开发团队的脚步。
|
- 您可以到 [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) 跟随开发团队的脚步。
|
||||||
- 想要先睹为快?通过 [在线体验](http://try.gogits.org/Unknown/gogs) 或查看 **安装部署 -> 二进制安装** 小节。
|
- 想要先睹为快?通过 [在线体验](https://try.gogs.io/Unknown/gogs) 或查看 **安装部署 -> 二进制安装** 小节。
|
||||||
- 使用过程中遇到问题?尝试从 [故障排查](http://gogs.io/docs/intro/troubleshooting.md) 页面获取帮助。
|
- 使用过程中遇到问题?尝试从 [故障排查](http://gogs.io/docs/intro/troubleshooting.md) 页面获取帮助。
|
||||||
|
|
||||||
## 功能特性
|
## 功能特性
|
||||||
|
@ -26,14 +26,16 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||||
- 注册/删除/重命名 用户
|
- 注册/删除/重命名 用户
|
||||||
- 创建/管理/删除 组织以及团队管理功能
|
- 创建/管理/删除 组织以及团队管理功能
|
||||||
- 创建/迁移/镜像/删除/关注/重命名/转移 公开/私有 仓库
|
- 创建/迁移/镜像/删除/关注/重命名/转移 公开/私有 仓库
|
||||||
- 仓库 浏览/发布/工单管理/Web 钩子
|
- 仓库 浏览/发布/工单管理
|
||||||
|
- 仓库和组织级别 Web 钩子
|
||||||
- 添加/删除 仓库协作者
|
- 添加/删除 仓库协作者
|
||||||
- Gravatar 以及缓存支持
|
- Gravatar 以及缓存支持
|
||||||
- 邮件服务(注册、Issue)
|
- 邮件服务(注册、Issue)
|
||||||
- 管理员面板
|
- 管理员面板
|
||||||
|
- Slack Web 钩子集成
|
||||||
- 支持 MySQL、PostgreSQL 以及 SQLite3 数据库
|
- 支持 MySQL、PostgreSQL 以及 SQLite3 数据库
|
||||||
- 社交帐号登录(GitHub、Google、QQ、微博)
|
- 社交帐号登录(GitHub、Google、QQ、微博)
|
||||||
- 多语言支持(英文、简体中文、德语等等)
|
- 多语言支持(英文、简体中文、德语、法语等等)
|
||||||
|
|
||||||
## 系统要求
|
## 系统要求
|
||||||
|
|
||||||
|
@ -49,18 +51,17 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||||
- [二进制安装](http://gogs.io/docs/installation/install_from_binary.md): **强烈推荐**
|
- [二进制安装](http://gogs.io/docs/installation/install_from_binary.md): **强烈推荐**
|
||||||
- [源码安装](http://gogs.io/docs/installation/install_from_source.md)
|
- [源码安装](http://gogs.io/docs/installation/install_from_source.md)
|
||||||
- [包管理安装](http://gogs.io/docs/installation/install_from_packages.md)
|
- [包管理安装](http://gogs.io/docs/installation/install_from_packages.md)
|
||||||
- [采用 Docker 部署](https://github.com/gogits/gogs/tree/master/dockerfiles)
|
- [采用 Docker 部署](https://github.com/gogits/gogs/tree/master/docker)
|
||||||
- [通过 Vagrant 安装](https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs)
|
- [通过 Vagrant 安装](https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs)
|
||||||
|
|
||||||
## 特别鸣谢
|
## 特别鸣谢
|
||||||
|
|
||||||
|
- [Macaron](https://github.com/Unknwon/macaron) 的路由与中间件机制。
|
||||||
|
- [beego](http://beego.me) 模块的使用与修改。
|
||||||
- 基于 [WeTalk](https://github.com/beego/wetalk) 修改的邮件服务和模块设计。
|
- 基于 [WeTalk](https://github.com/beego/wetalk) 修改的邮件服务和模块设计。
|
||||||
- 基于 [GoBlog](https://github.com/fuxiaohei/goblog) 修改的系统监视状态。
|
- 基于 [GoBlog](https://github.com/fuxiaohei/goblog) 修改的系统监视状态。
|
||||||
- [beego](http://beego.me) 模块的使用与修改。
|
|
||||||
- [martini](http://martini.codegangsta.io/) 的路由与中间件机制。
|
|
||||||
- 感谢 [gobuild.io](http://gobuild.io) 提供二进制编译与下载服务。
|
- 感谢 [gobuild.io](http://gobuild.io) 提供二进制编译与下载服务。
|
||||||
- 感谢 [lavachen](http://www.lavachen.cn/) 和 [Rocker](http://weibo.com/rocker1989) 设计的 Logo。
|
- 感谢 [lavachen](http://www.lavachen.cn/) 和 [Rocker](http://weibo.com/rocker1989) 设计的 Logo。
|
||||||
- 感谢 [Docker 中文社区](http://www.dockboard.org/) 提供的 [dockerfiles](https://github.com/gogits/gogs/tree/master/dockerfiles)。
|
|
||||||
|
|
||||||
## 贡献成员
|
## 贡献成员
|
||||||
|
|
||||||
|
|
158
cmd/cert.go
Normal file
158
cmd/cert.go
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/pem"
|
||||||
|
"log"
|
||||||
|
"math/big"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
var CmdCert = cli.Command{
|
||||||
|
Name: "cert",
|
||||||
|
Usage: "Generate self-signed certificate",
|
||||||
|
Description: `Generate a self-signed X.509 certificate for a TLS server.
|
||||||
|
Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
|
||||||
|
Action: runCert,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
cli.StringFlag{"host", "", "Comma-separated hostnames and IPs to generate a certificate for", ""},
|
||||||
|
cli.StringFlag{"ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521", ""},
|
||||||
|
cli.IntFlag{"rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set", ""},
|
||||||
|
cli.StringFlag{"start-date", "", "Creation date formatted as Jan 1 15:04:05 2011", ""},
|
||||||
|
cli.DurationFlag{"duration", 365 * 24 * time.Hour, "Duration that certificate is valid for", ""},
|
||||||
|
cli.BoolFlag{"ca", "whether this cert should be its own Certificate Authority", ""},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func publicKey(priv interface{}) interface{} {
|
||||||
|
switch k := priv.(type) {
|
||||||
|
case *rsa.PrivateKey:
|
||||||
|
return &k.PublicKey
|
||||||
|
case *ecdsa.PrivateKey:
|
||||||
|
return &k.PublicKey
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pemBlockForKey(priv interface{}) *pem.Block {
|
||||||
|
switch k := priv.(type) {
|
||||||
|
case *rsa.PrivateKey:
|
||||||
|
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
|
||||||
|
case *ecdsa.PrivateKey:
|
||||||
|
b, err := x509.MarshalECPrivateKey(k)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("unable to marshal ECDSA private key: %v", err)
|
||||||
|
}
|
||||||
|
return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCert(ctx *cli.Context) {
|
||||||
|
if len(ctx.String("host")) == 0 {
|
||||||
|
log.Fatal("Missing required --host parameter")
|
||||||
|
}
|
||||||
|
|
||||||
|
var priv interface{}
|
||||||
|
var err error
|
||||||
|
switch ctx.String("ecdsa-curve") {
|
||||||
|
case "":
|
||||||
|
priv, err = rsa.GenerateKey(rand.Reader, ctx.Int("rsa-bits"))
|
||||||
|
case "P224":
|
||||||
|
priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
|
||||||
|
case "P256":
|
||||||
|
priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
|
case "P384":
|
||||||
|
priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||||
|
case "P521":
|
||||||
|
priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
||||||
|
default:
|
||||||
|
log.Fatalf("Unrecognized elliptic curve: %q", ctx.String("ecdsa-curve"))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to generate private key: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var notBefore time.Time
|
||||||
|
if len(ctx.String("start-date")) == 0 {
|
||||||
|
notBefore = time.Now()
|
||||||
|
} else {
|
||||||
|
notBefore, err = time.Parse("Jan 2 15:04:05 2006", ctx.String("start-date"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to parse creation date: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notAfter := notBefore.Add(ctx.Duration("duration"))
|
||||||
|
|
||||||
|
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||||
|
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to generate serial number: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
template := x509.Certificate{
|
||||||
|
SerialNumber: serialNumber,
|
||||||
|
Subject: pkix.Name{
|
||||||
|
Organization: []string{"Acme Co"},
|
||||||
|
},
|
||||||
|
NotBefore: notBefore,
|
||||||
|
NotAfter: notAfter,
|
||||||
|
|
||||||
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||||
|
BasicConstraintsValid: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
hosts := strings.Split(ctx.String("host"), ",")
|
||||||
|
for _, h := range hosts {
|
||||||
|
if ip := net.ParseIP(h); ip != nil {
|
||||||
|
template.IPAddresses = append(template.IPAddresses, ip)
|
||||||
|
} else {
|
||||||
|
template.DNSNames = append(template.DNSNames, h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Bool("ca") {
|
||||||
|
template.IsCA = true
|
||||||
|
template.KeyUsage |= x509.KeyUsageCertSign
|
||||||
|
}
|
||||||
|
|
||||||
|
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to create certificate: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
certOut, err := os.Create("cert.pem")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to open cert.pem for writing: %s", err)
|
||||||
|
}
|
||||||
|
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
||||||
|
certOut.Close()
|
||||||
|
log.Println("Written cert.pem")
|
||||||
|
|
||||||
|
keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("failed to open key.pem for writing: %v", err)
|
||||||
|
}
|
||||||
|
pem.Encode(keyOut, pemBlockForKey(priv))
|
||||||
|
keyOut.Close()
|
||||||
|
log.Println("Written key.pem")
|
||||||
|
}
|
|
@ -24,16 +24,18 @@ var CmdDump = cli.Command{
|
||||||
Description: `Dump compresses all related files and database into zip file.
|
Description: `Dump compresses all related files and database into zip file.
|
||||||
It can be used for backup and capture Gogs server image to send to maintainer`,
|
It can be used for backup and capture Gogs server image to send to maintainer`,
|
||||||
Action: runDump,
|
Action: runDump,
|
||||||
Flags: []cli.Flag{},
|
Flags: []cli.Flag{
|
||||||
|
cli.BoolFlag{"verbose, v", "show process details", ""},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDump(*cli.Context) {
|
func runDump(ctx *cli.Context) {
|
||||||
setting.NewConfigContext()
|
setting.NewConfigContext()
|
||||||
models.LoadModelsConfig()
|
models.LoadModelsConfig()
|
||||||
models.SetEngine()
|
models.SetEngine()
|
||||||
|
|
||||||
log.Printf("Dumping local repositories...%s", setting.RepoRootPath)
|
log.Printf("Dumping local repositories...%s", setting.RepoRootPath)
|
||||||
zip.Verbose = false
|
zip.Verbose = ctx.Bool("verbose")
|
||||||
defer os.Remove("gogs-repo.zip")
|
defer os.Remove("gogs-repo.zip")
|
||||||
if err := zip.PackTo(setting.RepoRootPath, "gogs-repo.zip", true); err != nil {
|
if err := zip.PackTo(setting.RepoRootPath, "gogs-repo.zip", true); err != nil {
|
||||||
log.Fatalf("Fail to dump local repositories: %v", err)
|
log.Fatalf("Fail to dump local repositories: %v", err)
|
||||||
|
|
|
@ -171,7 +171,13 @@ func runServ(k *cli.Context) {
|
||||||
uuid := uuid.NewV4().String()
|
uuid := uuid.NewV4().String()
|
||||||
os.Setenv("uuid", uuid)
|
os.Setenv("uuid", uuid)
|
||||||
|
|
||||||
gitcmd := exec.Command(verb, repoPath)
|
var gitcmd *exec.Cmd
|
||||||
|
verbs := strings.Split(verb, " ")
|
||||||
|
if len(verbs) == 2 {
|
||||||
|
gitcmd = exec.Command(verbs[0], verbs[1], repoPath)
|
||||||
|
} else {
|
||||||
|
gitcmd = exec.Command(verb, repoPath)
|
||||||
|
}
|
||||||
gitcmd.Dir = setting.RepoRootPath
|
gitcmd.Dir = setting.RepoRootPath
|
||||||
gitcmd.Stdout = os.Stdout
|
gitcmd.Stdout = os.Stdout
|
||||||
gitcmd.Stdin = os.Stdin
|
gitcmd.Stdin = os.Stdin
|
||||||
|
|
63
cmd/web.go
63
cmd/web.go
|
@ -11,6 +11,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/Unknwon/macaron"
|
"github.com/Unknwon/macaron"
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
|
@ -26,6 +27,7 @@ import (
|
||||||
"github.com/gogits/gogs/modules/auth/apiv1"
|
"github.com/gogits/gogs/modules/auth/apiv1"
|
||||||
"github.com/gogits/gogs/modules/avatar"
|
"github.com/gogits/gogs/modules/avatar"
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
|
"github.com/gogits/gogs/modules/git"
|
||||||
"github.com/gogits/gogs/modules/log"
|
"github.com/gogits/gogs/modules/log"
|
||||||
"github.com/gogits/gogs/modules/middleware"
|
"github.com/gogits/gogs/modules/middleware"
|
||||||
"github.com/gogits/gogs/modules/middleware/binding"
|
"github.com/gogits/gogs/modules/middleware/binding"
|
||||||
|
@ -50,6 +52,7 @@ and it takes care of all the other things for you`,
|
||||||
|
|
||||||
// checkVersion checks if binary matches the version of templates files.
|
// checkVersion checks if binary matches the version of templates files.
|
||||||
func checkVersion() {
|
func checkVersion() {
|
||||||
|
// Templates.
|
||||||
data, err := ioutil.ReadFile(path.Join(setting.StaticRootPath, "templates/.VERSION"))
|
data, err := ioutil.ReadFile(path.Join(setting.StaticRootPath, "templates/.VERSION"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(4, "Fail to read 'templates/.VERSION': %v", err)
|
log.Fatal(4, "Fail to read 'templates/.VERSION': %v", err)
|
||||||
|
@ -57,6 +60,12 @@ func checkVersion() {
|
||||||
if string(data) != setting.AppVer {
|
if string(data) != setting.AppVer {
|
||||||
log.Fatal(4, "Binary and template file version does not match, did you forget to recompile?")
|
log.Fatal(4, "Binary and template file version does not match, did you forget to recompile?")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Macaron.
|
||||||
|
macaronVer := git.MustParseVersion(strings.Join(strings.Split(macaron.Version(), ".")[:3], "."))
|
||||||
|
if macaronVer.LessThan(git.MustParseVersion("0.1.8")) {
|
||||||
|
log.Fatal(4, "Macaron version does not match, did you forget to update?(github.com/Unknwon/macaron)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// newMacaron initializes Macaron instance.
|
// newMacaron initializes Macaron instance.
|
||||||
|
@ -64,20 +73,22 @@ func newMacaron() *macaron.Macaron {
|
||||||
m := macaron.New()
|
m := macaron.New()
|
||||||
m.Use(macaron.Logger())
|
m.Use(macaron.Logger())
|
||||||
m.Use(macaron.Recovery())
|
m.Use(macaron.Recovery())
|
||||||
m.Use(macaron.Static("public",
|
m.Use(macaron.Static(
|
||||||
|
path.Join(setting.StaticRootPath, "public"),
|
||||||
macaron.StaticOptions{
|
macaron.StaticOptions{
|
||||||
SkipLogging: !setting.DisableRouterLog,
|
SkipLogging: !setting.DisableRouterLog,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
if setting.EnableGzip {
|
// if setting.EnableGzip {
|
||||||
m.Use(macaron.Gzip())
|
// m.Use(macaron.Gzip())
|
||||||
}
|
// }
|
||||||
m.Use(macaron.Renderer(macaron.RenderOptions{
|
m.Use(macaron.Renderer(macaron.RenderOptions{
|
||||||
Directory: path.Join(setting.StaticRootPath, "templates"),
|
Directory: path.Join(setting.StaticRootPath, "templates"),
|
||||||
Funcs: []template.FuncMap{base.TemplateFuncs},
|
Funcs: []template.FuncMap{base.TemplateFuncs},
|
||||||
IndentJSON: macaron.Env != macaron.PROD,
|
IndentJSON: macaron.Env != macaron.PROD,
|
||||||
}))
|
}))
|
||||||
m.Use(i18n.I18n(i18n.Options{
|
m.Use(i18n.I18n(i18n.Options{
|
||||||
|
SubURL: setting.AppSubUrl,
|
||||||
Langs: setting.Langs,
|
Langs: setting.Langs,
|
||||||
Names: setting.Names,
|
Names: setting.Names,
|
||||||
Redirect: true,
|
Redirect: true,
|
||||||
|
@ -87,7 +98,9 @@ func newMacaron() *macaron.Macaron {
|
||||||
Interval: setting.CacheInternal,
|
Interval: setting.CacheInternal,
|
||||||
Conn: setting.CacheConn,
|
Conn: setting.CacheConn,
|
||||||
}))
|
}))
|
||||||
m.Use(captcha.Captchaer())
|
m.Use(captcha.Captchaer(captcha.Options{
|
||||||
|
SubURL: setting.AppSubUrl,
|
||||||
|
}))
|
||||||
m.Use(session.Sessioner(session.Options{
|
m.Use(session.Sessioner(session.Options{
|
||||||
Provider: setting.SessionProvider,
|
Provider: setting.SessionProvider,
|
||||||
Config: *setting.SessionConfig,
|
Config: *setting.SessionConfig,
|
||||||
|
@ -95,6 +108,8 @@ func newMacaron() *macaron.Macaron {
|
||||||
m.Use(csrf.Generate(csrf.Options{
|
m.Use(csrf.Generate(csrf.Options{
|
||||||
Secret: setting.SecretKey,
|
Secret: setting.SecretKey,
|
||||||
SetCookie: true,
|
SetCookie: true,
|
||||||
|
Header: "X-Csrf-Token",
|
||||||
|
CookiePath: setting.AppSubUrl,
|
||||||
}))
|
}))
|
||||||
m.Use(toolbox.Toolboxer(m, toolbox.Options{
|
m.Use(toolbox.Toolboxer(m, toolbox.Options{
|
||||||
HealthCheckFuncs: []*toolbox.HealthCheckFuncDesc{
|
HealthCheckFuncs: []*toolbox.HealthCheckFuncDesc{
|
||||||
|
@ -123,6 +138,7 @@ func runWeb(*cli.Context) {
|
||||||
|
|
||||||
// Routers.
|
// Routers.
|
||||||
m.Get("/", ignSignIn, routers.Home)
|
m.Get("/", ignSignIn, routers.Home)
|
||||||
|
m.Get("/explore", ignSignIn, routers.Explore)
|
||||||
m.Get("/install", bindIgnErr(auth.InstallForm{}), routers.Install)
|
m.Get("/install", bindIgnErr(auth.InstallForm{}), routers.Install)
|
||||||
m.Post("/install", bindIgnErr(auth.InstallForm{}), routers.InstallPost)
|
m.Post("/install", bindIgnErr(auth.InstallForm{}), routers.InstallPost)
|
||||||
m.Group("", func(r *macaron.Router) {
|
m.Group("", func(r *macaron.Router) {
|
||||||
|
@ -183,7 +199,8 @@ func runWeb(*cli.Context) {
|
||||||
r.Get("/logout", user.SignOut)
|
r.Get("/logout", user.SignOut)
|
||||||
})
|
})
|
||||||
|
|
||||||
m.Get("/user/:username", ignSignIn, user.Profile) // TODO: Legacy
|
// FIXME: Legacy
|
||||||
|
m.Get("/user/:username", ignSignIn, user.Profile)
|
||||||
|
|
||||||
// Gravatar service.
|
// Gravatar service.
|
||||||
avt := avatar.CacheServer("public/img/avatar/", "public/img/avatar_default.jpg")
|
avt := avatar.CacheServer("public/img/avatar/", "public/img/avatar_default.jpg")
|
||||||
|
@ -259,6 +276,13 @@ func runWeb(*cli.Context) {
|
||||||
m.Group("/settings", func(r *macaron.Router) {
|
m.Group("/settings", func(r *macaron.Router) {
|
||||||
r.Get("", org.Settings)
|
r.Get("", org.Settings)
|
||||||
r.Post("", bindIgnErr(auth.UpdateOrgSettingForm{}), org.SettingsPost)
|
r.Post("", bindIgnErr(auth.UpdateOrgSettingForm{}), org.SettingsPost)
|
||||||
|
r.Get("/hooks", org.SettingsHooks)
|
||||||
|
r.Get("/hooks/new", repo.WebHooksNew)
|
||||||
|
r.Post("/hooks/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
|
||||||
|
r.Post("/hooks/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
|
||||||
|
r.Get("/hooks/:id", repo.WebHooksEdit)
|
||||||
|
r.Post("/hooks/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
|
||||||
|
r.Post("/hooks/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
|
||||||
r.Route("/delete", "GET,POST", org.SettingsDelete)
|
r.Route("/delete", "GET,POST", org.SettingsDelete)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -284,9 +308,11 @@ func runWeb(*cli.Context) {
|
||||||
r.Route("/collaboration", "GET,POST", repo.SettingsCollaboration)
|
r.Route("/collaboration", "GET,POST", repo.SettingsCollaboration)
|
||||||
r.Get("/hooks", repo.Webhooks)
|
r.Get("/hooks", repo.Webhooks)
|
||||||
r.Get("/hooks/new", repo.WebHooksNew)
|
r.Get("/hooks/new", repo.WebHooksNew)
|
||||||
r.Post("/hooks/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
|
r.Post("/hooks/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
|
||||||
|
r.Post("/hooks/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
|
||||||
r.Get("/hooks/:id", repo.WebHooksEdit)
|
r.Get("/hooks/:id", repo.WebHooksEdit)
|
||||||
r.Post("/hooks/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
|
r.Post("/hooks/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
|
||||||
|
r.Post("/hooks/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
|
||||||
})
|
})
|
||||||
}, reqSignIn, middleware.RepoAssignment(true), reqTrueOwner)
|
}, reqSignIn, middleware.RepoAssignment(true), reqTrueOwner)
|
||||||
|
|
||||||
|
@ -327,6 +353,8 @@ func runWeb(*cli.Context) {
|
||||||
r.Get("/issues/:index", repo.ViewIssue)
|
r.Get("/issues/:index", repo.ViewIssue)
|
||||||
r.Get("/pulls", repo.Pulls)
|
r.Get("/pulls", repo.Pulls)
|
||||||
r.Get("/branches", repo.Branches)
|
r.Get("/branches", repo.Branches)
|
||||||
|
r.Get("/archive/*", repo.Download)
|
||||||
|
r.Get("/issues2/", repo.Issues2)
|
||||||
}, ignSignIn, middleware.RepoAssignment(true))
|
}, ignSignIn, middleware.RepoAssignment(true))
|
||||||
|
|
||||||
m.Group("/:username/:reponame", func(r *macaron.Router) {
|
m.Group("/:username/:reponame", func(r *macaron.Router) {
|
||||||
|
@ -339,22 +367,29 @@ func runWeb(*cli.Context) {
|
||||||
r.Get("/commit/:branchname", repo.Diff)
|
r.Get("/commit/:branchname", repo.Diff)
|
||||||
r.Get("/commit/:branchname/*", repo.Diff)
|
r.Get("/commit/:branchname/*", repo.Diff)
|
||||||
r.Get("/releases", repo.Releases)
|
r.Get("/releases", repo.Releases)
|
||||||
r.Get("/archive/*.*", repo.Download)
|
r.Get("/compare/:before([a-z0-9]+)...:after([a-z0-9]+)", repo.CompareDiff)
|
||||||
}, ignSignIn, middleware.RepoAssignment(true, true))
|
}, ignSignIn, middleware.RepoAssignment(true, true))
|
||||||
|
|
||||||
m.Group("/:username", func(r *macaron.Router) {
|
m.Group("/:username", func(r *macaron.Router) {
|
||||||
r.Get("/:reponame", middleware.RepoAssignment(true, true, true), repo.Home)
|
r.Get("/:reponame", ignSignIn, middleware.RepoAssignment(true, true, true), repo.Home)
|
||||||
m.Group("/:reponame", func(r *macaron.Router) {
|
r.Any("/:reponame/*", ignSignInAndCsrf, repo.Http)
|
||||||
r.Any("/*", repo.Http)
|
})
|
||||||
|
|
||||||
|
// robots.txt
|
||||||
|
m.Get("/robots.txt", func(ctx *middleware.Context) {
|
||||||
|
if setting.HasRobotsTxt {
|
||||||
|
ctx.ServeFile(path.Join(setting.CustomPath, "robots.txt"))
|
||||||
|
} else {
|
||||||
|
ctx.Error(404)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}, ignSignInAndCsrf)
|
|
||||||
|
|
||||||
// Not found handler.
|
// Not found handler.
|
||||||
m.NotFound(routers.NotFound)
|
m.NotFound(routers.NotFound)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
|
listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
|
||||||
log.Info("Listen: %v://%s", setting.Protocol, listenAddr)
|
log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubUrl)
|
||||||
switch setting.Protocol {
|
switch setting.Protocol {
|
||||||
case setting.HTTP:
|
case setting.HTTP:
|
||||||
err = http.ListenAndServe(listenAddr, m)
|
err = http.ListenAndServe(listenAddr, m)
|
||||||
|
|
12
conf/app.ini
12
conf/app.ini
|
@ -1,6 +1,5 @@
|
||||||
; App name that shows on every page title
|
; App name that shows on every page title
|
||||||
APP_NAME = Gogs: Go Git Service
|
APP_NAME = Gogs: Go Git Service
|
||||||
APP_LOGO = img/favicon.png
|
|
||||||
; Change it if you run locally
|
; Change it if you run locally
|
||||||
RUN_USER = git
|
RUN_USER = git
|
||||||
; Either "dev", "prod" or "test", default is "dev"
|
; Either "dev", "prod" or "test", default is "dev"
|
||||||
|
@ -22,14 +21,14 @@ OFFLINE_MODE = false
|
||||||
DISABLE_ROUTER_LOG = false
|
DISABLE_ROUTER_LOG = false
|
||||||
; Generate steps:
|
; Generate steps:
|
||||||
; $ cd path/to/gogs/custom/https
|
; $ cd path/to/gogs/custom/https
|
||||||
; $ go run $GOROOT/src/pkg/crypto/tls/generate_cert.go -ca=true -duration=8760h0m0s -host=myhost.example.com
|
; $ ./gogs cert -ca=true -duration=8760h0m0s -host=myhost.example.com
|
||||||
CERT_FILE = custom/https/cert.pem
|
CERT_FILE = custom/https/cert.pem
|
||||||
KEY_FILE = custom/https/key.pem
|
KEY_FILE = custom/https/key.pem
|
||||||
; Upper level of template and static file path
|
; Upper level of template and static file path
|
||||||
; default is the path where Gogs is executed
|
; default is the path where Gogs is executed
|
||||||
STATIC_ROOT_PATH =
|
STATIC_ROOT_PATH =
|
||||||
; Application level GZIP support
|
; Application level GZIP support
|
||||||
ENABLE_GZIP = false
|
#ENABLE_GZIP = false
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
; Either "mysql", "postgres" or "sqlite3", it's your choice
|
; Either "mysql", "postgres" or "sqlite3", it's your choice
|
||||||
|
@ -253,6 +252,9 @@ DRIVER =
|
||||||
; Based on xorm, e.g.: root:root@localhost/gogs?charset=utf8
|
; Based on xorm, e.g.: root:root@localhost/gogs?charset=utf8
|
||||||
CONN =
|
CONN =
|
||||||
|
|
||||||
|
[git]
|
||||||
|
MAX_GITDIFF_LINES = 10000
|
||||||
|
|
||||||
[i18n]
|
[i18n]
|
||||||
LANGS = en-US,zh-CN,de-DE,nl-NL
|
LANGS = en-US,zh-CN,de-DE,fr-CA,nl-NL
|
||||||
NAMES = English,简体中文,Deutsch,Nederlands
|
NAMES = English,简体中文,Deutsch,Français,Nederlands
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
app_desc = Ein schmerzloses selbst gehostetes Git-Service welches in Go geschrieben wurde
|
app_desc = Ein einfacher, selbst gehosteter Git-Service, geschrieben in Go.
|
||||||
|
|
||||||
home = Home
|
home = Home
|
||||||
dashboard = Dashboard
|
dashboard = Dashboard
|
||||||
|
@ -12,23 +12,23 @@ register = Registrieren
|
||||||
website = Webseite
|
website = Webseite
|
||||||
version = Version
|
version = Version
|
||||||
page = Seite
|
page = Seite
|
||||||
template = Template
|
template = Vorlage
|
||||||
language = Sprache
|
language = Sprache
|
||||||
|
|
||||||
username = Benutzername
|
username = Benutzername
|
||||||
email = E-mail
|
email = E-Mail
|
||||||
password = Kennwort
|
password = Passwort
|
||||||
re_type = neu tippen
|
re_type = wiederholen
|
||||||
captcha = Captcha
|
captcha = Captcha
|
||||||
|
|
||||||
repository = Repositorie
|
repository = Repository
|
||||||
organization = Organisation
|
organization = Organisation
|
||||||
mirror = Spiegel
|
mirror = Spiegel
|
||||||
new_repo = Neues Repository
|
new_repo = Neues Repository
|
||||||
new_migrate = Neue Migration
|
new_migrate = Neue Migration
|
||||||
new_org = Neue Organisation
|
new_org = Neue Organisation
|
||||||
manage_org = Organisationen verwalten
|
manage_org = Organisationen verwalten
|
||||||
admin_panel = Admin Panel
|
admin_panel = Admin-Panel
|
||||||
account_settings = Kontoeinstellungen
|
account_settings = Kontoeinstellungen
|
||||||
settings = Einstellungen
|
settings = Einstellungen
|
||||||
|
|
||||||
|
@ -38,214 +38,276 @@ issues = Issues
|
||||||
|
|
||||||
cancel = Abbrechen
|
cancel = Abbrechen
|
||||||
|
|
||||||
|
[install]
|
||||||
|
install = Installation
|
||||||
|
title = Installation für erstmaligen Start
|
||||||
|
requite_db_desc = Gogs erfordert MySQL, PostgreSQL oder SQLite 3, aber SQLite3 ist in der offiziellen binären Version akiviert.
|
||||||
|
db_type = Datenbanktyp
|
||||||
|
host = Host
|
||||||
|
user = Benutzer
|
||||||
|
password = Passwort
|
||||||
|
db_name = Datenbankname
|
||||||
|
db_helper = Bitte verwenden InnoDB-Engine mit utf8_general_ci Zeichensatz für MySQL.
|
||||||
|
ssl_mode = SSL-Modus
|
||||||
|
path = Pfad
|
||||||
|
sqlite_helper = Der Dateipfad des SQLite3 Datenbank.
|
||||||
|
general_title = Allgemeine Einstellungen von Gogs
|
||||||
|
repo_path = Repository Root-Verzeichnispfad
|
||||||
|
repo_path_helper = Alle Git-Repositorys werden in diesem Verzeichnis gespeichert.
|
||||||
|
run_user = Ausführender Benutzer
|
||||||
|
run_user_helper = Der Benutzer muss die Zugriffsberechtigung für das Repository Root-Verzeichnis haben und der ausführende Benutzer von Gogs sein.
|
||||||
|
domain = Domain
|
||||||
|
domain_helper = Dies hat Auswirkung auf die SSH clone URLs.
|
||||||
|
app_url = Anwendungs-URL
|
||||||
|
app_url_helper = Dies hat Auswirkung auf die HTTP/HTTPS clone URLs und für die E-Mails.
|
||||||
|
email_title = E-Mail-Service-Einstellungen(Optional)
|
||||||
|
smtp_host = SMTP Host
|
||||||
|
mailer_user = Sender E-mail
|
||||||
|
mailer_password = Sender Passwort
|
||||||
|
notify_title = Benachrichtigungseinstellungen(Optional)
|
||||||
|
register_confirm = Registrierungsbestätigung aktvieren
|
||||||
|
mail_notify = E-Mail-Benachrichtgung aktivieren
|
||||||
|
admin_title = Konto-Einstellungen für den Administrator
|
||||||
|
admin_name = Benutzername
|
||||||
|
admin_password = Passwort
|
||||||
|
confirm_password = Passwort bestätigen
|
||||||
|
admin_email = E-Mail
|
||||||
|
install_gogs = Gogs installieren
|
||||||
|
test_git_failed = Fehler beim Test des 'git' Kommandos: %v
|
||||||
|
sqlite3_not_available = Deine Version unterstüzt nicht SQLite3, bitte downloade dir die offiziele binäre Version von http://gogs.io/docs/installation/install_from_binary.html, NICHT die gobuild Version.
|
||||||
|
invalid_db_setting = Datenbank-Einstellungen sind nicht korrekt: %v
|
||||||
|
invalid_repo_path = Repository Root-Verzeichnis ist ungültig: %v
|
||||||
|
run_user_not_match = Der ausführende Benutzer ist nicht der aktuelle Benutzer: %s -> %s
|
||||||
|
save_config_failed = Versuche die Konfiguration zu speichern ist fehlgeschlagen: %v
|
||||||
|
invalid_admin_setting = Admin-Konto Einstellungen sind ungültig: %v
|
||||||
|
install_success = Herzlich Willkommen! Wir sind froh, dass du dich für Gogs entschieden hast. Hab viel Vergnügen damit.
|
||||||
|
|
||||||
[home]
|
[home]
|
||||||
uname_holder = Benutzername oder E-mail
|
uname_holder = Benutzername oder E-Mail
|
||||||
password_holder = Kennwort
|
password_holder = Passwort
|
||||||
switch_dashboard_context = Switch Dashboard Context
|
switch_dashboard_context = Switch Dashboard Context
|
||||||
my_repos = Meine Repositories
|
my_repos = Meine Repositorys
|
||||||
collaborative_repos = Collaborative Repositories
|
collaborative_repos = Gemeinschaftliche Repositorys
|
||||||
my_orgs = Meine Organisationen
|
my_orgs = Meine Organisationen
|
||||||
my_mirrors = Meine Spiegel
|
my_mirrors = Meine Spiegel
|
||||||
|
|
||||||
|
[explore]
|
||||||
|
repos = Repositories
|
||||||
|
|
||||||
[auth]
|
[auth]
|
||||||
create_new_account = Neues Konto erstellen
|
create_new_account = Neues Konto erstellen
|
||||||
register_hepler_msg = Sie haben bereits ein Konto? Jetzt anmelden!
|
register_hepler_msg = Du hast schon ein Konto? Jetzt anmelden!
|
||||||
social_register_hepler_msg = Sie haben bereits ein Konto? Verknüpfe es jetzt!
|
social_register_hepler_msg = Du hast schon ein soziales Konto? Jetzt verknüpfen!
|
||||||
disable_register_prompt = Es tut uns leid, die Registrierung wurde deaktiviert. Bitte wende Sie sich an den Administrator.
|
disable_register_prompt = Es tut uns leid, die Registrierung wurde deaktiviert. Bitte wende dich an den Administrator.
|
||||||
disable_register_mail = Es tut uns leid, die Registrierung E-Mail Bestätigung wurde deaktiviert.
|
disable_register_mail = Es tut uns leid, die Bestätigung der Registrierungs-E-Mail wurde deaktiviert.
|
||||||
remember_me = Erinnere mich
|
remember_me = angemeldet bleiben
|
||||||
forgot_password= Kennwort vergessen
|
forgot_password= Passwort vergessen
|
||||||
forget_password = Kennwort vergessen?
|
forget_password = Passwort vergessen?
|
||||||
sign_up_now = Benötigen Sie ein Konto? Registrieren Sie sich jetzt.
|
sign_up_now = Du willst ein Konto? Jetzt registrieren!
|
||||||
confirmation_mail_sent_prompt = A new confirmation e-mail has been sent to <b>%s</b>, please check your inbox within the next %d hours to complete your registration.
|
confirmation_mail_sent_prompt = Eine neu Bestätigungs-E-Mail wurde an <b>%s</b> gesendet. Kontrolliere dein Postfach innerhalb der nächsten %d Stunden um die Registrierung abzuschließen.
|
||||||
sign_in_email = Melden Sie sich mit Ihrer E-Mailadresse an
|
sign_in_email = Melden dich mit deiner E-Mail-Adresse an
|
||||||
active_your_account = Aktivieren Sie Ihr Konto
|
active_your_account = Aktivieren dein Konto
|
||||||
resent_limit_prompt = Sorry, you are sending an activation e-mail too frequently. Please wait 3 minutes.
|
resent_limit_prompt = Es tut uns leid, du sendest zu häufig Aktivierungs-E-Mails. Bitte warte 3 Minuten.
|
||||||
has_unconfirmed_mail = Hi %s, you have an unconfirmed email address(<b>%s</b>). If you haven't received a confirmation e-mail or need to resend a new one, please click on the button below.
|
has_unconfirmed_mail = Hallo %s, du hast eine unbestätigte E-Mail-Adresse (<b>%s</b>). Falls du noch keine Bestätigungs-E-Mail erhalten hast oder eine neue senden musst, klicke auf den unteren Button.
|
||||||
resend_mail = Klicken Sie hier, um Ihre Aktivierungs-E-Mail erneut senden
|
resend_mail = Hier klicken, um deine Aktivierungs-E-Mail erneut zu versenden
|
||||||
email_not_associate = Diese E-Mail-Adresse ist mit keinen Konto verknüpft.
|
email_not_associate = Diese E-Mail-Adresse ist mit keinem Konto verknüpft.
|
||||||
send_reset_mail = Klicken Sie hier, um sich das E-Mail zum Kennwort zurücksetzen erneut zu senden
|
send_reset_mail = Hier klicken, um die E-Mail zum Passwort-zurücksetzen erneut zu versenden
|
||||||
reset_password = Ihr Kennwort zurücksetzen
|
reset_password = Passwort zurücksetzen
|
||||||
invalid_code = Es tut uns leid, Ihre Bestätigungscode abgelaufen ist oder nicht gültig.
|
invalid_code = Es tut uns leid, der Bestätigungscode ist abgelaufen oder ungültig.
|
||||||
reset_password_helper = Klicken Sie hier, um Ihr Kennwort zurückzusetzen
|
reset_password_helper = Hier klicken, um das Passwort zurückzusetzen
|
||||||
password_too_short = Passwortlänge kann nicht weniger als 6 sein.
|
password_too_short = Das Passwort muss mindenstens 6 Zeichen lang sein
|
||||||
|
|
||||||
[form]
|
[form]
|
||||||
UserName = Benutzername
|
UserName = Benutzername
|
||||||
RepoName = Repository Name
|
RepoName = Repository-Name
|
||||||
Email = E-Mail-Adresse
|
Email = E-Mail-Adresse
|
||||||
Password = Kennwort
|
Password = Passwort
|
||||||
Retype = Kennwort erneut eingeben
|
Retype = Passwort erneut eingeben
|
||||||
SSHTitle = SSH Schlüsselname
|
SSHTitle = SSH-Schlüsselname
|
||||||
HttpsUrl = HTTPS URL
|
HttpsUrl = HTTPS-URL
|
||||||
PayloadUrl = Payload URL
|
PayloadUrl = Payload-URL
|
||||||
TeamName = Teamname
|
TeamName = Teamname
|
||||||
AuthName = Authentifizierungsname
|
AuthName = Authentifizierungsname
|
||||||
|
AdminEmail = Admin E-mail
|
||||||
|
|
||||||
require_error = ` darf nicht leer sein.`
|
require_error = ` darf nicht leer sein.`
|
||||||
alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.`
|
alpha_dash_error = ` kann ausschließlich alphanumerische Zeichen und "-_" enthalten.`
|
||||||
alpha_dash_dot_error = ` must be valid alpha or numeric or dash(-_) or dot characters.`
|
alpha_dash_dot_error = ` kann ausschließlich alphanumerische Zeichen und ".-_" enthalten.`
|
||||||
min_size_error = ` muss mindestens %s Zeichen enthalten.`
|
min_size_error = ` muss mindestens %s Zeichen enthalten.`
|
||||||
max_size_error = ` darf höchstens %s Zeichen enthalten.`
|
max_size_error = ` darf höchstens %s Zeichen enthalten.`
|
||||||
email_error = ` ist keine gültige E-Mail-Adresse.`
|
email_error = ` ist keine gültige E-Mail-Adresse.`
|
||||||
url_error = ` ist keine gültige URL.`
|
url_error = ` ist keine gültige URL.`
|
||||||
unknown_error = Unbekannter Fehler:
|
unknown_error = Unbekannter Fehler:
|
||||||
captcha_incorrect = Captcha stimmt nicht überein.
|
captcha_incorrect = Captcha stimmt nicht überein.
|
||||||
password_not_match = Die Kennwörter stimmen nicht überein.
|
password_not_match = Die Passwörter stimmen nicht überein.
|
||||||
|
|
||||||
username_been_taken = Benutzername ist bereits vergeben.
|
username_been_taken = Benutzername ist bereits vergeben.
|
||||||
repo_name_been_taken = Repository Name ist bereits vergeben.
|
repo_name_been_taken = Repository-Name ist bereits vergeben.
|
||||||
org_name_been_taken = Organisationsname ist bereits vergeben.
|
org_name_been_taken = Organisationsname ist bereits vergeben.
|
||||||
team_name_been_taken = Teamname ist bereits vergeben.
|
team_name_been_taken = Teamname ist bereits vergeben.
|
||||||
email_been_used = E-Mail-Adresse ist bereits vergeben.
|
email_been_used = E-Mail-Adresse wird bereits verwendet.
|
||||||
ssh_key_been_used = Public-Key Name wird bereits verwendet.
|
ssh_key_been_used = SSH-Schlüsselname wird bereits verwendet.
|
||||||
illegal_username = Ihr Benutzername enthält ungültige Zeichen.
|
illegal_username = Benutzername enthält ungültige Zeichen.
|
||||||
illegal_repo_name = Repository Name enthält ungültige Zeichen.
|
illegal_repo_name = Repository-Name enthält ungültige Zeichen.
|
||||||
illegal_org_name = Organisationsname enthält ungültige Zeichen.
|
illegal_org_name = Organisationsname enthält ungültige Zeichen.
|
||||||
illegal_team_name = Teamname enthält ungültige Zeichen.
|
illegal_team_name = Teamname enthält ungültige Zeichen.
|
||||||
username_password_incorrect = Benutzername oder Kennwort ist nicht korrekt.
|
username_password_incorrect = Benutzername oder Passwort ist nicht korrekt.
|
||||||
enterred_invalid_repo_name = Bitte stellen Sie sicher, dass der eingegeben Repository Name richtig ist.
|
enterred_invalid_repo_name = Bitte stelle sicher, dass der eingegeben Repository-Name richtig ist.
|
||||||
enterred_invalid_owner_name = Bitte stellen Sie sicher, dass der eingegeben Eigentümername richtig ist.
|
enterred_invalid_owner_name = Bitte stelle sicher, dass der eingegeben Besitzername richtig ist.
|
||||||
enterred_invalid_password = Bitte stellen Sie sicher, dass das eingegebene Passwort richtig ist.
|
enterred_invalid_password = Bitte stelle sicher, dass das eingegebene Passwort richtig ist.
|
||||||
user_not_exist = Angegebener Benutzer existiert nicht.
|
user_not_exist = Angegebener Benutzer existiert nicht.
|
||||||
last_org_owner = The user to remove is the last member in owner team. There must be another owner.
|
last_org_owner = Der zu entfernende Benutzer ist der letzte Teambesitzer. Es muss einen anderen Besitzer geben.
|
||||||
|
|
||||||
invalid_ssh_key = Leider sind wir nicht in der Lage, Ihren SSH-Schlüssel zu überprüfen: %s
|
invalid_ssh_key = Leider sind wir nicht in der Lage, Ihren SSH-Schlüssel zu überprüfen: %s
|
||||||
auth_failed = Authentifizierung fehlgeschlagen: %v
|
auth_failed = Authentifizierung fehlgeschlagen: %v
|
||||||
|
|
||||||
still_own_repo = Your account still have ownership of repository, you have to delete or transfer them first.
|
still_own_repo = Dein Konto besitzt noch Repositorys. Diese müssen zuerst gelöscht oder übertragen werden.
|
||||||
org_still_own_repo = This organization still have ownership of repository, you have to delete or transfer them first.
|
org_still_own_repo = Diese Organisation besitzt noch Repositorys. Diese müssen zuerst gelöscht oder übertragen werden.
|
||||||
|
|
||||||
still_own_user = This authentication still has used by some users, you should move them and then delete again.
|
still_own_user = Diese Authentifizierung wird noch von einigen Benutzern genutzt. Entferne diese zuvor und lösche erneut.
|
||||||
|
|
||||||
[settings]
|
[settings]
|
||||||
profile = Profil
|
profile = Profil
|
||||||
password = Kennwort
|
password = Passwort
|
||||||
ssh_keys = SSH-Schlüssel
|
ssh_keys = SSH-Schlüssel
|
||||||
social = Social Konten
|
social = Soziale Konten
|
||||||
orgs = Organisationen
|
orgs = Organisationen
|
||||||
delete = Delete Accoount
|
delete = Konto löschen
|
||||||
|
uid = Uid
|
||||||
|
|
||||||
public_profile = Öffentliches Profil
|
public_profile = Öffentliches Profil
|
||||||
profile_desc = Your Email address is public and will be used for any account related notifications, and any web based operations made via the site.
|
profile_desc = Deine E-Mail-Adresse ist öffentlich und dient dazu, dir Benachrichtigungen bezüglich deines Kontos und deiner Repositorys zu schicken.
|
||||||
full_name = Vollständiger Name
|
full_name = Vollständiger Name
|
||||||
website = Website
|
website = Webseite
|
||||||
location = Standort
|
location = Standort
|
||||||
update_profile = Profil aktualisieren
|
update_profile = Profil aktualisieren
|
||||||
update_profile_success = Your profile has been successfully updated.
|
update_profile_success = Profil aktualisiert
|
||||||
|
|
||||||
change_password = Kennwort ändern
|
change_password = Passwort ändern
|
||||||
old_password = Aktuelles Kennwort
|
old_password = Aktuelles Passwort
|
||||||
new_password = Neues Kennwort
|
new_password = Neues Passwort
|
||||||
password_incorrect = Aktuelles Kennwort ist nicht korrekt.
|
password_incorrect = Aktuelles Passwort ist nicht korrekt.
|
||||||
change_password_success = Kennwort erfolgreich geändert. Sie können nun mittels des neuen Kennwortes anmelden.
|
change_password_success = Passwort geändert. Du kannst dich jetzt mit dem neuen Passwort anmelden.
|
||||||
|
|
||||||
manage_ssh_keys = SSH-Schlüssel verwalten
|
manage_ssh_keys = SSH-Schlüssel verwalten
|
||||||
add_key = Schlüssel hinzufügen
|
add_key = SSH-Schlüssel hinzufügen
|
||||||
ssh_desc = This is a list of SSH keys associated with your account. Remove any keys that you do not recognize.
|
ssh_desc = Dies ist eine Liste aller SSH-Schlüssel, die mit deinem Konto verknüpft sind. Entferne alle Schlüssel, die du nicht kennst.
|
||||||
ssh_helper = <strong>Need help?</strong> Check out our guide to <a href="https://help.github.com/articles/generating-ssh-keys">generating SSH keys</a> or troubleshoot <a href="https://help.github.com/ssh-issues/">common SSH Problems</a>.
|
ssh_helper = <strong>Du brauchst Hilfe?</strong> Hier ist eine Anleitung zum <a href="https://help.github.com/articles/generating-ssh-keys">Erzeugen von SSH-Schlüsseln</a> oder <a href="https://help.github.com/ssh-issues/">Problemlösen einfacher SSH-Probleme</a>.
|
||||||
add_new_key = SSH-Schlüssel hinzufügen
|
add_new_key = SSH-Schlüssel hinzufügen
|
||||||
key_name = Schlüsselname
|
key_name = Schlüsselname
|
||||||
key_content = Inhalt
|
key_content = Inhalt
|
||||||
add_key_success = New SSH Key has been added!
|
add_key_success = SSH-Schlüssel hinzugefügt
|
||||||
delete_key = löschen
|
delete_key = SSH-Schlüssel löschen
|
||||||
add_on = Hinzugefügt am
|
add_on = Hinzugefügt am
|
||||||
last_used = Zuletzt verwendet auf
|
last_used = Zuletzt verwendet auf
|
||||||
no_activity = Keine neuen Aktivitäten
|
no_activity = Keine neuen Aktivitäten
|
||||||
|
|
||||||
manage_social = Manage Associated Social Accounts
|
manage_social = Verknüpfte soziale Konten verwalten
|
||||||
social_desc = This is a list of associated social accounts. Remove any binding that you do not recognize.
|
social_desc = Dies ist eine Liste verknüpfter sozialer Konten. Entferne alle Verknüpfungen, die du nicht kennst.
|
||||||
unbind = Verknüpfung entfernen
|
unbind = Verknüpfung entfernen
|
||||||
unbind_success = Die Verknüpfung zum Social Konto wurde entfernt.
|
unbind_success = Die Verknüpfung zum sozialen Konto wurde entfernt.
|
||||||
|
|
||||||
delete_account = Löschen Sie Ihr Konto
|
delete_account = Konto löschen
|
||||||
delete_prompt = Die Operation wird Ihr Konto dauerhaft löschen und kann <strong>NICHT</strong> rückgängig gemacht werden!
|
delete_prompt = Diese Aktion wird dein Konto dauerhaft löschen und kann <strong>NICHT</strong> rückgängig gemacht werden!
|
||||||
confirm_delete_account = Löschung bestätigen
|
confirm_delete_account = Löschen
|
||||||
|
|
||||||
[repo]
|
[repo]
|
||||||
owner = Eigentümer
|
owner = Besitzer
|
||||||
repo_name = Repositorie Name
|
repo_name = Repository-Name
|
||||||
repo_name_helper = Tolle Repositorienamen sind kurz, einprägsam und <strong>einzigartig</strong>.
|
repo_name_helper = Gute Repository-Namen sind kurz, einprägsam und <strong>einzigartig</strong>.
|
||||||
visibility = Sichtbarkeit
|
visibility = Sichtbarkeit
|
||||||
visiblity_helper = Dieses Repositorie ist <span class="label label-red label-radius">Privat</span>
|
visiblity_helper = Dieses Repository ist <span class="label label-red label-radius">Privat</span>
|
||||||
repo_desc = Beschreibung
|
repo_desc = Beschreibung
|
||||||
repo_lang = Sprache
|
repo_lang = Sprache
|
||||||
repo_lang_helper = Wählen Sie eine .gitignore Datei
|
repo_lang_helper = Wähle eine .gitignore Datei
|
||||||
license = Lizenz
|
license = Lizenz
|
||||||
license_helper = Wählen Sie eine Lizenzdatei aus
|
license_helper = Wähle eine Lizenz aus
|
||||||
init_readme = Initialisieren dieses Repository mit einem README.md
|
init_readme = Repository mit README.md initialisieren
|
||||||
create_repo = Repository erstellen
|
create_repo = Repository erstellen
|
||||||
default_branch = Default Branch
|
default_branch = Standard-Branch
|
||||||
mirror_interval = Mirror Intervall(Stunden)
|
mirror_interval = Spiegel-Intervall (in Stunden)
|
||||||
goget_meta = Go-Get Meta
|
goget_meta = Go-Get Meta
|
||||||
goget_meta_helper = This repository will be <span class="label label-blue label-radius">Go-Getable</span>
|
goget_meta_helper = Dieses Repository wird man mit <span class="label label-blue label-radius">go get</span> klonen können.
|
||||||
|
|
||||||
need_auth = Berechtigung erforderlich
|
need_auth = Authorisierung benötigt
|
||||||
migrate_type = Migrationstyp
|
migrate_type = Migrationstyp
|
||||||
migrate_type_helper = Dieses Repository wird ein <span class="label label-blue label-radius">Mirror</span>
|
migrate_type_helper = Dieses Repository wird ein <span class="label label-blue label-radius">Spiegel</span>
|
||||||
migrate_repo = Repositorie migrieren
|
migrate_repo = Repository migrieren
|
||||||
|
|
||||||
clone_helper = Need help cloning? Visit <a target="_blank" href="http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository">Help</a>!
|
copy_link = Klonen
|
||||||
|
clone_helper = Du brauchst Hilfe beim Klonen? Hier gibt es <a target="_blank" href="http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository">Hilfe</a>!
|
||||||
unwatch = Beobachtung beenden
|
unwatch = Beobachtung beenden
|
||||||
watch = Beobachtung
|
watch = Beobachtung
|
||||||
unstar = Markierung aufheben
|
unstar = Markierung aufheben
|
||||||
star = Markierung
|
star = Markierung
|
||||||
fork = Abspaltung
|
fork = Abspaltung
|
||||||
|
|
||||||
|
quick_guide = Kurzanleitung
|
||||||
|
clone_this_repo = Dieses Repository klonen
|
||||||
|
create_new_repo_command = Erstelle ein neues Repository mittels der Kommandozeile
|
||||||
|
push_exist_repo = Übertrage ein existierendes Repository von der Kommandozeile
|
||||||
|
|
||||||
settings = Einstellungen
|
settings = Einstellungen
|
||||||
settings.options = Optionen
|
settings.options = Optionen
|
||||||
settings.collaboration = Zusammenarbeit
|
settings.collaboration = Zusammenarbeit
|
||||||
settings.hooks = Webhooks
|
settings.hooks = Webhooks
|
||||||
settings.deploy_keys = Schlüssel bereitstellen
|
settings.deploy_keys = Deploy-Keys
|
||||||
settings.basic_settings = Grundeinstellungen
|
settings.basic_settings = Grundeinstellungen
|
||||||
settings.danger_zone = Danger Zone
|
settings.danger_zone = Gefahrenzone
|
||||||
settings.site = Offizielle Website
|
settings.site = Offizielle Webseite
|
||||||
settings.update_settings = Aktualisierungseinstellungen
|
settings.update_settings = Aktualisierungseinstellungen
|
||||||
settings.transfer = Eigentum übertragen
|
settings.transfer = Besitz übertragen
|
||||||
settings.transfer_desc = Transfer this repo to another user or to an organization where you have admin rights.
|
settings.transfer_desc = Übertrage dieses Repository einem anderen Benutzer oder einer Organisation.
|
||||||
settings.delete = Dieses Repository löschen
|
settings.new_owner_has_same_repo = Neuer Eigentümer hat bereits ein Repository mit dem gleichen Namen.
|
||||||
settings.delete_desc = Sobald Sie ein Repository löschen, gibt es keinen Weg zurück. Bitte seien Sie sicher.
|
settings.delete = Repository löschen
|
||||||
settings.update_settings_success = Repository Optionen wurde erfolgreich aktualisiert.
|
settings.delete_desc = Wenn dieses Repository gelöschet ist, gibt es keinen Weg zurück. Sei dir sicher!
|
||||||
|
settings.update_settings_success = Repository-Optionen aktualisiert
|
||||||
settings.transfer_owner = Neuer Besitzer
|
settings.transfer_owner = Neuer Besitzer
|
||||||
settings.make_transfer = Make Transfer
|
settings.make_transfer = übertragen
|
||||||
settings.confirm_delete = Löschung bestätigen
|
settings.transfer_succeed = Repository-Eigentum wurde erfolgreich übertragen.
|
||||||
settings.add_collaborator = Neuer Mitarbeiter hinzufügen
|
settings.confirm_delete = Löschen
|
||||||
settings.add_collaborator_success = Neuer Mitarbeiter wurde hinzugefügt.
|
settings.add_collaborator = Mitarbeiter hinzufügen
|
||||||
settings.remove_collaborator_success = Mitarbeiter wurde entfernt.
|
settings.add_collaborator_success = Mitarbeiter hinzugefügt
|
||||||
|
settings.remove_collaborator_success = Mitarbeiter entfernt
|
||||||
settings.add_webhook = Webhook hinzufügen
|
settings.add_webhook = Webhook hinzufügen
|
||||||
settings.hooks_desc = Webhooks allow external services to be notified when certain events happen on Gogs. When the specified events happen, we'll send a POST request to each of the URLs you provide. Learn more in our <a target="_blank" href="http://gogs.io/docs/features/webhook.html">Webhooks Guide</a>.
|
settings.hooks_desc = Webhooks erlauben es externe Dienste zu informieren, wenn etwas bestimmtes in deinem Repository passiert. GoGS sendet dann eine POST-Request an alle angegebenen URLs. Erfahre mehr in unserem <a target="_blank" href="http://gogs.io/docs/features/webhook.html">Webhooks Guide</a>.
|
||||||
settings.remove_hook_success = Webhook wurde entfernt.
|
settings.remove_hook_success = Webhook entfernt
|
||||||
settings.add_webhook_desc = We’ll send a <code>POST</code> request to the URL below with details of any subscribed events. You can also specify which data format you'd like to receive (JSON, <code>x-www-form-urlencoded</code>, <em>etc</em>). More information can be found in <a target="_blank" href="http://gogs.io/docs/features/webhook.html">Webhooks Guide</a>.
|
settings.add_webhook_desc = GoGS sendet einen <code>POST</code>-Request an die unten stehende URL mit Details aller abonierten Ereignisse. Du kannst auch angeben, welches Datenformat du erhalten willst (JSON, <code>x-www-form-urlencoded</code>, <em>etc</em>). Mehr Informationen findest du im <a target="_blank" href="http://gogs.io/docs/features/webhook.html">Webhooks Guide</a>.
|
||||||
settings.payload_url = Payload URL
|
settings.payload_url = Payload-URL
|
||||||
settings.content_type = Inhaltstyp
|
settings.content_type = Inhaltstyp
|
||||||
settings.secret = Geheimnis
|
settings.secret = Secret
|
||||||
settings.event_desc = Durch welche Ereignisse würden Sie gerne diesen Webhook auslösen?
|
settings.event_desc = Welche Ereignisse sollen diesen Webhook auslösen?
|
||||||
settings.event_push_only = Just the <code>push</code> event.
|
settings.event_push_only = Nur das <code>push</code>-Ereignis.
|
||||||
settings.active = Aktiv
|
settings.active = Aktiv
|
||||||
settings.active_helper = We will deliver event details when this hook is triggered.
|
settings.active_helper = Ereignisdetails werden ausgeliefert, wenn dieser Webhook ausgelöst wird.
|
||||||
settings.add_hook_success = Neuer Webhook wurde hinzugefügt.
|
settings.add_hook_success = Webhook hinzugefügt
|
||||||
settings.update_webhook = Webhook aktualisieren
|
settings.update_webhook = Webhook aktualisieren
|
||||||
settings.update_hook_success = Webhook wurde aktualisiert.
|
settings.update_hook_success = Webhook aktualisiert
|
||||||
settings.delete_webhook = Webhook löschen
|
settings.delete_webhook = Webhook löschen
|
||||||
settings.recent_deliveries = Jüngste Zustellungen
|
settings.recent_deliveries = letzte Zustellungen
|
||||||
|
settings.hook_type = Hook Type
|
||||||
|
settings.add_slack_hook_desc = Add <a href="http://slack.com">Slack</a> integration to your repository.
|
||||||
|
settings.slack_token = Token
|
||||||
|
settings.slack_domain = Domain
|
||||||
|
settings.slack_channel = Channel
|
||||||
|
|
||||||
[org]
|
[org]
|
||||||
org_name_holder = Name der Organisation
|
org_name_holder = Name der Organisation
|
||||||
org_name_helper = Namen großer Organisationen sind kurz und einprägsam.
|
org_name_helper = Gute Namen von Organisationen sind kurz und einprägsam.
|
||||||
org_email_helper = E-Mail der Organisation empfängt alle Benachrichtigungen und Bestätigungen.
|
org_email_helper = Das E-Mail-Konto der Organisation empfängt alle Benachrichtigungen.
|
||||||
create_org = Organisation erstellen
|
create_org = Organisation erstellen
|
||||||
repo_updated = Aktualisiert
|
repo_updated = Aktualisiert
|
||||||
people = Personen
|
people = Personen
|
||||||
invite_someone = Jemanden einladen
|
invite_someone = Benutzer einladen
|
||||||
teams = Teams
|
teams = Teams
|
||||||
lower_members = Mitglieder
|
lower_members = Mitglieder
|
||||||
lower_repositories = Repositories
|
lower_repositories = Repositorys
|
||||||
create_new_team = Neues Team erstellen
|
create_new_team = Neues Team erstellen
|
||||||
org_desc = Beschreibung
|
org_desc = Beschreibung
|
||||||
team_name = Teamname
|
team_name = Teamname
|
||||||
team_desc = Beschreibung
|
team_desc = Beschreibung
|
||||||
team_name_helper = Sie werden diesen Namen verwenden, um dieses Team in Gesprächen zu erwähnen.
|
team_name_helper = Verwende diesen Namen, um dich auf dieses Team zu beziehen.
|
||||||
team_desc_helper = Was hat das Team auf sich?
|
team_desc_helper = Was hat es mit diesem Team auf sich?
|
||||||
team_permission_desc = Welche Berechtigungsstufe soll das Team haben?
|
team_permission_desc = Welche Berechtigungsstufe soll das Team haben?
|
||||||
|
|
||||||
settings = Einstellungen
|
settings = Einstellungen
|
||||||
|
@ -254,68 +316,69 @@ settings.full_name = Vollständiger Name
|
||||||
settings.website = Webseite
|
settings.website = Webseite
|
||||||
settings.location = Standort
|
settings.location = Standort
|
||||||
settings.update_settings = Aktualisierungseinstellungen
|
settings.update_settings = Aktualisierungseinstellungen
|
||||||
settings.update_setting_success = Einstellung der Organisation wurde erfolgreich aktualisiert.
|
settings.update_setting_success = Organisationseinstellungen aktualisiert
|
||||||
settings.delete = Organisation löschen
|
settings.delete = Organisation löschen
|
||||||
settings.delete_account = Diese Organisation löschen
|
settings.delete_account = Diese Organisation löschen
|
||||||
settings.delete_prompt = Die Operation wird diese Organisation dauerhaft löschen und kann <strong>NICHT</strong> rückgängig gemacht werden!
|
settings.delete_prompt = Die Organisation wird dauerhaft gelöscht. Dies kann <strong>NICHT</strong> rückgängig gemacht werden!
|
||||||
settings.confirm_delete_account = Löschung bestätigen
|
settings.confirm_delete_account = Löschen
|
||||||
|
settings.hooks_desc = Add webhooks that will be triggered for <strong>all repositories</strong> under this organization.
|
||||||
|
|
||||||
members.public = Öffentlich
|
members.public = Öffentlich
|
||||||
members.public_helper = Privat machen
|
members.public_helper = Privat machen
|
||||||
members.private = Privat
|
members.private = Privat
|
||||||
members.private_helper = Öffentlich machen
|
members.private_helper = Öffentlich machen
|
||||||
members.owner = Eigentümer
|
members.owner = Besitzer
|
||||||
members.member = Mitglied
|
members.member = Mitglied
|
||||||
members.conceal = Verbergen
|
members.conceal = Verbergen
|
||||||
members.remove = Entfernen
|
members.remove = Entfernen
|
||||||
members.leave = Verlassen
|
members.leave = Verlassen
|
||||||
members.invite_desc = Start typing a username to invite a new member to %s:
|
members.invite_desc = Benutzernamen eingeben, um ihn als neues Mitglied in %s einzuladen:
|
||||||
members.invite_now = Jetzt einladen
|
members.invite_now = Jetzt einladen
|
||||||
|
|
||||||
teams.join = Beitreten
|
teams.join = Beitreten
|
||||||
teams.leave = Verlassen
|
teams.leave = Verlassen
|
||||||
teams.read_access = Lesezugriff
|
teams.read_access = Lesezugriff
|
||||||
teams.read_access_helper = This team will be able to view and clone its repositories.
|
teams.read_access_helper = Dieses Team wird Repositorys einsehen und klonen können.
|
||||||
teams.write_access = Schreibzugriff
|
teams.write_access = Schreibzugriff
|
||||||
teams.write_access_helper = This team will be able to read its repositories, as well as push to them.
|
teams.write_access_helper = Dieses Team wird die Repositorys einsehen und in sie hinein pushen können.
|
||||||
teams.admin_access = Adminzugriff
|
teams.admin_access = Adminzugriff
|
||||||
teams.admin_access_helper = This team will be able to push/pull to its repositories, as well as add other collaborators to them.
|
teams.admin_access_helper = Dieses Team wird pull- und push-Rechte für die Repositorys haben und Mitarbeiter einladen können.
|
||||||
teams.no_desc = Dieses Team hat keine Beschreibung
|
teams.no_desc = Dieses Team hat keine Beschreibung
|
||||||
teams.settings = Einstellungen
|
teams.settings = Einstellungen
|
||||||
teams.owners_permission_desc = Owners have full access to <strong>all repositories</strong> and have <strong>admin rights</strong> to the organization.
|
teams.owners_permission_desc = Besitzer haben vollen Zugriff auf <strong>alle Repositorys</strong> und <strong>Admin Rechte</strong> für diese Organisation.
|
||||||
teams.members = Teammitglieder
|
teams.members = Teammitglieder
|
||||||
teams.update_settings = Einstellungen aktualisieren
|
teams.update_settings = Einstellungen aktualisieren
|
||||||
teams.delete_team = Dieses Team löschen
|
teams.delete_team = Dieses Team löschen
|
||||||
teams.add_team_member = Teammitglied hinzufügen
|
teams.add_team_member = Teammitglied hinzufügen
|
||||||
teams.delete_team_success = Das Team wurde erfolgreich gelöscht.
|
teams.delete_team_success = Team gelöscht
|
||||||
teams.read_permission_desc = This team grants <strong>Read</strong> access: members can view and clone the team's repositories.
|
teams.read_permission_desc = Dieses Team erlaubt <strong>Lesezugriff</strong>: Mitglieder können Team-Repositorys einsehen und klonen.
|
||||||
teams.write_permission_desc = This team grants <strong>Write</strong> access: members can read from and push to the team's repositories.
|
teams.write_permission_desc = Dieses Team erlaubt <strong>Schreibzugriff</strong>: Mitglieder können Team-Repositorys einsehen und hinein pushen.
|
||||||
teams.admin_permission_desc = This team grants <strong>Admin</strong> access: members can read from, push to, and add collaborators to the team's repositories.
|
teams.admin_permission_desc = Diese Team erlaubt <strong>Adminzugriff</strong>: Mitglieder dieses Teams können pullen, pushen und dem Team Mitarbeiter hinzufügen.
|
||||||
teams.repositories = Team Repositories
|
teams.repositories = Team-Repositorys
|
||||||
teams.add_team_repository = Teamrepositorie hinzufügen
|
teams.add_team_repository = Team-Repository hinzufügen
|
||||||
teams.remove_repo = Entfernen
|
teams.remove_repo = Entfernen
|
||||||
|
|
||||||
[admin]
|
[admin]
|
||||||
dashboard = Dashboard
|
dashboard = Dashboard
|
||||||
users = Benutzer
|
users = Benutzer
|
||||||
organizations = Organisationen
|
organizations = Organisationen
|
||||||
repositories = Repositories
|
repositories = Repositorys
|
||||||
authentication = Authentifizierung
|
authentication = Authentifizierung
|
||||||
config = Konfiguration
|
config = Konfiguration
|
||||||
monitor = Monitoring
|
monitor = Monitoring
|
||||||
prev = Prev.
|
prev = zurück
|
||||||
next = Next
|
next = vor
|
||||||
|
|
||||||
dashboard.statistic = Statistik
|
dashboard.statistic = Statistik
|
||||||
dashboard.operations = Operationen
|
dashboard.operations = Operationen
|
||||||
dashboard.system_status = System Monitor Status
|
dashboard.system_status = System-Monitor-Status
|
||||||
dashboard.statistic_info = Gogs database has <b>%d</b> users, <b>%d</b> organizations, <b>%d</b> public keys, <b>%d</b> repositories, <b>%d</b> watches, <b>%d</b> stars, <b>%d</b> actions, <b>%d</b> accesses, <b>%d</b> issues, <b>%d</b> comments, <b>%d</b> social accounts, <b>%d</b> follows, <b>%d</b> mirrors, <b>%d</b> releases, <b>%d</b> login sources, <b>%d</b> webhooks, <b>%d</b> milestones, <b>%d</b> labels, <b>%d</b> hook tasks, <b>%d</b> teams, <b>%d</b> update tasks, <b>%d</b> attachments.
|
dashboard.statistic_info = GoGS Datenbank hat <b>%d</b> Benutzer, <b>%d</b> Organizationen, <b>%d</b> öffentliche Schlüssel, <b>%d</b> Repositorys, <b>%d</b> watches, <b>%d</b> stars, <b>%d</b> actions, <b>%d</b> Zugriffe, <b>%d</b> issues, <b>%d</b> Kommentare, <b>%d</b> soziale Konten, <b>%d</b> follows, <b>%d</b> Spiegel, <b>%d</b> Releases, <b>%d</b> Login-Quellen, <b>%d</b> Webhooks, <b>%d</b> Milestones, <b>%d</b> Labels, <b>%d</b> Hook-Tasks, <b>%d</b> Teams, <b>%d</b> Aktualisierungs-Tasks, <b>%d</b> Anhänge.
|
||||||
dashboard.operation_name = Operation Name
|
dashboard.operation_name = Operation Name
|
||||||
dashboard.operation_switch = Switch
|
dashboard.operation_switch = Switch
|
||||||
dashboard.operation_run = Run
|
dashboard.operation_run = Ausführen
|
||||||
dashboard.clean_unbind_oauth = Clean unbound OAuthes
|
dashboard.clean_unbind_oauth = ungebundene OAuths bereinigen
|
||||||
dashboard.delete_inactivate_accounts = Alle inaktiven Konten löschen
|
dashboard.delete_inactivate_accounts = inaktive Konten löschen
|
||||||
dashboard.server_uptime = Server Uptime
|
dashboard.server_uptime = Server-Uptime
|
||||||
dashboard.current_goroutine = Aktuelle Goroutines
|
dashboard.current_goroutine = Aktuelle Goroutines
|
||||||
dashboard.current_memory_usage = Aktuelle Speichernutzung
|
dashboard.current_memory_usage = Aktuelle Speichernutzung
|
||||||
dashboard.total_memory_allocated = Zugeteilter Gesamtspeicher
|
dashboard.total_memory_allocated = Zugeteilter Gesamtspeicher
|
||||||
|
@ -323,67 +386,66 @@ dashboard.memory_obtained = Erhaltener Speicher
|
||||||
dashboard.pointer_lookup_times = Pointer Lookup Times
|
dashboard.pointer_lookup_times = Pointer Lookup Times
|
||||||
dashboard.memory_allocate_times = Memory Allocate Times
|
dashboard.memory_allocate_times = Memory Allocate Times
|
||||||
dashboard.memory_free_times = Memory Free Times
|
dashboard.memory_free_times = Memory Free Times
|
||||||
dashboard.current_heap_usage = Current Heap Usage
|
dashboard.current_heap_usage = Aktuelle Heap-Auslastung
|
||||||
dashboard.heap_memory_obtained = Heap Memory Obtained
|
dashboard.heap_memory_obtained = erhaltener Heap-Memory
|
||||||
dashboard.heap_memory_idle = Heap Memory Idle
|
dashboard.heap_memory_idle = unbenutzter Heap-Memory
|
||||||
dashboard.heap_memory_in_use = Heap Memory In Use
|
dashboard.heap_memory_in_use = benutzter Heap-Memory
|
||||||
dashboard.heap_memory_released = Heap Memory Released
|
dashboard.heap_memory_released = freigegebener Heap-Memory
|
||||||
dashboard.heap_objects = Heap Objects
|
dashboard.heap_objects = Heap-Objekte
|
||||||
dashboard.bootstrap_stack_usage = Bootstrap Stack Usage
|
dashboard.bootstrap_stack_usage = Bootstrap-Stack-Auslastung
|
||||||
dashboard.stack_memory_obtained = Stack Memory Obtained
|
dashboard.stack_memory_obtained = erhaltener Stack-Memory
|
||||||
dashboard.mspan_structures_usage = MSpan Structures Usage
|
dashboard.mspan_structures_usage = MSpan-Structures-Auslastung
|
||||||
dashboard.mspan_structures_obtained = MSpan Structures Obtained
|
dashboard.mspan_structures_obtained = erhaltene MSpan-Structures
|
||||||
dashboard.mcache_structures_usage = MCache Structures Usage
|
dashboard.mcache_structures_usage = MCache-Structures-Auslastung
|
||||||
dashboard.mcache_structures_obtained = MCache Structures Obtained
|
dashboard.mcache_structures_obtained = erhaltene MCache-Structures
|
||||||
dashboard.profiling_bucket_hash_table_obtained = Profiling Bucket Hash Table Obtained
|
dashboard.profiling_bucket_hash_table_obtained = Profiling Bucket Hash Table Obtained
|
||||||
dashboard.gc_metadata_obtained = GC Metadada Obtained
|
dashboard.gc_metadata_obtained = erhaltene GC-Metadata
|
||||||
dashboard.other_system_allocation_obtained = Other System Allocation Obtained
|
dashboard.other_system_allocation_obtained = andere erhaltene System-Allokatoren
|
||||||
dashboard.next_gc_recycle = Next GC Recycle
|
dashboard.next_gc_recycle = nächster GC-Zyklus
|
||||||
dashboard.last_gc_time = Since Last GC Time
|
dashboard.last_gc_time = seit letztem GC-Zyklus
|
||||||
dashboard.total_gc_time = Total GC Pause
|
dashboard.total_gc_time = gesammte GC-Zeit
|
||||||
dashboard.total_gc_pause = Total GC Pause
|
dashboard.total_gc_pause = gesammte GC-Pause
|
||||||
dashboard.last_gc_pause = Last GC Pause
|
dashboard.last_gc_pause = letzte GC-Pause
|
||||||
dashboard.gc_times = GC Takt
|
dashboard.gc_times = GC-Takt
|
||||||
|
|
||||||
users.user_manage_panel = User Manage Panel
|
users.user_manage_panel = Benutzer
|
||||||
users.new_account = Neues Konto erstellen
|
users.new_account = Neues Konto erstellen
|
||||||
users.name = Name
|
users.name = Name
|
||||||
users.email = E-mail
|
|
||||||
users.activated = Aktiviert
|
users.activated = Aktiviert
|
||||||
users.admin = Admin
|
users.admin = Admin
|
||||||
users.repos = Repos
|
users.repos = Repositorys
|
||||||
users.created = Erzeugt
|
users.created = Erzeugt
|
||||||
users.edit = Bearbeiten
|
users.edit = Bearbeiten
|
||||||
users.auth_source = Auth Source
|
users.auth_source = Auth-Quelle
|
||||||
users.local = Lokal
|
users.local = Lokal
|
||||||
users.auth_login_name = Auth Login Name
|
users.auth_login_name = Auth-Login-Name
|
||||||
users.update_profile_success = Kontoprofil wurde erfolgreich aktualisiert.
|
users.update_profile_success = Kontoprofil aktualisiert
|
||||||
users.edit_account = Konto bearbeiten
|
users.edit_account = Konto bearbeiten
|
||||||
users.is_activated = Dieses Konto ist aktiviert
|
users.is_activated = Dieses Konto ist aktiviert
|
||||||
users.is_admin = Dieses Konto hat Administratorrechte
|
users.is_admin = Dieses Konto hat Administratorrechte
|
||||||
users.update_profile = Kontopprofil aktualisieren
|
users.update_profile = Kontoprofil aktualisieren
|
||||||
users.delete_account = Dieses Konto löschen
|
users.delete_account = Dieses Konto löschen
|
||||||
users.still_own_repo = Dieses Konto ist noch Eigentümer von Repositories, Sie müssen zuerst diese löschen oder übertragen.
|
users.still_own_repo = Dieses Konto besitzt noch Repositorys. Diese müssen zuerst gelöscht oder übertragen werden.
|
||||||
|
|
||||||
orgs.org_manage_panel = Organization Manage Panel
|
orgs.org_manage_panel = Organisationenverwaltung
|
||||||
orgs.name = Name
|
orgs.name = Name
|
||||||
orgs.teams = Teams
|
orgs.teams = Teams
|
||||||
orgs.members = Mitglieder
|
orgs.members = Mitglieder
|
||||||
|
|
||||||
repos.repo_manage_panel = Repository Manage Panel
|
repos.repo_manage_panel = Repositorys
|
||||||
repos.owner = Eigentümer
|
repos.owner = Besitzer
|
||||||
repos.name = Name
|
repos.name = Name
|
||||||
repos.private = Privat
|
repos.private = Privat
|
||||||
repos.watches = Watches
|
repos.watches = Watches
|
||||||
repos.stars = Stars
|
repos.stars = Stars
|
||||||
repos.issues = Themen
|
repos.issues = Issues
|
||||||
|
|
||||||
auths.auth_manage_panel = Authorization Manage Panel
|
auths.auth_manage_panel = Authentifizierung
|
||||||
auths.new = Neu Authentifizierungsquelle hinzufügen
|
auths.new = Neue Authentifizierungsquelle hinzufügen
|
||||||
auths.name = Name
|
auths.name = Name
|
||||||
auths.type = Typ
|
auths.type = Typ
|
||||||
auths.enabled = Aktiviert
|
auths.enabled = aktiviert
|
||||||
auths.updated = Aktualisiert
|
auths.updated = aktualisiert
|
||||||
auths.auth_type = Authentifizierungstyp
|
auths.auth_type = Authentifizierungstyp
|
||||||
auths.auth_name = Authentifizierungsname
|
auths.auth_name = Authentifizierungsname
|
||||||
auths.domain = Domain
|
auths.domain = Domain
|
||||||
|
@ -393,30 +455,30 @@ auths.base_dn = Base DN
|
||||||
auths.attributes = Suchattribute
|
auths.attributes = Suchattribute
|
||||||
auths.filter = Suchfilter
|
auths.filter = Suchfilter
|
||||||
auths.ms_ad_sa = Ms Ad SA
|
auths.ms_ad_sa = Ms Ad SA
|
||||||
auths.smtp_auth = SMTP Authentifizierungstyp
|
auths.smtp_auth = SMTP-Authentifizierungstyp
|
||||||
auths.smtphost = SMTP Host
|
auths.smtphost = SMTP-Host
|
||||||
auths.smtpport = SMTP Port
|
auths.smtpport = SMTP-Port
|
||||||
auths.enable_tls = TLS-Verschlüsselung aktivieren
|
auths.enable_tls = TLS-Verschlüsselung aktivieren
|
||||||
auths.enable_auto_register = Automatische Registrierung aktivieren
|
auths.enable_auto_register = Automatische Registrierung aktivieren
|
||||||
auths.tips = Tipps
|
auths.tips = Tipps
|
||||||
auths.edit = Authentifizierungseinstellungen bearbeiten
|
auths.edit = Authentifizierungseinstellungen bearbeiten
|
||||||
auths.activated = Diese Authentifizierung ist aktiviert
|
auths.activated = Diese Authentifizierung ist aktiviert
|
||||||
auths.update_success = Authentifizierungseinstellungen wurde erfolgreich aktualisiert.
|
auths.update_success = Authentifizierungseinstellungen aktualisiert
|
||||||
auths.update = Authentifizierungseinstellungen aktualisieren
|
auths.update = Authentifizierungseinstellungen aktualisieren
|
||||||
auths.delete = Diese Authentifizierung löschen
|
auths.delete = Authentifizierung löschen
|
||||||
|
|
||||||
config.server_config = Server-Konfiguration
|
config.server_config = Server-Konfiguration
|
||||||
config.app_name = Anwendungsname
|
config.app_name = Anwendungsname
|
||||||
config.app_ver = Anwendungsversion
|
config.app_ver = Anwendungsversion
|
||||||
config.app_url = Anwendungs URL
|
config.app_url = Anwendungs-URL
|
||||||
config.domain = Domain
|
config.domain = Domain
|
||||||
config.offline_mode = Offline Mode
|
config.offline_mode = Offline-Modus
|
||||||
config.disable_router_log = Router Log deaktivieren
|
config.disable_router_log = Router-Log deaktivieren
|
||||||
config.run_user = Run User
|
config.run_user = Laufzeit-Benutzer
|
||||||
config.run_mode = Run Mode
|
config.run_mode = Laufzeit-Modus
|
||||||
config.repo_root_path = Repositorie Wurzelverzeichnis
|
config.repo_root_path = Repository-Verzeichnis
|
||||||
config.static_file_root_path = Wurzelverzeichnis für statische Dateien
|
config.static_file_root_path = Verzeichnis für statische Dateien
|
||||||
config.log_file_root_path = Wurzelverzeichnis für Log Dateien
|
config.log_file_root_path = Log-Verzeichnis
|
||||||
config.script_type = Skript-Typ
|
config.script_type = Skript-Typ
|
||||||
config.reverse_auth_user = Reverse Authentication User
|
config.reverse_auth_user = Reverse Authentication User
|
||||||
config.db_config = Datenbankkonfiguration
|
config.db_config = Datenbankkonfiguration
|
||||||
|
@ -424,54 +486,54 @@ config.db_type = Typ
|
||||||
config.db_host = Host
|
config.db_host = Host
|
||||||
config.db_name = Name
|
config.db_name = Name
|
||||||
config.db_user = Benutzer
|
config.db_user = Benutzer
|
||||||
config.db_ssl_mode = SSL Modus
|
config.db_ssl_mode = SSL-Modus
|
||||||
config.db_ssl_mode_helper = (nur für "postgres")
|
config.db_ssl_mode_helper = (nur für "postgres")
|
||||||
config.db_path = Verzeichnis
|
config.db_path = Verzeichnis
|
||||||
config.db_path_helper = (nur für "sqlite3")
|
config.db_path_helper = (nur für "sqlite3")
|
||||||
config.service_config = Service Einstellungen
|
config.service_config = Service-Einstellungen
|
||||||
config.register_email_confirm = E-Mail Bestätigung bei Registrierung
|
config.register_email_confirm = E-Mail-Bestätigung bei Registrierung
|
||||||
config.disable_register = Registrierung deaktivieren
|
config.disable_register = Registrierung deaktivieren
|
||||||
config.require_sign_in_view = Require Sign In View
|
config.require_sign_in_view = Require Sign In View
|
||||||
config.mail_notify = E-Mail Benachrichtigung
|
config.mail_notify = E-Mail-Benachrichtigung
|
||||||
config.enable_cache_avatar = Avatar Cache avtivieren
|
config.enable_cache_avatar = Avatar-Cache aktivieren
|
||||||
config.active_code_lives = Active Code Lives
|
config.active_code_lives = Active Code Lives
|
||||||
config.reset_password_code_lives = Reset Password Code Lives
|
config.reset_password_code_lives = Reset Password Code Lives
|
||||||
config.webhook_config = Webhook Einstellungen
|
config.webhook_config = Webhook-Einstellungen
|
||||||
config.task_interval = Task Intervall
|
config.task_interval = Task-Intervall
|
||||||
config.deliver_timeout = Zeitlimit für Zustellung
|
config.deliver_timeout = Zeitlimit für Zustellung
|
||||||
config.mailer_config = Mailer Einstellungen
|
config.mailer_config = Mailer-Einstellungen
|
||||||
config.mailer_enabled = Aktiviert
|
config.mailer_enabled = Aktiviert
|
||||||
config.mailer_name = Name
|
config.mailer_name = Name
|
||||||
config.mailer_host = Host
|
config.mailer_host = Host
|
||||||
config.mailer_user = Benutzer
|
config.mailer_user = Benutzer
|
||||||
config.oauth_config = OAuth Einstellungen
|
config.oauth_config = OAuth-Einstellungen
|
||||||
config.oauth_enabled = Aktiviert
|
config.oauth_enabled = Aktiviert
|
||||||
config.cache_config = Cache Einstellungen
|
config.cache_config = Cache-Einstellungen
|
||||||
config.cache_adapter = Cache Adapter
|
config.cache_adapter = Cache-Adapter
|
||||||
config.cache_interval = Cache Intervall
|
config.cache_interval = Cache-Intervall
|
||||||
config.cache_conn = Cache Anbindung
|
config.cache_conn = Cache-Anbindung
|
||||||
config.session_config = Session Einstellungen
|
config.session_config = Session-Einstellungen
|
||||||
config.session_provider = Session Provider
|
config.session_provider = Session-Provider
|
||||||
config.provider_config = Provider Einstellungen
|
config.provider_config = Provider-Einstellungen
|
||||||
config.cookie_name = Cookie Name
|
config.cookie_name = Cookie-Name
|
||||||
config.enable_set_cookie = Enable Set Cookie
|
config.enable_set_cookie = Enable Set Cookie
|
||||||
config.gc_interval_time = GC Interval Time
|
config.gc_interval_time = GC-Intervallzeit
|
||||||
config.session_life_time = Session Lebensdauer
|
config.session_life_time = Session-Lebensdauer
|
||||||
config.https_only = nur HTTPS
|
config.https_only = nur HTTPS
|
||||||
config.cookie_life_time = Cookie Lebensdauer
|
config.cookie_life_time = Cookie-Lebensdauer
|
||||||
config.session_hash_function = Session ID Hash Function
|
config.session_hash_function = Session-ID-Hashfunktion
|
||||||
config.session_hash_key = Session ID Hash Key
|
config.session_hash_key = Session-ID-Hashschlüssel
|
||||||
config.picture_config = Bildereinstellungen
|
config.picture_config = Bildeinstellungen
|
||||||
config.picture_service = Bilderservice
|
config.picture_service = Bildservice
|
||||||
config.disable_gravatar = Gravatar deaktivieren
|
config.disable_gravatar = Gravatar deaktivieren
|
||||||
config.log_config = Log Einstellungen
|
config.log_config = Log-Einstellungen
|
||||||
config.log_mode = Log Modus
|
config.log_mode = Log-Modus
|
||||||
|
|
||||||
monitor.cron = Cron Tasks
|
monitor.cron = Cron-Tasks
|
||||||
monitor.name = Name
|
monitor.name = Name
|
||||||
monitor.schedule = Zeitplan
|
monitor.schedule = Zeitplan
|
||||||
monitor.next = Next Time
|
monitor.next = nächste Ausführung
|
||||||
monitor.previous = Previous Time
|
monitor.previous = letzte Ausführung
|
||||||
monitor.execute_times = Execute Times
|
monitor.execute_times = Execute Times
|
||||||
monitor.process = Laufende Prozesse
|
monitor.process = Laufende Prozesse
|
||||||
monitor.desc = Beschreibung
|
monitor.desc = Beschreibung
|
||||||
|
@ -479,10 +541,11 @@ monitor.start = Startzeit
|
||||||
monitor.execute_time = Ausführungszeit
|
monitor.execute_time = Ausführungszeit
|
||||||
|
|
||||||
[action]
|
[action]
|
||||||
create_repo = Repositorie erstellen <a href="/%s">%s</a>
|
create_repo = hat Repository <a href="%s/%s">%s</a> erstellt
|
||||||
commit_repo = pushed to <a href="/%s/src/%s">%s</a> at <a href="/%s">%s</a>
|
commit_repo = hat nach <a href="%s/%s/src/%s">%s</a> in <a href="%s/%s">%s</a> gepusht
|
||||||
create_issue = opened issue <a href="/%s/issues/%s">%s#%s</a>
|
create_issue = hat Issue <a href="%s/%s/issues/%s">%s#%s</a> eröffnet
|
||||||
comment_issue = commented on issue <a href="/%s/issues/%s">%s#%s</a>
|
comment_issue = hat Issue <a href="%s/%s/issues/%s">%s#%s</a> kommentiert
|
||||||
|
transfer_repo = hat Repository <code>%s</code> transferiert an <a href="/%s%s">%s</a>
|
||||||
|
|
||||||
[tool]
|
[tool]
|
||||||
ago = vor
|
ago = vor
|
||||||
|
@ -504,16 +567,3 @@ months = %d Monate %s
|
||||||
years = %d Jahre %s
|
years = %d Jahre %s
|
||||||
raw_seconds = Sekunden
|
raw_seconds = Sekunden
|
||||||
raw_minutes = Minuten
|
raw_minutes = Minuten
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,50 @@ issues = Issues
|
||||||
|
|
||||||
cancel = Cancel
|
cancel = Cancel
|
||||||
|
|
||||||
|
[install]
|
||||||
|
install = Installation
|
||||||
|
title = Install Steps For First-time Run
|
||||||
|
requite_db_desc = Gogs requires MySQL, PostgreSQL or SQLite3, but SQLite3 is usually available in the official binary version.
|
||||||
|
db_type = Database Type
|
||||||
|
host = Host
|
||||||
|
user = User
|
||||||
|
password = Password
|
||||||
|
db_name = Database Name
|
||||||
|
db_helper = Please use INNODB engine with utf8_general_ci charset for MySQL.
|
||||||
|
ssl_mode = SSL Mode
|
||||||
|
path = Path
|
||||||
|
sqlite_helper = The file path of SQLite3 database.
|
||||||
|
general_title = General Settings of Gogs
|
||||||
|
repo_path = Repository Root Path
|
||||||
|
repo_path_helper = All Git remote repositories will be saved to this directory.
|
||||||
|
run_user = Run User
|
||||||
|
run_user_helper = The user must have access to Repository Root Path and run Gogs.
|
||||||
|
domain = Domain
|
||||||
|
domain_helper = This affects SSH clone URLs.
|
||||||
|
app_url = Application URL
|
||||||
|
app_url_helper = This affects HTTP/HTTPS clone URL and somewhere in e-mail.
|
||||||
|
email_title = Email Service Settings(Optional)
|
||||||
|
smtp_host = SMTP Host
|
||||||
|
mailer_user = Sender E-mail
|
||||||
|
mailer_password = Sender Password
|
||||||
|
notify_title = Notification Settings(Optional)
|
||||||
|
register_confirm = Enable Register Confirmation
|
||||||
|
mail_notify = Enable Mail Notification
|
||||||
|
admin_title = Admin Account Settings
|
||||||
|
admin_name = Username
|
||||||
|
admin_password = Password
|
||||||
|
confirm_password = Confirm Password
|
||||||
|
admin_email = E-mail
|
||||||
|
install_gogs = Install Gogs
|
||||||
|
test_git_failed = Fail to test 'git' command: %v
|
||||||
|
sqlite3_not_available = Your release version does not support SQLite3, please download the official binary version from http://gogs.io/docs/installation/install_from_binary.html, NOT the gobuild version.
|
||||||
|
invalid_db_setting = Database setting is not correct: %v
|
||||||
|
invalid_repo_path = Repository root path is invalid: %v
|
||||||
|
run_user_not_match = Run user isn't the current user: %s -> %s
|
||||||
|
save_config_failed = Fail to save configuration: %v
|
||||||
|
invalid_admin_setting = Admin account setting is invalid: %v
|
||||||
|
install_success = Welcome! We're glad that you choose Gogs, have fun and take care.
|
||||||
|
|
||||||
[home]
|
[home]
|
||||||
uname_holder = Username or E-mail
|
uname_holder = Username or E-mail
|
||||||
password_holder = Password
|
password_holder = Password
|
||||||
|
@ -47,6 +91,9 @@ collaborative_repos = Collaborative Repositories
|
||||||
my_orgs = My Organizations
|
my_orgs = My Organizations
|
||||||
my_mirrors = My Mirrors
|
my_mirrors = My Mirrors
|
||||||
|
|
||||||
|
[explore]
|
||||||
|
repos = Repositories
|
||||||
|
|
||||||
[auth]
|
[auth]
|
||||||
create_new_account = Create New Account
|
create_new_account = Create New Account
|
||||||
register_hepler_msg = Already have an account? Sign in now!
|
register_hepler_msg = Already have an account? Sign in now!
|
||||||
|
@ -81,6 +128,7 @@ HttpsUrl = HTTPS URL
|
||||||
PayloadUrl = Payload URL
|
PayloadUrl = Payload URL
|
||||||
TeamName = Team name
|
TeamName = Team name
|
||||||
AuthName = Authorization name
|
AuthName = Authorization name
|
||||||
|
AdminEmail = Admin E-mail
|
||||||
|
|
||||||
require_error = ` cannot be empty.`
|
require_error = ` cannot be empty.`
|
||||||
alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.`
|
alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.`
|
||||||
|
@ -91,7 +139,7 @@ email_error = ` is not a valid e-mail address.`
|
||||||
url_error = ` is not a valid URL.`
|
url_error = ` is not a valid URL.`
|
||||||
unknown_error = Unknown error:
|
unknown_error = Unknown error:
|
||||||
captcha_incorrect = Captcha didn't match.
|
captcha_incorrect = Captcha didn't match.
|
||||||
password_not_match = Password and re-type password are not same.
|
password_not_match = Password and confirm password are not same.
|
||||||
|
|
||||||
username_been_taken = Username has been already taken.
|
username_been_taken = Username has been already taken.
|
||||||
repo_name_been_taken = Repository name has been already taken.
|
repo_name_been_taken = Repository name has been already taken.
|
||||||
|
@ -118,6 +166,15 @@ org_still_own_repo = This organization still have ownership of repository, you h
|
||||||
|
|
||||||
still_own_user = This authentication still has used by some users, you should move them and then delete again.
|
still_own_user = This authentication still has used by some users, you should move them and then delete again.
|
||||||
|
|
||||||
|
[user]
|
||||||
|
change_avatar = Change your avatar at gravatar.com
|
||||||
|
join_on = Joined on
|
||||||
|
repositories = Repositories
|
||||||
|
activity = Public Activity
|
||||||
|
followers = Followers
|
||||||
|
starred = Starred
|
||||||
|
following = Following
|
||||||
|
|
||||||
[settings]
|
[settings]
|
||||||
profile = Profile
|
profile = Profile
|
||||||
password = Password
|
password = Password
|
||||||
|
@ -125,6 +182,7 @@ ssh_keys = SSH Keys
|
||||||
social = Social Accounts
|
social = Social Accounts
|
||||||
orgs = Organizations
|
orgs = Organizations
|
||||||
delete = Delete Account
|
delete = Delete Account
|
||||||
|
uid = Uid
|
||||||
|
|
||||||
public_profile = Public Profile
|
public_profile = Public Profile
|
||||||
profile_desc = Your Email address is public and will be used for any account related notifications, and any web based operations made via the site.
|
profile_desc = Your Email address is public and will be used for any account related notifications, and any web based operations made via the site.
|
||||||
|
@ -133,6 +191,10 @@ website = Website
|
||||||
location = Location
|
location = Location
|
||||||
update_profile = Update Profile
|
update_profile = Update Profile
|
||||||
update_profile_success = Your profile has been successfully updated.
|
update_profile_success = Your profile has been successfully updated.
|
||||||
|
change_username = Username Changed
|
||||||
|
change_username_desc = Username has been changed, do you want to continue? This will affect all links relate to your account.
|
||||||
|
continue = Continue
|
||||||
|
cancel = Cancel
|
||||||
|
|
||||||
change_password = Change Password
|
change_password = Change Password
|
||||||
old_password = Current Password
|
old_password = Current Password
|
||||||
|
@ -159,8 +221,10 @@ unbind = Unbind
|
||||||
unbind_success = Social account has been unbound.
|
unbind_success = Social account has been unbound.
|
||||||
|
|
||||||
delete_account = Delete Your Account
|
delete_account = Delete Your Account
|
||||||
delete_prompt = The operation will delete your account permanently, and <strong>CANNOT</strong> be undo!
|
delete_prompt = The operation will delete your account permanently, and <strong>CANNOT</strong> be undone!
|
||||||
confirm_delete_account = Confirm Deletion
|
confirm_delete_account = Confirm Deletion
|
||||||
|
delete_account_title = Account Deletion
|
||||||
|
delete_account_desc = This account is going to be deleted permanently, do you want to continue?
|
||||||
|
|
||||||
[repo]
|
[repo]
|
||||||
owner = Owner
|
owner = Owner
|
||||||
|
@ -185,6 +249,9 @@ migrate_type = Migration Type
|
||||||
migrate_type_helper = This repository will be a <span class="label label-blue label-radius">Mirror</span>
|
migrate_type_helper = This repository will be a <span class="label label-blue label-radius">Mirror</span>
|
||||||
migrate_repo = Migrate Repository
|
migrate_repo = Migrate Repository
|
||||||
|
|
||||||
|
copy_link = Copy
|
||||||
|
click_to_copy = Copy to clipboard
|
||||||
|
copied = Copied OK
|
||||||
clone_helper = Need help cloning? Visit <a target="_blank" href="http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository">Help</a>!
|
clone_helper = Need help cloning? Visit <a target="_blank" href="http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository">Help</a>!
|
||||||
unwatch = Unwatch
|
unwatch = Unwatch
|
||||||
watch = Watch
|
watch = Watch
|
||||||
|
@ -192,6 +259,30 @@ unstar = Unstar
|
||||||
star = Star
|
star = Star
|
||||||
fork = Fork
|
fork = Fork
|
||||||
|
|
||||||
|
no_desc = No Description
|
||||||
|
quick_guide = Quick Guide
|
||||||
|
clone_this_repo = Clone this repository
|
||||||
|
create_new_repo_command = Create a new repository on the command line
|
||||||
|
push_exist_repo = Push an existing repository from the command line
|
||||||
|
|
||||||
|
branch = Branch
|
||||||
|
tree = Tree
|
||||||
|
branch_and_tags = Branches & Tags
|
||||||
|
branches = Branches
|
||||||
|
tags = Tags
|
||||||
|
issues = Issues
|
||||||
|
commits = Commits
|
||||||
|
releases = Releases
|
||||||
|
|
||||||
|
commits.commits = Commits
|
||||||
|
commits.search = Search commits
|
||||||
|
commits.find = Find
|
||||||
|
commits.author = Author
|
||||||
|
commits.message = Message
|
||||||
|
commits.date = Date
|
||||||
|
commits.older = Older
|
||||||
|
commits.newer = Newer
|
||||||
|
|
||||||
settings = Settings
|
settings = Settings
|
||||||
settings.options = Options
|
settings.options = Options
|
||||||
settings.collaboration = Collaboration
|
settings.collaboration = Collaboration
|
||||||
|
@ -201,13 +292,18 @@ settings.basic_settings = Basic Settings
|
||||||
settings.danger_zone = Danger Zone
|
settings.danger_zone = Danger Zone
|
||||||
settings.site = Official Site
|
settings.site = Official Site
|
||||||
settings.update_settings = Update Settings
|
settings.update_settings = Update Settings
|
||||||
|
settings.change_reponame = Repository Name Changed
|
||||||
|
settings.change_reponame_desc = Repository name has been changed, do you want to continue? This will affect all links relate to this repository.
|
||||||
settings.transfer = Transfer Ownership
|
settings.transfer = Transfer Ownership
|
||||||
settings.transfer_desc = Transfer this repo to another user or to an organization where you have admin rights.
|
settings.transfer_desc = Transfer this repo to another user or to an organization where you have admin rights.
|
||||||
|
settings.new_owner_has_same_repo = New owner already has a repository with same name.
|
||||||
settings.delete = Delete This Repository
|
settings.delete = Delete This Repository
|
||||||
settings.delete_desc = Once you delete a repository, there is no going back. Please be certain.
|
settings.delete_desc = Once you delete a repository, there is no going back. Please be certain.
|
||||||
|
settings.transfer_notices = <p>- You will lose access if new owner is a individual user.</p><p>- You will remain access if new owner is an organization and you're one of the owners.</p>
|
||||||
settings.update_settings_success = Repository options has been successfully updated.
|
settings.update_settings_success = Repository options has been successfully updated.
|
||||||
settings.transfer_owner = New Owner
|
settings.transfer_owner = New Owner
|
||||||
settings.make_transfer = Make Transfer
|
settings.make_transfer = Make Transfer
|
||||||
|
settings.transfer_succeed = Repository ownership has been successfully transferred.
|
||||||
settings.confirm_delete = Confirm Deletion
|
settings.confirm_delete = Confirm Deletion
|
||||||
settings.add_collaborator = Add New Collaborator
|
settings.add_collaborator = Add New Collaborator
|
||||||
settings.add_collaborator_success = New collaborator has been added.
|
settings.add_collaborator_success = New collaborator has been added.
|
||||||
|
@ -228,6 +324,11 @@ settings.update_webhook = Update Webhook
|
||||||
settings.update_hook_success = Webhook has been updated.
|
settings.update_hook_success = Webhook has been updated.
|
||||||
settings.delete_webhook = Delete Webhook
|
settings.delete_webhook = Delete Webhook
|
||||||
settings.recent_deliveries = Recent Deliveries
|
settings.recent_deliveries = Recent Deliveries
|
||||||
|
settings.hook_type = Hook Type
|
||||||
|
settings.add_slack_hook_desc = Add <a href="http://slack.com">Slack</a> integration to your repository.
|
||||||
|
settings.slack_token = Token
|
||||||
|
settings.slack_domain = Domain
|
||||||
|
settings.slack_channel = Channel
|
||||||
|
|
||||||
[org]
|
[org]
|
||||||
org_name_holder = Organization Name
|
org_name_holder = Organization Name
|
||||||
|
@ -254,11 +355,16 @@ settings.full_name = Full Name
|
||||||
settings.website = Website
|
settings.website = Website
|
||||||
settings.location = Location
|
settings.location = Location
|
||||||
settings.update_settings = Update Settings
|
settings.update_settings = Update Settings
|
||||||
|
settings.change_orgname = Organization Name Changed
|
||||||
|
settings.change_orgname_desc = Organization name has been changed, do you want to continue? This will affect all links relate to this organization.
|
||||||
settings.update_setting_success = Organization setting has been successfully updated.
|
settings.update_setting_success = Organization setting has been successfully updated.
|
||||||
settings.delete = Delete Organization
|
settings.delete = Delete Organization
|
||||||
settings.delete_account = Delete This Organization
|
settings.delete_account = Delete This Organization
|
||||||
settings.delete_prompt = The operation will delete this organization permanently, and <strong>CANNOT</strong> be undo!
|
settings.delete_prompt = The operation will delete this organization permanently, and <strong>CANNOT</strong> be undone!
|
||||||
settings.confirm_delete_account = Confirm Deletion
|
settings.confirm_delete_account = Confirm Deletion
|
||||||
|
settings.delete_org_title = Organization Deletion
|
||||||
|
settings.delete_org_desc = This organization is going to be deleted permanently, do you want to continue?
|
||||||
|
settings.hooks_desc = Add webhooks that will be triggered for <strong>all repositories</strong> under this organization.
|
||||||
|
|
||||||
members.public = Public
|
members.public = Public
|
||||||
members.public_helper = make private
|
members.public_helper = make private
|
||||||
|
@ -287,6 +393,8 @@ teams.members = Team Members
|
||||||
teams.update_settings = Update Settings
|
teams.update_settings = Update Settings
|
||||||
teams.delete_team = Delete This Team
|
teams.delete_team = Delete This Team
|
||||||
teams.add_team_member = Add Team Member
|
teams.add_team_member = Add Team Member
|
||||||
|
teams.delete_team_title = Team Deletion
|
||||||
|
teams.delete_team_desc = This team is going to be deleted, do you want to continue? Members of this team may lose access to some repositories.
|
||||||
teams.delete_team_success = Given team has been successfully deleted.
|
teams.delete_team_success = Given team has been successfully deleted.
|
||||||
teams.read_permission_desc = This team grants <strong>Read</strong> access: members can view and clone the team's repositories.
|
teams.read_permission_desc = This team grants <strong>Read</strong> access: members can view and clone the team's repositories.
|
||||||
teams.write_permission_desc = This team grants <strong>Write</strong> access: members can read from and push to the team's repositories.
|
teams.write_permission_desc = This team grants <strong>Write</strong> access: members can read from and push to the team's repositories.
|
||||||
|
@ -403,6 +511,8 @@ auths.activated = This authentication has activated
|
||||||
auths.update_success = Authorization setting has been successfully updated.
|
auths.update_success = Authorization setting has been successfully updated.
|
||||||
auths.update = Update Authorization Setting
|
auths.update = Update Authorization Setting
|
||||||
auths.delete = Delete This Authorization
|
auths.delete = Delete This Authorization
|
||||||
|
auths.delete_auth_title = Authorization Deletion
|
||||||
|
auths.delete_auth_desc = This authorization is going to be deleted, do you want to continue?
|
||||||
|
|
||||||
config.server_config = Server Configuration
|
config.server_config = Server Configuration
|
||||||
config.app_name = Application Name
|
config.app_name = Application Name
|
||||||
|
@ -478,10 +588,11 @@ monitor.start = Start Time
|
||||||
monitor.execute_time = Execution Time
|
monitor.execute_time = Execution Time
|
||||||
|
|
||||||
[action]
|
[action]
|
||||||
create_repo = created repository <a href="/%s">%s</a>
|
create_repo = created repository <a href="%s/%s">%s</a>
|
||||||
commit_repo = pushed to <a href="/%s/src/%s">%s</a> at <a href="/%s">%s</a>
|
commit_repo = pushed to <a href="%s/%s/src/%s">%s</a> at <a href="%s/%s">%s</a>
|
||||||
create_issue = opened issue <a href="/%s/issues/%s">%s#%s</a>
|
create_issue = opened issue <a href="%s/%s/issues/%s">%s#%s</a>
|
||||||
comment_issue = commented on issue <a href="/%s/issues/%s">%s#%s</a>
|
comment_issue = commented on issue <a href="%s/%s/issues/%s">%s#%s</a>
|
||||||
|
transfer_repo = transfered repository <code>%s</code> to <a href="/%s%s">%s</a>
|
||||||
|
|
||||||
[tool]
|
[tool]
|
||||||
ago = ago
|
ago = ago
|
||||||
|
|
516
conf/locale/locale_fr-CA.ini
Normal file
516
conf/locale/locale_fr-CA.ini
Normal file
|
@ -0,0 +1,516 @@
|
||||||
|
app_desc = Un service Git écrit en Go auto-hébergé
|
||||||
|
|
||||||
|
home = Accueil
|
||||||
|
dashboard = Tableau de bord
|
||||||
|
explore = Explorer
|
||||||
|
help = Aide
|
||||||
|
sign_in = Connexion
|
||||||
|
social_sign_in = Authentification via Internet: 2ème étape <small>associé le compte</small>
|
||||||
|
sign_out = Déconnexion
|
||||||
|
sign_up = Créer un compte
|
||||||
|
register = S'inscrire
|
||||||
|
website = Site web
|
||||||
|
version = Version
|
||||||
|
page = Page
|
||||||
|
template = Gabarit
|
||||||
|
language = Langage
|
||||||
|
|
||||||
|
username = Usager
|
||||||
|
email = Courriel
|
||||||
|
password = Mot de passe
|
||||||
|
re_type = Saisir à nouveau
|
||||||
|
captcha = Captcha
|
||||||
|
|
||||||
|
repository = Dépôt
|
||||||
|
organization = Organisation
|
||||||
|
mirror = Mirroir
|
||||||
|
new_repo = Nouveau dépôt
|
||||||
|
new_migrate = Nouvelle migration
|
||||||
|
new_org = Nouvel organisation
|
||||||
|
manage_org = Gestion des organisations
|
||||||
|
admin_panel = Gestion
|
||||||
|
account_settings = Profil usager
|
||||||
|
settings = Configuration
|
||||||
|
|
||||||
|
news_feed = Fil de nouvelles
|
||||||
|
pull_requests = Demandes de fusion (pull requests)
|
||||||
|
issues = Suivi de problèmes
|
||||||
|
|
||||||
|
cancel = Annuler
|
||||||
|
|
||||||
|
[home]
|
||||||
|
uname_holder = Nom d'usager ou courriel
|
||||||
|
password_holder = Mot de passe
|
||||||
|
switch_dashboard_context = Changer de tableau de bord
|
||||||
|
my_repos = Mes dépôts
|
||||||
|
collaborative_repos = Dépôts partagés
|
||||||
|
my_orgs = Mes organisations
|
||||||
|
my_mirrors = Mes mirroirs
|
||||||
|
|
||||||
|
[auth]
|
||||||
|
create_new_account = Créer un nouveau compte
|
||||||
|
register_hepler_msg = Déjà inscrits? Connectez-vous maintenant!
|
||||||
|
social_register_hepler_msg = Déjà inscrits? Branchez-vous!
|
||||||
|
disable_register_prompt = Désolé, l'auto-inscription n'est pas activée. Contactez l'admnistrateur du site.
|
||||||
|
disable_register_mail = Désolé, la confirmation d'inscription par courriel est désactivée. Contactez l'administrateur du site.
|
||||||
|
remember_me = Se souvenir de moi
|
||||||
|
forgot_password= Mot de passe oublié
|
||||||
|
forget_password = Mot de passe oublié?
|
||||||
|
sign_up_now = Besoin d'un compte? Inscrivez-vous maintenant.
|
||||||
|
confirmation_mail_sent_prompt = Un courriel de confirmation à été envoyé à <b>%s</b>, consultez vos courriels d'ici %d heures pour terminer l'inscription.
|
||||||
|
sign_in_email = Connexion avec votre courriel
|
||||||
|
active_your_account = Activez votre compte
|
||||||
|
resent_limit_prompt = Désolé vous demandez trop souvent un courriel de confirmation. S.v.p. patientez 3 minutes.
|
||||||
|
has_unconfirmed_mail = Bonjour %s, votre adresse courriel n'est pas vérifiée(<b>%s</b>). Si vous n'avez pas reçu de courriel de confirmation ou si vous avez besoin d'en envoyer un maintenant, appuyez sur le bouton ci-dessous.
|
||||||
|
resend_mail = Appuyez ici pour envoyer de nouveau un courriel de confirmation.
|
||||||
|
email_not_associate = Ce courriel ne correspond à aucun compte.
|
||||||
|
send_reset_mail = Appuyez ici pour (ré)envoyer un courriel pour réinitialiser le mot de passe.
|
||||||
|
reset_password = Réinitialiser votre mot de passe
|
||||||
|
invalid_code = Désolé, ce code de confirmation est périmé ou non-valide.
|
||||||
|
reset_password_helper = Appuyez ici pour réinitialiser votre mot de passe
|
||||||
|
password_too_short = La longueur du mot de passe doit être d'au moins 6 caractères.
|
||||||
|
|
||||||
|
[form]
|
||||||
|
UserName = Nom d'usager
|
||||||
|
RepoName = Nom du dépôt
|
||||||
|
Email = Adresse de courriel
|
||||||
|
Password = Mot de passe
|
||||||
|
Retype = Mot de passe (confirmation)
|
||||||
|
SSHTitle = Nom de la clé SSH
|
||||||
|
HttpsUrl = URL HTTPS
|
||||||
|
PayloadUrl = URL cible
|
||||||
|
TeamName = Nom de l'équipe
|
||||||
|
AuthName = Nom d'usager
|
||||||
|
|
||||||
|
require_error = ` ne peut être vide.`
|
||||||
|
alpha_dash_error = ` doit être composé de caractères alpha-numériques et/ou d'un tiret(-_).`
|
||||||
|
alpha_dash_dot_error = ` doit être composé de caractères alpha-numérique, un point(.) et/ou tiret(-_).`
|
||||||
|
min_size_error = ` doit être composé d'au moins %s caractères.`
|
||||||
|
max_size_error = ` doit être conposé d'au plus %s caractères.`
|
||||||
|
email_error = ` n'est pas une adresse de courriel bien formée.`
|
||||||
|
url_error = ` n'est pas un URL valide.`
|
||||||
|
unknown_error = Erreur inconnue:
|
||||||
|
captcha_incorrect = Le captcha ne concorde pas.
|
||||||
|
password_not_match = Les deux mots de passe diffèrent.
|
||||||
|
|
||||||
|
username_been_taken = `Nom d'usager dèjà utilisé.`
|
||||||
|
repo_name_been_taken = Nom de dépôt déjà utilisé.
|
||||||
|
org_name_been_taken = Nom d'organisation déjà utilisé.
|
||||||
|
team_name_been_taken = Nom d'équipe déjà utilisé.
|
||||||
|
email_been_used = Adresse de courriel déjà utilisée.
|
||||||
|
ssh_key_been_used = Nom de clé publique déjà utilisé.
|
||||||
|
illegal_username = Votre nom d'usager contient des caractères interdits.
|
||||||
|
illegal_repo_name = Le nom du dépôt contient des caractères interdits.
|
||||||
|
illegal_org_name = Le nom de l'organisation contient des caractères interdits.
|
||||||
|
illegal_team_name = Le nom de l'équipe contient des caractères interdits.
|
||||||
|
username_password_incorrect = Nom d'usager ou mot de passe erroné.
|
||||||
|
enterred_invalid_repo_name = Nom de dépôt inexistant.
|
||||||
|
enterred_invalid_owner_name = Responsable de dépôt inexistant.
|
||||||
|
enterred_invalid_password = Mot de passe erroné.
|
||||||
|
user_not_exist = Nom d'usager inexistant.
|
||||||
|
last_org_owner = Ceci est le dernier responsable du dépôt. Il doit y avoir obligatoirement au moins un usager responsable.
|
||||||
|
|
||||||
|
invalid_ssh_key = Désolé, impossible de vérifier votre clé SSH: %
|
||||||
|
auth_failed = Erreur d'authentification : %v
|
||||||
|
|
||||||
|
still_own_repo = Votre compte est responsable d'au moins un dépôt. Vous devez soit détruire ces dépôts, soit transférer la responsabilité à un autre usager.
|
||||||
|
org_still_own_repo = Cette organisation est responsable d'au moins un dépôt. Vous devez soit détruire ces dépôts, soit transférer la responsabilité à un autre usager ou organisation.
|
||||||
|
|
||||||
|
still_own_user = Cette authentification est utilisée par un usager.
|
||||||
|
|
||||||
|
[settings]
|
||||||
|
profile = Profil
|
||||||
|
password = Mot de passe
|
||||||
|
ssh_keys = Clés SSH
|
||||||
|
social = Comptes Internet
|
||||||
|
orgs = Organisations
|
||||||
|
delete = Supprimer votre compte
|
||||||
|
|
||||||
|
public_profile = Profil public
|
||||||
|
profile_desc = Votre adresse de courriel est publique et sera utilisée pour les avis produits par le site.
|
||||||
|
full_name = Nom complet
|
||||||
|
website = Site web
|
||||||
|
location = Endroit
|
||||||
|
update_profile = Mettre à jour le profil
|
||||||
|
update_profile_success = Mise à jour du profil réussie.
|
||||||
|
|
||||||
|
change_password = Changer le mot de passe
|
||||||
|
old_password = Mot de passe actuel
|
||||||
|
new_password = Nouveau mot de passe
|
||||||
|
password_incorrect = Mot de passe actuel erroné.
|
||||||
|
change_password_success = Modification du mot de passe effectuée. Vous pouvez dorénavant vous connecter avec le nouveau mot de passe.
|
||||||
|
|
||||||
|
manage_ssh_keys = Gestion des clés SSH
|
||||||
|
add_key = Ajouter une clé
|
||||||
|
ssh_desc = Voici la liste de clés SSH associées à votre profil. Retirez les clés que vous ne reconnaissez pas.
|
||||||
|
ssh_helper = <strong>Beson d'aide?</strong> Consultez le guide au <a href="https://help.github.com/articles/generating-ssh-keys">generating SSH keys</a> ou vérifiez <a href="https://help.github.com/ssh-issues/">les problèmes SSH fréquents</a>.
|
||||||
|
add_new_key = Ajouter une clé SSH
|
||||||
|
key_name = Nom de la clé
|
||||||
|
key_content = Contenu
|
||||||
|
add_key_success = Clé SSH ajoutée!
|
||||||
|
delete_key = Détruire
|
||||||
|
add_on = Ajoutée le
|
||||||
|
last_used = Dernière utilisation le
|
||||||
|
no_activity = Pas d'activité récente
|
||||||
|
|
||||||
|
manage_social = Gestion des comptes Internets associés
|
||||||
|
social_desc = Ceci est une liste de comptes Internet associés. Retirez les comptes que vous ne reconnaissez pas.
|
||||||
|
unbind = Désassocier
|
||||||
|
unbind_success = Compte Internet déassocié.
|
||||||
|
|
||||||
|
delete_account = Detruire votre compte
|
||||||
|
delete_prompt = Cette opération détruira votre compte et <strong>ne pourra être annulée</strong>!
|
||||||
|
confirm_delete_account = Confirmez la suppression
|
||||||
|
|
||||||
|
[repo]
|
||||||
|
owner = Responsable
|
||||||
|
repo_name = Nom du dépôt
|
||||||
|
repo_name_helper = Les bons noms de dépôts sont courts, mémorables et <strong>uniques</strong>.
|
||||||
|
visibility = Visibilité
|
||||||
|
visiblity_helper = Ce dépôt est <span class="label label-red label-radius">privé</span>
|
||||||
|
repo_desc = Description
|
||||||
|
repo_lang = Langue
|
||||||
|
repo_lang_helper = Choisir un fichier .gitignore
|
||||||
|
license = License
|
||||||
|
license_helper = Choisir un fichier de licence
|
||||||
|
init_readme = Initialiser le dépôt avec un fichier README.md
|
||||||
|
create_repo = Créer le dépôt
|
||||||
|
default_branch = Branche par défaut
|
||||||
|
mirror_interval = Intervale de synchronisation (heures)
|
||||||
|
goget_meta = Métadonnées Go-Get
|
||||||
|
goget_meta_helper = Ce dépôt sera <span class="label label-blue label-radius">Go-Getable</span>
|
||||||
|
|
||||||
|
need_auth = Authorisation requise
|
||||||
|
migrate_type = Type de migration
|
||||||
|
migrate_type_helper = Ce dépôt sera un <span class="label label-blue label-radius">mirroir</span>
|
||||||
|
migrate_repo = Migrer le dépôt
|
||||||
|
|
||||||
|
copy_link = Copier
|
||||||
|
clone_helper = Besoin d'aide pour cloner? Obtenez de l' <a target="_blank" href="http://git-scm.com/book/fr/Les-bases-de-Git-Démarrer-un-dépôt-Git">aide</a>!
|
||||||
|
unwatch = Ne plus suivre
|
||||||
|
watch = Suivre
|
||||||
|
unstar = Retirer étoile
|
||||||
|
star = Étoile
|
||||||
|
fork = Fork
|
||||||
|
|
||||||
|
quick_guide = Guide rapide
|
||||||
|
clone_this_repo = Cloner ce dépôt
|
||||||
|
create_new_repo_command = Créer un nouveau dépôt à la ligne de commande
|
||||||
|
push_exist_repo = Pousser un dépôt existant depuis la ligne de commande
|
||||||
|
|
||||||
|
settings = Réglages
|
||||||
|
settings.options = Réglages de base
|
||||||
|
settings.collaboration = Collaboration
|
||||||
|
settings.hooks = Webhooks
|
||||||
|
settings.deploy_keys = Clé de déploiement
|
||||||
|
settings.basic_settings = réglages de base
|
||||||
|
settings.danger_zone = Danger!
|
||||||
|
settings.site = Site officiel
|
||||||
|
settings.update_settings = Réglage des mises à jour
|
||||||
|
settings.transfer = Transférer la responsabilité
|
||||||
|
settings.transfer_desc = Transférer ce dépôt à un autre usager ou organisation si vous en avez la responsabilité.
|
||||||
|
settings.delete = Détruire ce dépôt
|
||||||
|
settings.delete_desc = La destruction est irrémédiable, impossible d'annuler. Soyez sûr de votre décision.
|
||||||
|
settings.update_settings_success = Réglages modifiés
|
||||||
|
settings.transfer_owner = Nouveau responsable
|
||||||
|
settings.make_transfer = Faire le transfert
|
||||||
|
settings.confirm_delete = Confirmer la destruction
|
||||||
|
settings.add_collaborator = Ajouter un nouveau collaborateur
|
||||||
|
settings.add_collaborator_success = Nouveau collaborateur ajouté.
|
||||||
|
settings.remove_collaborator_success = Collaborateur supprimé.
|
||||||
|
settings.add_webhook = Ajouter un Webhook
|
||||||
|
settings.hooks_desc = Les Webhooks permettent à des services externes d'être avertis de certains changements sur Gogs. Lorque qu'un changement se produit, Gogs envoie une requête POST à chacun des URLs spécifiés. Plus d'info disponible sur notre <a target="_blank" href="http://gogs.io/docs/features/webhook.html">guide Webhooks'</a>.
|
||||||
|
settings.remove_hook_success = Webhook supprimé.
|
||||||
|
settings.add_webhook_desc = Gogs envoiera un POST à l'URL ci-dessous avec le détail de l'événement souscrit. Vous pouvez aussi spécifier dans quel format vous désirez recevoir les données (JSON,<code>x-www-form-urlencoded</code>, <em>etc</em>). Plus d'info disponible sur notre <a target="_blank" href="http://gogs.io/docs/features/webhook.html">guide Webhooks'</a>.
|
||||||
|
settings.payload_url = URL cible
|
||||||
|
settings.content_type = Content Type
|
||||||
|
settings.secret = Secret
|
||||||
|
settings.event_desc = Quels changements déclencheront le webhook?
|
||||||
|
settings.event_push_only = Uniquement les <code>push</code>.
|
||||||
|
settings.active = Activé
|
||||||
|
settings.active_helper = Gogs fournira le détail de l'événement lorsque ce webhook sera déclenché.
|
||||||
|
settings.add_hook_success = Nouveau webhook ajouté.
|
||||||
|
settings.update_webhook = Mettre à jour le webhook
|
||||||
|
settings.update_hook_success = Webhook mis à jour.
|
||||||
|
settings.delete_webhook = Détruire le webhook
|
||||||
|
settings.recent_deliveries = Livraisons récentes
|
||||||
|
settings.hook_type = Type de déclencheur
|
||||||
|
settings.add_slack_hook_desc = Ajouter la compatibilité <a href="http://slack.com">Slack</a> à ce dépôt.
|
||||||
|
settings.slack_token = Jeton (token)
|
||||||
|
settings.slack_domain = Domaine
|
||||||
|
settings.slack_channel = Canal
|
||||||
|
|
||||||
|
[org]
|
||||||
|
org_name_holder = Nom de l'organisation
|
||||||
|
org_name_helper = Les bons noms d'organisations sont courts, mémorables et uniques
|
||||||
|
org_email_helper = Le courriel de l'organisation recevra toutes les notifications et les confirmations.
|
||||||
|
create_org = Créer une organisation
|
||||||
|
repo_updated = Changement effectué
|
||||||
|
people = Personne
|
||||||
|
invite_someone = Inviter quelqu'un
|
||||||
|
teams = Équipes
|
||||||
|
lower_members = Membres
|
||||||
|
lower_repositories = Dépôts
|
||||||
|
create_new_team = Créer une nouvelle équipe
|
||||||
|
org_desc = Description
|
||||||
|
team_name = Nom de l'équipe
|
||||||
|
team_desc = Description
|
||||||
|
team_name_helper = Le nom qui sera utilisé pour mentionner cette équipe dans les conversations.
|
||||||
|
team_desc_helper = Quel est la raison d'être de cette équipe?
|
||||||
|
team_permission_desc = Quel niveau de permission attribuer à cette équipe?
|
||||||
|
|
||||||
|
settings = Réglages
|
||||||
|
settings.options = Paramètres
|
||||||
|
settings.full_name = Nom complet
|
||||||
|
settings.website = Site web
|
||||||
|
settings.location = Endroit
|
||||||
|
settings.update_settings = Mettre à jour les paramètres
|
||||||
|
settings.update_setting_success = Paramètres mis à jour.
|
||||||
|
settings.delete = Détruire l'organisation
|
||||||
|
settings.delete_account = Détruire cette organisation
|
||||||
|
settings.delete_prompt = La destruction de l'organisation est irrémédiable, impossible d'annuler. Soyez sûr de votre décision.
|
||||||
|
settings.confirm_delete_account = Confirmer la destruction
|
||||||
|
|
||||||
|
members.public = Publique
|
||||||
|
members.public_helper = Rendre privé
|
||||||
|
members.private = Privé
|
||||||
|
members.private_helper = Rendre publique
|
||||||
|
members.owner = Responsable
|
||||||
|
members.member = Membre
|
||||||
|
members.conceal = Caché
|
||||||
|
members.remove = Retirer
|
||||||
|
members.leave = Quitter
|
||||||
|
members.invite_desc = Commencez à saisir un nom d'usager pour l'inviter à %s:
|
||||||
|
members.invite_now = Inviter
|
||||||
|
|
||||||
|
teams.join = Rejoindre
|
||||||
|
teams.leave = Quitter
|
||||||
|
teams.read_access = Droits de lecture
|
||||||
|
teams.read_access_helper = Cette équipe pourra voir et cloner ses dépôts.
|
||||||
|
teams.write_access = Droits d'écriture
|
||||||
|
teams.write_access_helper = Cette équipe pourra voir et cloner ses dépôts ainsi que pousser vers ceux-ci.
|
||||||
|
teams.admin_access = Droits de gestion
|
||||||
|
teams.admin_access_helper = En plus des droits d'écriture, cette équipe pourra gérer les collaborateurs.
|
||||||
|
teams.no_desc = Cette équipe ne posséde pas de description
|
||||||
|
teams.settings = Réglages
|
||||||
|
teams.owners_permission_desc = Les responsables ont accès à <strong>tous</strong> les dépôts et en possédent les droits de gestion.
|
||||||
|
teams.members = Membre de l'équipe
|
||||||
|
teams.update_settings = Mettre à jour
|
||||||
|
teams.delete_team = Détruire cette équipe
|
||||||
|
teams.add_team_member = Ajouter un membre à l'équipe
|
||||||
|
teams.delete_team_success = Équipe détruite
|
||||||
|
teams.read_permission_desc = La participation à cette équipe confère les droits de lecture. Ses membres peuvent voir et cloner ses dépôts.
|
||||||
|
teams.write_permission_desc = La participation à cette équipe confère les droits d'écriture en plus des droits de lecture. Ses membres peuvent pousser vers les dépôts de l'équipe.
|
||||||
|
teams.admin_permission_desc = La participation à cette équire confère les droits de gestion. Ses membres peuvent voir, cloner, pousser et gérer les collaborateurs des dépôts.
|
||||||
|
teams.repositories = Dépôts de l'équipe
|
||||||
|
teams.add_team_repository = Ajouer un dépôt à l'équipe
|
||||||
|
teams.remove_repo = Enlever
|
||||||
|
|
||||||
|
[admin]
|
||||||
|
dashboard = Tableau de bord
|
||||||
|
users = Usagers
|
||||||
|
organizations = Organisations
|
||||||
|
repositories = Dépôts
|
||||||
|
authentication = Sources d'authentifications
|
||||||
|
config = Configuration
|
||||||
|
monitor = Monitoring
|
||||||
|
prev = Préc.
|
||||||
|
next = Suiv.
|
||||||
|
|
||||||
|
dashboard.statistic = Statistiques
|
||||||
|
dashboard.operations = Opérations
|
||||||
|
dashboard.system_status = État du monitoring système
|
||||||
|
dashboard.statistic_info = La BD Gogs compte <b>%d</b> usagers, <b>%d</b> organisations, <b>%d</b> clé SSH, <b>%d</b> dépôts, <b>%d</b> suivis, <b>%d</b> étoiles, <b>%d</b> actions, <b>%d</b> accès, <b>%d</b> tickets, <b>%d</b> commentaires, <b>%d</b> comptes Internet, <b>%d</b> suivis, <b>%d</b> mirroirs, <b>%d</b> publications, <b>%d</b> sources d'authentification, <b>%d</b> webhooks, <b>%d</b> jalons, <b>%d</b> tags, <b>%d</b> tâches hook, <b>%d</b> équipes, <b>%d</b> tâches de mise à jours, <b>%d</b> fichiers joints.
|
||||||
|
dashboard.operation_name = Nom de l'opération
|
||||||
|
dashboard.operation_switch = Commande
|
||||||
|
dashboard.operation_run = Lancer
|
||||||
|
dashboard.clean_unbind_oauth = Nettoyer les OAuths orphelins
|
||||||
|
dashboard.delete_inactivate_accounts = Détruire les comptes inactifs
|
||||||
|
dashboard.server_uptime = Démarré depuis
|
||||||
|
dashboard.current_goroutine = Nombre de Goroutines
|
||||||
|
dashboard.current_memory_usage = Usage mémoire actuel
|
||||||
|
dashboard.total_memory_allocated = Mémoire allouée totale
|
||||||
|
dashboard.memory_obtained = Memoire obtenue
|
||||||
|
dashboard.pointer_lookup_times = Accès pointeur
|
||||||
|
dashboard.memory_allocate_times = Allocation mémoire
|
||||||
|
dashboard.memory_free_times = Désallocation mémoire
|
||||||
|
dashboard.current_heap_usage = Taille du heap actuelle
|
||||||
|
dashboard.heap_memory_obtained = Mémoire heap obtenue
|
||||||
|
dashboard.heap_memory_idle = Mémoire heap inactive
|
||||||
|
dashboard.heap_memory_in_use = Mémoire heap utilisée
|
||||||
|
dashboard.heap_memory_released = Mémoire heap relachée
|
||||||
|
dashboard.heap_objects = Objets dans le heap
|
||||||
|
dashboard.bootstrap_stack_usage = Bootstrap Stack Usage
|
||||||
|
dashboard.stack_memory_obtained = Stack Memory Obtained
|
||||||
|
dashboard.mspan_structures_usage = MSpan Structures Usage
|
||||||
|
dashboard.mspan_structures_obtained = MSpan Structures Obtained
|
||||||
|
dashboard.mcache_structures_usage = MCache Structures Usage
|
||||||
|
dashboard.mcache_structures_obtained = MCache Structures Obtained
|
||||||
|
dashboard.profiling_bucket_hash_table_obtained = Profiling Bucket Hash Table Obtained
|
||||||
|
dashboard.gc_metadata_obtained = GC Metadada Obtained
|
||||||
|
dashboard.other_system_allocation_obtained = Other System Allocation Obtained
|
||||||
|
dashboard.next_gc_recycle = Next GC Recycle
|
||||||
|
dashboard.last_gc_time = Since Last GC Time
|
||||||
|
dashboard.total_gc_time = Total GC Pause
|
||||||
|
dashboard.total_gc_pause = Total GC Pause
|
||||||
|
dashboard.last_gc_pause = Last GC Pause
|
||||||
|
dashboard.gc_times = GC Times
|
||||||
|
|
||||||
|
users.user_manage_panel = Gestion des usager
|
||||||
|
users.new_account = Creér un nouveau compte
|
||||||
|
users.name = Nom
|
||||||
|
users.activated = Activé
|
||||||
|
users.admin = Gestionnaire
|
||||||
|
users.repos = Dépôts
|
||||||
|
users.created = Créé
|
||||||
|
users.edit = Editer
|
||||||
|
users.auth_source = Source d'authentification
|
||||||
|
users.local = Locale
|
||||||
|
users.auth_login_name = Identifiant d'authentification
|
||||||
|
users.update_profile_success = Compte crée.
|
||||||
|
users.edit_account = Éditer compte
|
||||||
|
users.is_activated = Ce compte est activé
|
||||||
|
users.is_admin = Ce compte a les droits de gestionnaire
|
||||||
|
users.update_profile = Mettre à jour le compte
|
||||||
|
users.delete_account = Détruire ce compte
|
||||||
|
users.still_own_repo = Ce compte est responsables d'un dépôt. I faut détruire le dépôt ou transférer la responsabilité avant de détruire ce compte.
|
||||||
|
|
||||||
|
orgs.org_manage_panel = Gestion des organisations
|
||||||
|
orgs.name = Nom
|
||||||
|
orgs.teams = Équipes
|
||||||
|
orgs.members = Membres
|
||||||
|
|
||||||
|
repos.repo_manage_panel = Gestion des dépôts
|
||||||
|
repos.owner = Responsable
|
||||||
|
repos.name = Nom
|
||||||
|
repos.private = Privé
|
||||||
|
repos.watches = Suivis
|
||||||
|
repos.stars = Étoiles
|
||||||
|
repos.issues = Ticket
|
||||||
|
|
||||||
|
auths.auth_manage_panel = Gestion des sources d'authentification
|
||||||
|
auths.new = Ajouter une nouvelle source d'authentification
|
||||||
|
auths.name = Nom
|
||||||
|
auths.type = Type
|
||||||
|
auths.enabled = Activé
|
||||||
|
auths.updated = Mis à jour
|
||||||
|
auths.auth_type = Type d'authentification
|
||||||
|
auths.auth_name = Nom de l'authentification
|
||||||
|
auths.domain = Domaine
|
||||||
|
auths.host = Serveur
|
||||||
|
auths.port = Port
|
||||||
|
auths.base_dn = DN de base
|
||||||
|
auths.attributes = Attributs de recherche
|
||||||
|
auths.filter = Filtre de recherche
|
||||||
|
auths.ms_ad_sa = Microsoft Active Directory
|
||||||
|
auths.smtp_auth = Authentification SMTP
|
||||||
|
auths.smtphost = Serveur SMTP
|
||||||
|
auths.smtpport = Port SMTP
|
||||||
|
auths.enable_tls = Chiffrement TLS
|
||||||
|
auths.enable_auto_register = Activer auto-abonnement
|
||||||
|
auths.tips = Trucs
|
||||||
|
auths.edit = Éditer réglages d'authentification
|
||||||
|
auths.activated = Source d'authentification activée
|
||||||
|
auths.update_success = Réglages mis à jour.
|
||||||
|
auths.update = Mettre à jour réglages
|
||||||
|
auths.delete = Détruire cette source
|
||||||
|
|
||||||
|
config.server_config = Configuration du serveur
|
||||||
|
config.app_name = Nom de l'applicaiton
|
||||||
|
config.app_ver = Version de l'application
|
||||||
|
config.app_url = URL de l'application
|
||||||
|
config.domain = Domaine
|
||||||
|
config.offline_mode = Mode hors-ligne
|
||||||
|
config.disable_router_log = Journal du routeur désactivé
|
||||||
|
config.run_user = Éxécuté en tant que
|
||||||
|
config.run_mode = Mode de fonctionnement
|
||||||
|
config.repo_root_path = Dossier contenant les dépôts
|
||||||
|
config.static_file_root_path = Dossier contenant les fichiers statiques
|
||||||
|
config.log_file_root_path = Dossier contenant les journaux
|
||||||
|
config.script_type = Type de script
|
||||||
|
config.reverse_auth_user = Usager d'authentification inversée
|
||||||
|
config.db_config = Configuration de la BD
|
||||||
|
config.db_type = Type
|
||||||
|
config.db_host = Serveur
|
||||||
|
config.db_name = Nom
|
||||||
|
config.db_user = Usager
|
||||||
|
config.db_ssl_mode = Mode SSL
|
||||||
|
config.db_ssl_mode_helper = (pour "postgres" seulement)
|
||||||
|
config.db_path = Path
|
||||||
|
config.db_path_helper = (pour "sqlite3" seulement)
|
||||||
|
config.service_config = Configuration du service
|
||||||
|
config.register_email_confirm = Confirmation d'abonnement par courriel
|
||||||
|
config.disable_register = Auto-inscription désactivée
|
||||||
|
config.require_sign_in_view = Connexion requise pour visualiser
|
||||||
|
config.mail_notify = Notifications par courriel
|
||||||
|
config.enable_cache_avatar = Cache avatar activée
|
||||||
|
config.active_code_lives = Jeton d'activation
|
||||||
|
config.reset_password_code_lives = Jeton de modification mot-de-passe
|
||||||
|
config.webhook_config = Configuration Webhook
|
||||||
|
config.task_interval = Intervalle
|
||||||
|
config.deliver_timeout = Expiration des appels
|
||||||
|
config.mailer_config = Configuration expédition de courriels
|
||||||
|
config.mailer_enabled = Activé
|
||||||
|
config.mailer_name = Nom
|
||||||
|
config.mailer_host = Serveur
|
||||||
|
config.mailer_user = Usager
|
||||||
|
config.oauth_config = Configuration OAuth
|
||||||
|
config.oauth_enabled = Activé
|
||||||
|
config.cache_config = Configuration du cache
|
||||||
|
config.cache_adapter = Mécanisme de cache
|
||||||
|
config.cache_interval = Intervalle
|
||||||
|
config.cache_conn = Chaîne de connexion
|
||||||
|
config.session_config = Configuration des session
|
||||||
|
config.session_provider = Mécanisme
|
||||||
|
config.provider_config = Configuration du mécanisme
|
||||||
|
config.cookie_name = Nom du fichier témoin
|
||||||
|
config.enable_set_cookie = Fichier témoin actvité
|
||||||
|
config.gc_interval_time = Intervalle GC
|
||||||
|
config.session_life_time = Durée de la session
|
||||||
|
config.https_only = HTTPS exigé
|
||||||
|
config.cookie_life_time = Expiration du fichier témoin
|
||||||
|
config.session_hash_function = Fonction de hashage ID de session
|
||||||
|
config.session_hash_key = Clé de hashage ID de session
|
||||||
|
config.picture_config = Configuration des avatars
|
||||||
|
config.picture_service = Service image
|
||||||
|
config.disable_gravatar = Désactivé Gravatar
|
||||||
|
config.log_config = Configuration du journal
|
||||||
|
config.log_mode = Mode de journal
|
||||||
|
|
||||||
|
monitor.cron = Cron Tasks
|
||||||
|
monitor.name = Name
|
||||||
|
monitor.schedule = Schedule
|
||||||
|
monitor.next = Next Time
|
||||||
|
monitor.previous = Previous Time
|
||||||
|
monitor.execute_times = Execute Times
|
||||||
|
monitor.process = Running Processes
|
||||||
|
monitor.desc = Description
|
||||||
|
monitor.start = Start Time
|
||||||
|
monitor.execute_time = Execution Time
|
||||||
|
|
||||||
|
[action]
|
||||||
|
create_repo = a créé le dépôt <a href="/%s">%s</a>
|
||||||
|
commit_repo = a poussé sur <a href="/%s/src/%s">%s</a> à <a href="/%s">%s</a>
|
||||||
|
create_issue = a ouvert le ticket <a href="/%s/issues/%s">%s#%s</a>
|
||||||
|
comment_issue = a commenté sur le ticket <a href="/%s/issues/%s">%s#%s</a>
|
||||||
|
|
||||||
|
[tool]
|
||||||
|
ago = auparavant
|
||||||
|
from_now = depuis
|
||||||
|
now = maintenant
|
||||||
|
1s = 1 seconde %s
|
||||||
|
1m = 1 minute %s
|
||||||
|
1h = 1 heure %s
|
||||||
|
1d = 1 jour %s
|
||||||
|
1w = 1 semaine %s
|
||||||
|
1mon = 1 mos %s
|
||||||
|
1y = 1 an %s
|
||||||
|
seconds = %d secondes %s
|
||||||
|
minutes = %d minutes %s
|
||||||
|
hours = %d heures %s
|
||||||
|
days = %d jours %s
|
||||||
|
weeks = %d semaines %s
|
||||||
|
months = %d mois %s
|
||||||
|
years = %d années %s
|
||||||
|
raw_seconds = secondes
|
||||||
|
raw_minutes = minutes
|
|
@ -38,6 +38,50 @@ issues = 工单管理
|
||||||
|
|
||||||
cancel = 取消
|
cancel = 取消
|
||||||
|
|
||||||
|
[install]
|
||||||
|
install = 安装页面
|
||||||
|
title = 首次运行安装程序
|
||||||
|
requite_db_desc = Gogs 允许后端数据库为 MySQL、PostgreSQL 或 SQLite3,但是 SQLite3 一般只有官方二进制发行版才支持。
|
||||||
|
db_type = 数据库类型
|
||||||
|
host = 数据库主机
|
||||||
|
user = 数据库用户
|
||||||
|
password = 数据库用户密码
|
||||||
|
db_name = 数据库名称
|
||||||
|
db_helper = 如果您使用 MySQL,请使用 INNODB 引擎以及 utf8_general_ci 字符集。
|
||||||
|
ssl_mode = SSL 模式
|
||||||
|
path = 数据库文件路径
|
||||||
|
sqlite_helper = SQLite3 数据库的文件路径。
|
||||||
|
general_title = 应用基本设置
|
||||||
|
repo_path = 仓库根目录
|
||||||
|
repo_path_helper = 所有 Git 远程仓库都将被存放于该目录。
|
||||||
|
run_user = 运行系统用户
|
||||||
|
run_user_helper = 该用户必须具有对仓库根目录和运行 Gogs 的操作权限。
|
||||||
|
domain = 域名
|
||||||
|
domain_helper = 该设置影响 SSH 克隆地址。
|
||||||
|
app_url = 应用 URL
|
||||||
|
app_url_helper = 该设置影响 HTTP/HTTPS 克隆地址和一些邮箱中的链接。
|
||||||
|
email_title = 邮件服务设置(可选)
|
||||||
|
smtp_host = SMTP 主机
|
||||||
|
mailer_user = 发送邮箱
|
||||||
|
mailer_password = 发送邮箱密码
|
||||||
|
notify_title = 通知提醒设置(可选)
|
||||||
|
register_confirm = 启用注册邮箱确认
|
||||||
|
mail_notify = 启用邮件通知提醒
|
||||||
|
admin_title = 管理员帐号设置
|
||||||
|
admin_name = 管理员用户名
|
||||||
|
admin_password = 管理员密码
|
||||||
|
confirm_password = 确认密码
|
||||||
|
admin_email = 管理员邮箱
|
||||||
|
install_gogs = 立即安装
|
||||||
|
test_git_failed = 无法识别 'git' 命令:%v
|
||||||
|
sqlite3_not_available = 您所使用的发行版不支持 SQLite3,请从 http://gogs.io/docs/installation/install_from_binary.html 下载官方二进制发行版,而不是 gobuild 版本。
|
||||||
|
invalid_db_setting = 数据库设置不正确:%v
|
||||||
|
invalid_repo_path = 仓库根目录设置不正确:%v
|
||||||
|
run_user_not_match = 运行系统用户非当前用户:%s -> %s
|
||||||
|
save_config_failed = 应用配置保存失败:%v
|
||||||
|
invalid_admin_setting = 管理员帐户设置不正确:%v
|
||||||
|
install_success = 您好!我们很高兴您选择使用 Gogs,祝您使用愉快,代码从此无 BUG!
|
||||||
|
|
||||||
[home]
|
[home]
|
||||||
uname_holder = 用户名或邮箱
|
uname_holder = 用户名或邮箱
|
||||||
password_holder = 密码
|
password_holder = 密码
|
||||||
|
@ -47,6 +91,9 @@ collaborative_repos = 参与协作的仓库
|
||||||
my_orgs = 我的组织
|
my_orgs = 我的组织
|
||||||
my_mirrors = 我的镜像
|
my_mirrors = 我的镜像
|
||||||
|
|
||||||
|
[explore]
|
||||||
|
repos = 探索仓库
|
||||||
|
|
||||||
[auth]
|
[auth]
|
||||||
create_new_account = 创建帐户
|
create_new_account = 创建帐户
|
||||||
register_hepler_msg = 已经注册?立即登录!
|
register_hepler_msg = 已经注册?立即登录!
|
||||||
|
@ -81,6 +128,7 @@ HttpsUrl = HTTPS URL 地址
|
||||||
PayloadUrl = 推送地址
|
PayloadUrl = 推送地址
|
||||||
TeamName = 团队名称
|
TeamName = 团队名称
|
||||||
AuthName = 认证名称
|
AuthName = 认证名称
|
||||||
|
AdminEmail = 管理员邮箱
|
||||||
|
|
||||||
require_error = 不能为空。
|
require_error = 不能为空。
|
||||||
alpha_dash_error = 必须为英文字母、阿拉伯数字或横线(-_)。
|
alpha_dash_error = 必须为英文字母、阿拉伯数字或横线(-_)。
|
||||||
|
@ -118,6 +166,15 @@ org_still_own_repo = 该组织仍然是某些仓库的拥有者,您必须先
|
||||||
|
|
||||||
still_own_user = 该授权认证依旧被部分用户使用,请先删除该部分用户后再试!
|
still_own_user = 该授权认证依旧被部分用户使用,请先删除该部分用户后再试!
|
||||||
|
|
||||||
|
[user]
|
||||||
|
change_avatar = 到 gravatar.com 上修改您的头像
|
||||||
|
join_on = 加入于
|
||||||
|
repositories = 仓库列表
|
||||||
|
activity = 公开活动
|
||||||
|
followers = 关注者
|
||||||
|
starred = 已点赞
|
||||||
|
following = 关注中
|
||||||
|
|
||||||
[settings]
|
[settings]
|
||||||
profile = 个人信息
|
profile = 个人信息
|
||||||
password = 修改密码
|
password = 修改密码
|
||||||
|
@ -125,6 +182,7 @@ ssh_keys = 管理 SSH 密钥
|
||||||
social = 社交帐号绑定
|
social = 社交帐号绑定
|
||||||
orgs = 管理组织
|
orgs = 管理组织
|
||||||
delete = 删除帐户
|
delete = 删除帐户
|
||||||
|
uid = 用户 ID
|
||||||
|
|
||||||
public_profile = 公开信息
|
public_profile = 公开信息
|
||||||
profile_desc = 您的邮箱地址将会被公开,并被用于接收帐户的所有提醒和通知。
|
profile_desc = 您的邮箱地址将会被公开,并被用于接收帐户的所有提醒和通知。
|
||||||
|
@ -133,6 +191,10 @@ website = 个人网站
|
||||||
location = 所在地区
|
location = 所在地区
|
||||||
update_profile = 更新信息
|
update_profile = 更新信息
|
||||||
update_profile_success = 您的个人信息更新成功!
|
update_profile_success = 您的个人信息更新成功!
|
||||||
|
change_username = 用户名将被修改
|
||||||
|
change_username_desc = 用户名被修改,您确定要继续操作吗?这将会影响到所有与您帐户有关的链接。
|
||||||
|
continue = 继续操作
|
||||||
|
cancel = 取消操作
|
||||||
|
|
||||||
change_password = 修改密码
|
change_password = 修改密码
|
||||||
old_password = 当前密码
|
old_password = 当前密码
|
||||||
|
@ -161,6 +223,8 @@ unbind_success = 社交帐号解除绑定成功!
|
||||||
delete_account = 删除当前帐户
|
delete_account = 删除当前帐户
|
||||||
delete_prompt = 删除操作会永久清除您的帐户信息,并且 <strong>不可恢复</strong>!
|
delete_prompt = 删除操作会永久清除您的帐户信息,并且 <strong>不可恢复</strong>!
|
||||||
confirm_delete_account = 确认删除帐户
|
confirm_delete_account = 确认删除帐户
|
||||||
|
delete_account_title = 帐户删除操作
|
||||||
|
delete_account_desc = 该帐户将被永久性删除,您确定要继续操作吗?
|
||||||
|
|
||||||
[repo]
|
[repo]
|
||||||
owner = 拥有者
|
owner = 拥有者
|
||||||
|
@ -185,6 +249,9 @@ migrate_type = 迁移类型
|
||||||
migrate_type_helper = 本仓库将是 <span class="label label-blue label-radius">镜像</span>
|
migrate_type_helper = 本仓库将是 <span class="label label-blue label-radius">镜像</span>
|
||||||
migrate_repo = 迁移仓库
|
migrate_repo = 迁移仓库
|
||||||
|
|
||||||
|
copy_link = 复制链接
|
||||||
|
click_to_copy = 复制到剪切板
|
||||||
|
copied = 复制成功
|
||||||
clone_helper = 不知道如何操作?访问 <a target="_blank" href="http://git-scm.com/book/zh/Git-基础-取得项目的-Git-仓库">此处</a> 查看帮助!
|
clone_helper = 不知道如何操作?访问 <a target="_blank" href="http://git-scm.com/book/zh/Git-基础-取得项目的-Git-仓库">此处</a> 查看帮助!
|
||||||
unwatch = 取消关注
|
unwatch = 取消关注
|
||||||
watch = 关注
|
watch = 关注
|
||||||
|
@ -192,6 +259,30 @@ unstar = 取消点赞
|
||||||
star = 点赞
|
star = 点赞
|
||||||
fork = 派生
|
fork = 派生
|
||||||
|
|
||||||
|
no_desc = 暂无描述
|
||||||
|
quick_guide = 快速帮助
|
||||||
|
clone_this_repo = 克隆当前仓库
|
||||||
|
create_new_repo_command = 从命令行创建一个新的仓库
|
||||||
|
push_exist_repo = 从命令行推送已经创建的仓库
|
||||||
|
|
||||||
|
branch = 分支
|
||||||
|
tree = 目录树
|
||||||
|
branch_and_tags = 分支与标签
|
||||||
|
branches = 分支列表
|
||||||
|
tags = 标签列表
|
||||||
|
issues = 工单管理
|
||||||
|
commits = 提交历史
|
||||||
|
releases = 版本发布
|
||||||
|
|
||||||
|
commits.commits = 次代码提交
|
||||||
|
commits.search = 搜索提交历史
|
||||||
|
commits.find = 查找
|
||||||
|
commits.author = 作者
|
||||||
|
commits.message = 备注
|
||||||
|
commits.date = 提交日期
|
||||||
|
commits.older = 更旧的提交
|
||||||
|
commits.newer = 更新的提交
|
||||||
|
|
||||||
settings = 仓库设置
|
settings = 仓库设置
|
||||||
settings.options = 基本设置
|
settings.options = 基本设置
|
||||||
settings.collaboration = 管理协作者
|
settings.collaboration = 管理协作者
|
||||||
|
@ -201,13 +292,18 @@ settings.basic_settings = 基本设置
|
||||||
settings.danger_zone = 危险操作区
|
settings.danger_zone = 危险操作区
|
||||||
settings.site = 官方网站
|
settings.site = 官方网站
|
||||||
settings.update_settings = 更新仓库设置
|
settings.update_settings = 更新仓库设置
|
||||||
|
settings.change_reponame = 仓库名称将被修改
|
||||||
|
settings.change_reponame_desc = 仓库名称被修改,您确定要继续操作吗?这将会影响到所有与该仓库有关的链接。
|
||||||
settings.transfer = 转移仓库所有权
|
settings.transfer = 转移仓库所有权
|
||||||
settings.transfer_desc = 您可以将仓库转移至您拥有管理员权限的帐户或组织。
|
settings.transfer_desc = 您可以将仓库转移至您拥有管理员权限的帐户或组织。
|
||||||
|
settings.new_owner_has_same_repo = 新的仓库拥有者已经存在同名仓库!
|
||||||
settings.delete = 删除本仓库
|
settings.delete = 删除本仓库
|
||||||
settings.delete_desc = 删除仓库操作不可逆转,请三思而后行。
|
settings.delete_desc = 删除仓库操作不可逆转,请三思而后行。
|
||||||
|
settings.transfer_notices = <p>- 如果您转移给个人用户,您将对仓库失去所有权限。</p><p>- 如果您转移给您作为拥有者的组织,则可继续保持操作权限。</p>
|
||||||
settings.update_settings_success = 仓库设置更新成功!
|
settings.update_settings_success = 仓库设置更新成功!
|
||||||
settings.transfer_owner = 新拥有者
|
settings.transfer_owner = 新拥有者
|
||||||
settings.make_transfer = 确认转移仓库
|
settings.make_transfer = 确认转移仓库
|
||||||
|
settings.transfer_succeed = 仓库所有权转移成功!
|
||||||
settings.confirm_delete = 确认删除仓库
|
settings.confirm_delete = 确认删除仓库
|
||||||
settings.add_collaborator = 增加新的协作者
|
settings.add_collaborator = 增加新的协作者
|
||||||
settings.add_collaborator_success = 成功添加新的协作者!
|
settings.add_collaborator_success = 成功添加新的协作者!
|
||||||
|
@ -228,6 +324,11 @@ settings.update_webhook = 更新 Web 钩子
|
||||||
settings.update_hook_success = Web 钩子更新成功!
|
settings.update_hook_success = Web 钩子更新成功!
|
||||||
settings.delete_webhook = 删除 Web 钩子
|
settings.delete_webhook = 删除 Web 钩子
|
||||||
settings.recent_deliveries = 最近推送记录
|
settings.recent_deliveries = 最近推送记录
|
||||||
|
settings.hook_type = 钩子类型
|
||||||
|
settings.add_slack_hook_desc = 为您的仓库增加 <a href="http://slack.com">Slack</a> 集成
|
||||||
|
settings.slack_token = 令牌
|
||||||
|
settings.slack_domain = 域名
|
||||||
|
settings.slack_channel = 频道
|
||||||
|
|
||||||
[org]
|
[org]
|
||||||
org_name_holder = 组织名称
|
org_name_holder = 组织名称
|
||||||
|
@ -254,11 +355,16 @@ settings.full_name = 组织全名
|
||||||
settings.website = 官方网站
|
settings.website = 官方网站
|
||||||
settings.location = 所在地区
|
settings.location = 所在地区
|
||||||
settings.update_settings = 更新组织设置
|
settings.update_settings = 更新组织设置
|
||||||
|
settings.change_orgname = 组织名称将被修改
|
||||||
|
settings.change_orgname_desc = 组织名称被修改,您确定要继续操作吗?这将会影响到所有与该组织有关的链接。
|
||||||
settings.update_setting_success = 组织设置更新成功!
|
settings.update_setting_success = 组织设置更新成功!
|
||||||
settings.delete = 删除组织
|
settings.delete = 删除组织
|
||||||
settings.delete_account = 删除当前组织
|
settings.delete_account = 删除当前组织
|
||||||
settings.delete_prompt = 删除操作会永久清除该组织的信息,并且 <strong>不可恢复</strong>!
|
settings.delete_prompt = 删除操作会永久清除该组织的信息,并且 <strong>不可恢复</strong>!
|
||||||
settings.confirm_delete_account = 确认删除组织
|
settings.confirm_delete_account = 确认删除组织
|
||||||
|
settings.delete_org_title = 组织删除操作
|
||||||
|
settings.delete_org_desc = 该组织将被永久性删除,您确定要继续操作吗?
|
||||||
|
settings.hooks_desc = 在此处添加的 Web 钩子将会应用到该组织下的 <strong>所有仓库</strong>。
|
||||||
|
|
||||||
members.public = 公开成员
|
members.public = 公开成员
|
||||||
members.public_helper = 设为私有
|
members.public_helper = 设为私有
|
||||||
|
@ -287,6 +393,8 @@ teams.members = 团队成员
|
||||||
teams.update_settings = 更新团队设置
|
teams.update_settings = 更新团队设置
|
||||||
teams.delete_team = 删除当前团队
|
teams.delete_team = 删除当前团队
|
||||||
teams.add_team_member = 添加团队成员
|
teams.add_team_member = 添加团队成员
|
||||||
|
teams.delete_team_title = 团队删除操作
|
||||||
|
teams.delete_team_desc = 删除操作会永久清除有关该团队的信息,您确定要继续操作吗?团队成员可能会失去对某些仓库的操作权限。
|
||||||
teams.delete_team_success = 指定团队删除成功!
|
teams.delete_team_success = 指定团队删除成功!
|
||||||
teams.read_permission_desc = 该团队拥有对所属仓库的 <strong>读取</strong> 权限,团队成员可以进行查看和克隆等只读操作。
|
teams.read_permission_desc = 该团队拥有对所属仓库的 <strong>读取</strong> 权限,团队成员可以进行查看和克隆等只读操作。
|
||||||
teams.write_permission_desc = 该团队拥有对所属仓库的 <strong>读取</strong> 和 <strong>写入</strong> 的权限。
|
teams.write_permission_desc = 该团队拥有对所属仓库的 <strong>读取</strong> 和 <strong>写入</strong> 的权限。
|
||||||
|
@ -362,6 +470,7 @@ users.is_activated = 该用户已被激活
|
||||||
users.is_admin = 该用户具有管理员权限
|
users.is_admin = 该用户具有管理员权限
|
||||||
users.update_profile = 更新用户信息
|
users.update_profile = 更新用户信息
|
||||||
users.delete_account = 删除该用户
|
users.delete_account = 删除该用户
|
||||||
|
users.still_own_repo = 该帐户仍然是某些仓库的拥有者,您必须先转移或删除它们才能执行删除帐户操作!
|
||||||
|
|
||||||
orgs.org_manage_panel = 组织管理面板
|
orgs.org_manage_panel = 组织管理面板
|
||||||
orgs.name = 组织名称
|
orgs.name = 组织名称
|
||||||
|
@ -402,6 +511,8 @@ auths.activated = 该授权认证已经启用
|
||||||
auths.update_success = 授权认证设置更新成功!
|
auths.update_success = 授权认证设置更新成功!
|
||||||
auths.update = 更新授权认证信息
|
auths.update = 更新授权认证信息
|
||||||
auths.delete = 删除该授权认证
|
auths.delete = 删除该授权认证
|
||||||
|
auths.delete_auth_title = 授权认证删除操作
|
||||||
|
auths.delete_auth_desc = 该授权认证将被删除,您确定要继续吗?
|
||||||
|
|
||||||
config.server_config = 服务器配置
|
config.server_config = 服务器配置
|
||||||
config.app_name = 应用名称
|
config.app_name = 应用名称
|
||||||
|
@ -477,10 +588,11 @@ monitor.start = 开始时间
|
||||||
monitor.execute_time = 已执行时间
|
monitor.execute_time = 已执行时间
|
||||||
|
|
||||||
[action]
|
[action]
|
||||||
create_repo = 创建了仓库 <a href="/%s">%s</a>
|
create_repo = 创建了仓库 <a href="%s/%s">%s</a>
|
||||||
commit_repo = 推送了 <a href="/%s/src/%s">%s</a> 分支的代码到 <a href="/%s">%s</a>
|
commit_repo = 推送了 <a href="%s/%s/src/%s">%s</a> 分支的代码到 <a href="%s/%s">%s</a>
|
||||||
create_issue = 创建了工单 <a href="/%s/issues/%s">%s#%s</a>
|
create_issue = 创建了工单 <a href="%s/%s/issues/%s">%s#%s</a>
|
||||||
comment_issue = 评论了工单 <a href="/%s/issues/%s">%s#%s</a>
|
comment_issue = 评论了工单 <a href="%s/%s/issues/%s">%s#%s</a>
|
||||||
|
transfer_repo = 将仓库 <code>%s</code> 转移至 <a href="/%s%s">%s</a>
|
||||||
|
|
||||||
[tool]
|
[tool]
|
||||||
ago = 之前
|
ago = 之前
|
||||||
|
|
89
docker/README.md
Normal file
89
docker/README.md
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
Docker
|
||||||
|
======
|
||||||
|
|
||||||
|
TOOLS ARE WRITTEN FOR TESTING AND TO SEE WHAT IT IS!
|
||||||
|
|
||||||
|
For this to work you will need the nifty docker tool [fig].
|
||||||
|
|
||||||
|
The most simple setup will look like this:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./assemble_blocks.sh docker_gogs w_db option_db_mysql
|
||||||
|
fig up
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
That's it. You have GoGS running in docker linked to a MySQL docker container.
|
||||||
|
|
||||||
|
Now visit http://localhost:3000/ and give details for the admin account an you're up and running.
|
||||||
|
|
||||||
|
|
||||||
|
How does it work
|
||||||
|
----------------
|
||||||
|
|
||||||
|
`./assemble_blocks.sh` will look in `blocks` for subdirectories.
|
||||||
|
In the subdirectories there are three relevant files: `Dockerfile`, `config` and `fig`.
|
||||||
|
|
||||||
|
`Dockerfile` will be copied to `docker/` (also means last `Dockerfile` wins).
|
||||||
|
|
||||||
|
The `config` file contains lines which will in the gogs docker container end up in `$GOGS_PATH/custom/config/app.ini` and by this gogs will be configured.
|
||||||
|
Here you can define things like the MySQL server for your database block.
|
||||||
|
|
||||||
|
The `fig` file will just be added to `fig.yml`, which is used by fig to manage your containers.
|
||||||
|
This inculdes container linking!
|
||||||
|
|
||||||
|
Just have a look at them and it will be clear how to write your own blocks.
|
||||||
|
|
||||||
|
Just some things
|
||||||
|
|
||||||
|
- all files (`Dockerfile`, `fig` and `config`) are optional
|
||||||
|
- the gogs block should always be the first block
|
||||||
|
|
||||||
|
Currently the blocks are designed that, the blocks that start with `docker` pull in the base docker image.
|
||||||
|
Then one block starting with `w` defines, what containers should be linked to the gogs container.
|
||||||
|
For every option in the `w` block you need to add an `option` container.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./assemble_blocks.sh docker_gogs w_db_cache option_db_mysql option_cache_redis
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
More sophisticated Example
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
Her is a more elaborated example
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./assemble_blocks.sh docker_gogs w_db_cache_session option_db_postgresql option_cache_redis option_session_mysql
|
||||||
|
fig up
|
||||||
|
```
|
||||||
|
|
||||||
|
This will set up four containters and link them proberly. One for each of
|
||||||
|
|
||||||
|
- gogs
|
||||||
|
- database (postgresql)
|
||||||
|
- cache (redis)
|
||||||
|
- session (mysql)
|
||||||
|
|
||||||
|
WARNING: This will not work at the Moment! MySQL session is broken!
|
||||||
|
|
||||||
|
|
||||||
|
Remark
|
||||||
|
------
|
||||||
|
|
||||||
|
After you execute `assemble_blocks.sh` you should always trigger `fig build` to inculde the the new init script `init_gogs.sh` in the docker image.
|
||||||
|
|
||||||
|
If you want to use another GoGS docker file, but keep everything else the same, you can create a block, e.g. `docker_gogs_custom`, with only a `Dockerfile` and call
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./assemble_blocks.sh docker_gogs_custom w_db option_database_mysql
|
||||||
|
```
|
||||||
|
|
||||||
|
This will pull in the `Dockerfile` from `docker_gogs` instead of the one from `docker_gogs`.
|
||||||
|
|
||||||
|
`Dockerfile`s for the `master` and `dev` branch are provided as `docker_gogs` and `docker_gogs_dev`
|
||||||
|
|
||||||
|
|
||||||
|
[fig]:http://www.fig.sh/
|
72
docker/assemble_blocks.sh
Executable file
72
docker/assemble_blocks.sh
Executable file
|
@ -0,0 +1,72 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
blocks_dir=blocks
|
||||||
|
docker_dir=docker
|
||||||
|
template_dir=templates
|
||||||
|
|
||||||
|
docker_file=Dockerfile
|
||||||
|
|
||||||
|
gogs_config_file=conf.tmp
|
||||||
|
gogs_config=config
|
||||||
|
gogs_init_file=$docker_dir/init_gogs.sh
|
||||||
|
|
||||||
|
fig_file=fig.yml
|
||||||
|
fig_config=fig
|
||||||
|
|
||||||
|
gogs_init_template=$template_dir/init_gogs.sh.tpl
|
||||||
|
|
||||||
|
if [ "$#" == 0 ]; then
|
||||||
|
blocks=`ls $blocks_dir`
|
||||||
|
if [ -z "$blocks" ]; then
|
||||||
|
echo "No Blocks available in $blocks_dir"
|
||||||
|
else
|
||||||
|
echo "Available Blocks:"
|
||||||
|
for block in $blocks; do
|
||||||
|
echo " $block"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
for file in $gogs_config_file $fig_file; do
|
||||||
|
if [ -e $file ]; then
|
||||||
|
echo "Deleting $file"
|
||||||
|
rm $file
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
for dir in $@; do
|
||||||
|
current_dir=$blocks_dir/$dir
|
||||||
|
if [ ! -d "$current_dir" ]; then
|
||||||
|
echo "$current_dir is not a directory"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e $current_dir/$docker_file ]; then
|
||||||
|
echo "Copying $current_dir/$docker_file to $docker_dir/$docker_file"
|
||||||
|
cp $current_dir/$docker_file $docker_dir/$docker_file
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e $current_dir/$gogs_config ]; then
|
||||||
|
echo "Adding $current_dir/$gogs_config to $gogs_config_file"
|
||||||
|
cat $current_dir/$gogs_config >> $gogs_config_file
|
||||||
|
echo "" >> $gogs_config_file
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e $current_dir/$fig_config ]; then
|
||||||
|
echo "Adding $current_dir/$fig_config to $fig_file"
|
||||||
|
cat $current_dir/fig >> $fig_file
|
||||||
|
echo "" >> $fig_file
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Creating $gogs_init_file"
|
||||||
|
sed "/{{ CONFIG }}/{
|
||||||
|
r $gogs_config_file
|
||||||
|
d
|
||||||
|
}" $gogs_init_template > $gogs_init_file
|
||||||
|
|
||||||
|
if [ -e $gogs_config_file ]; then
|
||||||
|
echo "Removing temporary GoGS config"
|
||||||
|
rm $gogs_config_file
|
||||||
|
fi
|
52
docker/blocks/docker_gogs/Dockerfile
Normal file
52
docker/blocks/docker_gogs/Dockerfile
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
FROM ubuntu:14.04
|
||||||
|
|
||||||
|
# This part is taken from the official docker image --------------------
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
build-essential ca-certificates curl \
|
||||||
|
bzr git mercurial \
|
||||||
|
--no-install-recommends
|
||||||
|
|
||||||
|
ENV GOLANG_VERSION 1.3
|
||||||
|
|
||||||
|
RUN curl -sSL http://golang.org/dl/go$GOLANG_VERSION.src.tar.gz \
|
||||||
|
| tar -v -C /usr/src -xz
|
||||||
|
WORKDIR /usr/src/go
|
||||||
|
|
||||||
|
RUN cd src && ./make.bash --no-clean 2>&1
|
||||||
|
|
||||||
|
ENV PATH /usr/src/go/bin:$PATH
|
||||||
|
|
||||||
|
RUN mkdir -p /go/src
|
||||||
|
ENV GOPATH /go
|
||||||
|
ENV PATH /go/bin:$PATH
|
||||||
|
WORKDIR /go
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
RUN useradd -m git
|
||||||
|
|
||||||
|
ENV GOGS_PATH $GOPATH/src/github.com/gogits/gogs
|
||||||
|
ENV GOGS_CUSTOM_CONF_PATH $GOGS_PATH/custom/conf
|
||||||
|
ENV GOGS_CUSTOM_CONF $GOGS_CUSTOM_CONF_PATH/app.ini
|
||||||
|
|
||||||
|
RUN go get -u -d github.com/gogits/gogs
|
||||||
|
# WORKDIR $GOGS_PATH
|
||||||
|
WORKDIR /go/src/github.com/gogits/gogs
|
||||||
|
RUN go build github.com/gogits/gogs
|
||||||
|
RUN chown -R git $GOGS_PATH
|
||||||
|
|
||||||
|
ADD init_gogs.sh /tmp/
|
||||||
|
RUN chown git /tmp/init_gogs.sh
|
||||||
|
RUN chmod +x /tmp/init_gogs.sh
|
||||||
|
|
||||||
|
USER git
|
||||||
|
ENV HOME /home/git
|
||||||
|
ENV USER git
|
||||||
|
ENV PATH $GOGS_PATH:$PATH
|
||||||
|
|
||||||
|
RUN git config --global user.name "GoGS"
|
||||||
|
|
||||||
|
ENTRYPOINT ["/tmp/init_gogs.sh"]
|
||||||
|
CMD ["gogs", "web"]
|
53
docker/blocks/docker_gogs_dev/Dockerfile
Normal file
53
docker/blocks/docker_gogs_dev/Dockerfile
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
FROM ubuntu:14.04
|
||||||
|
|
||||||
|
# This part is derived from the official docker image ------------------
|
||||||
|
|
||||||
|
RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
|
||||||
|
apt-get install -qy \
|
||||||
|
build-essential ca-certificates curl \
|
||||||
|
bzr git mercurial \
|
||||||
|
--no-install-recommends
|
||||||
|
|
||||||
|
ENV GOLANG_VERSION 1.3
|
||||||
|
|
||||||
|
RUN curl -sSL http://golang.org/dl/go$GOLANG_VERSION.src.tar.gz \
|
||||||
|
| tar -v -C /usr/src -xz
|
||||||
|
WORKDIR /usr/src/go
|
||||||
|
|
||||||
|
RUN cd src && ./make.bash --no-clean 2>&1
|
||||||
|
|
||||||
|
ENV PATH /usr/src/go/bin:$PATH
|
||||||
|
|
||||||
|
RUN mkdir -p /go/src
|
||||||
|
ENV GOPATH /go
|
||||||
|
ENV PATH /go/bin:$PATH
|
||||||
|
WORKDIR /go
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
RUN useradd -m git
|
||||||
|
|
||||||
|
ENV GOGS_PATH $GOPATH/src/github.com/gogits/gogs
|
||||||
|
ENV GOGS_CUSTOM_CONF_PATH $GOGS_PATH/custom/conf
|
||||||
|
ENV GOGS_CUSTOM_CONF $GOGS_CUSTOM_CONF_PATH/app.ini
|
||||||
|
|
||||||
|
RUN git clone -b dev https://github.com/gogits/gogs.git $GOGS_PATH
|
||||||
|
# WORKDIR $GOGS_PATH
|
||||||
|
WORKDIR /go/src/github.com/gogits/gogs
|
||||||
|
RUN go get -d && go build
|
||||||
|
RUN chown -R git $GOGS_PATH
|
||||||
|
|
||||||
|
ADD init_gogs.sh /tmp/
|
||||||
|
RUN chown git /tmp/init_gogs.sh
|
||||||
|
RUN chmod +x /tmp/init_gogs.sh
|
||||||
|
|
||||||
|
USER git
|
||||||
|
ENV HOME /home/git
|
||||||
|
ENV USER git
|
||||||
|
ENV PATH $GOGS_PATH:$PATH
|
||||||
|
|
||||||
|
RUN git config --global user.name "GoGS"
|
||||||
|
|
||||||
|
ENTRYPOINT ["/tmp/init_gogs.sh"]
|
||||||
|
CMD ["gogs", "web"]
|
3
docker/blocks/option_cache_memcache/config
Normal file
3
docker/blocks/option_cache_memcache/config
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[cache]
|
||||||
|
DB_TYPE = memcache
|
||||||
|
HOST = HOST = ${CACHE_1_PORT_11211_TCP_ADDR}:${CACHE_1_PORT_11211_TCP_PORT}
|
2
docker/blocks/option_cache_memcache/fig
Normal file
2
docker/blocks/option_cache_memcache/fig
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
cache:
|
||||||
|
image: sylvainlasnier/memcached:latest
|
3
docker/blocks/option_cache_redis/config
Normal file
3
docker/blocks/option_cache_redis/config
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[cache]
|
||||||
|
DB_TYPE = redis
|
||||||
|
HOST = ${CACHE_1_PORT_6379_TCP_ADDR}:${CACHE_1_PORT_6379_TCP_PORT}
|
2
docker/blocks/option_cache_redis/fig
Normal file
2
docker/blocks/option_cache_redis/fig
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
cache:
|
||||||
|
image: redis:latest
|
6
docker/blocks/option_db_mysql/config
Normal file
6
docker/blocks/option_db_mysql/config
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[database]
|
||||||
|
DB_TYPE = mysql
|
||||||
|
HOST = ${DB_1_PORT_3306_TCP_ADDR}:${DB_1_PORT_3306_TCP_PORT}
|
||||||
|
NAME = ${DB_1_ENV_MYSQL_DATABASE}
|
||||||
|
USER = ${DB_1_ENV_MYSQL_USER}
|
||||||
|
PASSWD = ${DB_1_ENV_MYSQL_PASSWORD}
|
7
docker/blocks/option_db_mysql/fig
Normal file
7
docker/blocks/option_db_mysql/fig
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
db:
|
||||||
|
image: mysql:latest
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: rootpass
|
||||||
|
MYSQL_DATABASE: gogs
|
||||||
|
MYSQL_USER: gogs
|
||||||
|
MYSQL_PASSWORD: password
|
6
docker/blocks/option_db_postgresql/config
Normal file
6
docker/blocks/option_db_postgresql/config
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[database]
|
||||||
|
DB_TYPE = postgres
|
||||||
|
HOST = ${DB_1_PORT_5432_TCP_ADDR}:${DB_1_PORT_5432_TCP_PORT}
|
||||||
|
NAME = ${DB_1_ENV_POSTGRESQL_DB}
|
||||||
|
USER = ${DB_1_ENV_POSTGRESQL_USER}
|
||||||
|
PASSWD = ${DB_1_ENV_POSTGRESQL_PASS}
|
6
docker/blocks/option_db_postgresql/fig
Normal file
6
docker/blocks/option_db_postgresql/fig
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
db:
|
||||||
|
image: wyaeld/postgres:9.3
|
||||||
|
environment:
|
||||||
|
POSTGRESQL_DB: gogs
|
||||||
|
POSTGRESQL_USER: gogs
|
||||||
|
POSTGRESQL_PASS: password
|
3
docker/blocks/option_session_mysql/config
Normal file
3
docker/blocks/option_session_mysql/config
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[session]
|
||||||
|
PROVIDER = mysql
|
||||||
|
PROVIDER_CONFIG = ${SESSION_1_ENV_MYSQL_USER}:${SESSION_1_ENV_MYSQL_PASSWORD}@SESSION_1_PORT_3306_TCP_PROTO(${SESSION_1_PORT_3306_TCP_ADDR}:${SESSION_1_PORT_3306_TCP_PORT})/${SESSION_1_ENV_MYSQL_DATABASE}
|
7
docker/blocks/option_session_mysql/fig
Normal file
7
docker/blocks/option_session_mysql/fig
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
session:
|
||||||
|
image: mysql:latest
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: rootpass
|
||||||
|
MYSQL_DATABASE: gogs_session
|
||||||
|
MYSQL_USER: gogs
|
||||||
|
MYSQL_PASSWORD: password
|
6
docker/blocks/w_cache/fig
Normal file
6
docker/blocks/w_cache/fig
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
gogs:
|
||||||
|
build: docker
|
||||||
|
links:
|
||||||
|
- cache
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
7
docker/blocks/w_cache_session/fig
Normal file
7
docker/blocks/w_cache_session/fig
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
gogs:
|
||||||
|
build: docker
|
||||||
|
links:
|
||||||
|
- cache
|
||||||
|
- session
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
6
docker/blocks/w_db/fig
Normal file
6
docker/blocks/w_db/fig
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
gogs:
|
||||||
|
build: docker
|
||||||
|
links:
|
||||||
|
- db
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
7
docker/blocks/w_db_cache/fig
Normal file
7
docker/blocks/w_db_cache/fig
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
gogs:
|
||||||
|
build: docker
|
||||||
|
links:
|
||||||
|
- db
|
||||||
|
- cache
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
8
docker/blocks/w_db_cache_session/fig
Normal file
8
docker/blocks/w_db_cache_session/fig
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
gogs:
|
||||||
|
build: docker
|
||||||
|
links:
|
||||||
|
- db
|
||||||
|
- cache
|
||||||
|
- session
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
7
docker/blocks/w_db_session/fig
Normal file
7
docker/blocks/w_db_session/fig
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
gogs:
|
||||||
|
build: docker
|
||||||
|
links:
|
||||||
|
- db
|
||||||
|
- session
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
4
docker/blocks/w_none/fig
Normal file
4
docker/blocks/w_none/fig
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
gogs:
|
||||||
|
build: docker
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
6
docker/blocks/w_session/fig
Normal file
6
docker/blocks/w_session/fig
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
gogs:
|
||||||
|
build: docker
|
||||||
|
links:
|
||||||
|
- session
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
12
docker/templates/init_gogs.sh.tpl
Normal file
12
docker/templates/init_gogs.sh.tpl
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if [ ! -d "$DIRECTORY" ]; then
|
||||||
|
mkdir -p $GOGS_CUSTOM_CONF_PATH
|
||||||
|
|
||||||
|
echo "
|
||||||
|
{{ CONFIG }}
|
||||||
|
" >> $GOGS_CUSTOM_CONF
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$@"
|
|
@ -1,40 +0,0 @@
|
||||||
### Install Gogs With Docker
|
|
||||||
|
|
||||||
Deploying gogs in [Docker](http://www.docker.io/) is just as easy as eating a pie, what you do is just open the `dockerfiles/build.sh` file, replace the configs:
|
|
||||||
|
|
||||||
```
|
|
||||||
DB_TYPE="YOUR_DB_TYPE" # type of database, support 'mysql' and 'postgres'
|
|
||||||
MEM_TYPE="YOUR_MEM_TYPE" # type of memory database, support 'redis' and 'memcache'
|
|
||||||
DB_PASSWORD="YOUR_DB_PASSWORD" # The database password.
|
|
||||||
DB_RUN_NAME="YOUR_DB_RUN_NAME" # The --name option value when run the database image.
|
|
||||||
MEM_RUN_NAME="YOUR_MEM_RUN_NAME" # The --name option value when run the mem database image.
|
|
||||||
HOST_PORT="YOUR_HOST_PORT" # The port on host, which will be redirected to the port 3000 inside gogs container.
|
|
||||||
```
|
|
||||||
|
|
||||||
And run:
|
|
||||||
```
|
|
||||||
cd dockerfiles
|
|
||||||
./build.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
The build might take some time, just be patient. After it finishes, you will receive the message:
|
|
||||||
|
|
||||||
```
|
|
||||||
Now we have the MySQL image(running) and gogs image, use the follow command to start gogs service( the content might be different, according to your own configs):
|
|
||||||
docker run -i -t --link YOUR_DB_RUN_NAME:db --link YOUR_MEM_RUN_NAME:mem -p YOUR_HOST_PORT:3000 gogits/gogs
|
|
||||||
```
|
|
||||||
|
|
||||||
Just follow the message, run:
|
|
||||||
|
|
||||||
```
|
|
||||||
docker run -i -t --link YOUR_DB_RUN_NAME:db --link YOUR_MEM_RUN_NAME:mem -p YOUR_HOST_PORT:3000 gogits/gogs
|
|
||||||
```
|
|
||||||
|
|
||||||
Now we have gogs running! Open the browser and navigate to:
|
|
||||||
|
|
||||||
```
|
|
||||||
http://YOUR_HOST_IP:YOUR_HOST_PORT
|
|
||||||
```
|
|
||||||
|
|
||||||
Let's 'gogs'!
|
|
||||||
Ouya~
|
|
3
gogs.go
3
gogs.go
|
@ -17,7 +17,7 @@ import (
|
||||||
"github.com/gogits/gogs/modules/setting"
|
"github.com/gogits/gogs/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
const APP_VER = "0.4.9.0831 Beta"
|
const APP_VER = "0.5.4.1003 Beta"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
@ -35,6 +35,7 @@ func main() {
|
||||||
cmd.CmdUpdate,
|
cmd.CmdUpdate,
|
||||||
cmd.CmdFix,
|
cmd.CmdFix,
|
||||||
cmd.CmdDump,
|
cmd.CmdDump,
|
||||||
|
cmd.CmdCert,
|
||||||
}
|
}
|
||||||
app.Flags = append(app.Flags, []cli.Flag{}...)
|
app.Flags = append(app.Flags, []cli.Flag{}...)
|
||||||
app.Run(os.Args)
|
app.Run(os.Args)
|
||||||
|
|
103
models/action.go
103
models/action.go
|
@ -137,7 +137,7 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
url := fmt.Sprintf("/%s/%s/commit/%s", repoUserName, repoName, c.Sha1)
|
url := fmt.Sprintf("%s/%s/%s/commit/%s", setting.AppSubUrl, repoUserName, repoName, c.Sha1)
|
||||||
message := fmt.Sprintf(`<a href="%s">%s</a>`, url, c.Message)
|
message := fmt.Sprintf(`<a href="%s">%s</a>`, url, c.Message)
|
||||||
|
|
||||||
if _, err = CreateComment(userId, issue.RepoId, issue.Id, 0, 0, COMMIT, message, nil); err != nil {
|
if _, err = CreateComment(userId, issue.RepoId, issue.Id, 0, 0, COMMIT, message, nil); err != nil {
|
||||||
|
@ -172,7 +172,7 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
|
||||||
|
|
||||||
// CommitRepoAction adds new action for committing repository.
|
// CommitRepoAction adds new action for committing repository.
|
||||||
func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
|
func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
|
||||||
repoId int64, repoUserName, repoName string, refFullName string, commit *base.PushCommits) error {
|
repoId int64, repoUserName, repoName string, refFullName string, commit *base.PushCommits, oldCommitId string, newCommitId string) error {
|
||||||
|
|
||||||
opType := COMMIT_REPO
|
opType := COMMIT_REPO
|
||||||
// Check it's tag push or branch.
|
// Check it's tag push or branch.
|
||||||
|
@ -220,14 +220,44 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
|
||||||
|
|
||||||
ws, err := GetActiveWebhooksByRepoId(repoId)
|
ws, err := GetActiveWebhooksByRepoId(repoId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("action.CommitRepoAction(GetWebhooksByRepoId): " + err.Error())
|
return errors.New("action.CommitRepoAction(GetActiveWebhooksByRepoId): " + err.Error())
|
||||||
} else if len(ws) == 0 {
|
}
|
||||||
|
|
||||||
|
// check if repo belongs to org and append additional webhooks
|
||||||
|
if repo.Owner.IsOrganization() {
|
||||||
|
// get hooks for org
|
||||||
|
orgws, err := GetActiveWebhooksByOrgId(repo.OwnerId)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("action.CommitRepoAction(GetActiveWebhooksByOrgId): " + err.Error())
|
||||||
|
}
|
||||||
|
ws = append(ws, orgws...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ws) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
repoLink := fmt.Sprintf("%s%s/%s", setting.AppUrl, repoUserName, repoName)
|
repoLink := fmt.Sprintf("%s%s/%s", setting.AppUrl, repoUserName, repoName)
|
||||||
|
compareUrl := ""
|
||||||
|
// if not the first commit, set the compareUrl
|
||||||
|
if !strings.HasPrefix(oldCommitId, "0000000") {
|
||||||
|
compareUrl = fmt.Sprintf("%s/compare/%s...%s", repoLink, oldCommitId, newCommitId)
|
||||||
|
}
|
||||||
|
|
||||||
|
pusher_email, pusher_name := "", ""
|
||||||
|
pusher, err := GetUserByName(userName)
|
||||||
|
if err == nil {
|
||||||
|
pusher_email = pusher.Email
|
||||||
|
pusher_name = pusher.GetFullNameFallback()
|
||||||
|
}
|
||||||
|
|
||||||
commits := make([]*PayloadCommit, len(commit.Commits))
|
commits := make([]*PayloadCommit, len(commit.Commits))
|
||||||
for i, cmt := range commit.Commits {
|
for i, cmt := range commit.Commits {
|
||||||
|
author_username := ""
|
||||||
|
author, err := GetUserByEmail(cmt.AuthorEmail)
|
||||||
|
if err == nil {
|
||||||
|
author_username = author.Name
|
||||||
|
}
|
||||||
commits[i] = &PayloadCommit{
|
commits[i] = &PayloadCommit{
|
||||||
Id: cmt.Sha1,
|
Id: cmt.Sha1,
|
||||||
Message: cmt.Message,
|
Message: cmt.Message,
|
||||||
|
@ -235,6 +265,7 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
|
||||||
Author: &PayloadAuthor{
|
Author: &PayloadAuthor{
|
||||||
Name: cmt.AuthorName,
|
Name: cmt.AuthorName,
|
||||||
Email: cmt.AuthorEmail,
|
Email: cmt.AuthorEmail,
|
||||||
|
UserName: author_username,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,15 +280,20 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
|
||||||
Website: repo.Website,
|
Website: repo.Website,
|
||||||
Watchers: repo.NumWatches,
|
Watchers: repo.NumWatches,
|
||||||
Owner: &PayloadAuthor{
|
Owner: &PayloadAuthor{
|
||||||
Name: repoUserName,
|
Name: repo.Owner.GetFullNameFallback(),
|
||||||
Email: actEmail,
|
Email: repo.Owner.Email,
|
||||||
|
UserName: repo.Owner.Name,
|
||||||
},
|
},
|
||||||
Private: repo.IsPrivate,
|
Private: repo.IsPrivate,
|
||||||
},
|
},
|
||||||
Pusher: &PayloadAuthor{
|
Pusher: &PayloadAuthor{
|
||||||
Name: repo.Owner.LowerName,
|
Name: pusher_name,
|
||||||
Email: repo.Owner.Email,
|
Email: pusher_email,
|
||||||
|
UserName: userName,
|
||||||
},
|
},
|
||||||
|
Before: oldCommitId,
|
||||||
|
After: newCommitId,
|
||||||
|
CompareUrl: compareUrl,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, w := range ws {
|
for _, w := range ws {
|
||||||
|
@ -266,15 +302,36 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Secret = w.Secret
|
switch w.HookTaskType {
|
||||||
|
case SLACK:
|
||||||
|
{
|
||||||
|
s, err := GetSlackPayload(p, w.Meta)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("action.GetSlackPayload: " + err.Error())
|
||||||
|
}
|
||||||
CreateHookTask(&HookTask{
|
CreateHookTask(&HookTask{
|
||||||
Type: WEBHOOK,
|
Type: w.HookTaskType,
|
||||||
Url: w.Url,
|
Url: w.Url,
|
||||||
Payload: p,
|
BasePayload: s,
|
||||||
ContentType: w.ContentType,
|
ContentType: w.ContentType,
|
||||||
IsSsl: w.IsSsl,
|
IsSsl: w.IsSsl,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
p.Secret = w.Secret
|
||||||
|
CreateHookTask(&HookTask{
|
||||||
|
Type: w.HookTaskType,
|
||||||
|
Url: w.Url,
|
||||||
|
BasePayload: p,
|
||||||
|
ContentType: w.ContentType,
|
||||||
|
IsSsl: w.IsSsl,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
go DeliverHooks()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,13 +350,29 @@ func NewRepoAction(u *User, repo *Repository) (err error) {
|
||||||
|
|
||||||
// TransferRepoAction adds new action for transfering repository.
|
// TransferRepoAction adds new action for transfering repository.
|
||||||
func TransferRepoAction(u, newUser *User, repo *Repository) (err error) {
|
func TransferRepoAction(u, newUser *User, repo *Repository) (err error) {
|
||||||
if err = NotifyWatchers(&Action{ActUserId: u.Id, ActUserName: u.Name, ActEmail: u.Email,
|
action := &Action{
|
||||||
OpType: TRANSFER_REPO, RepoId: repo.Id, RepoName: repo.Name, Content: newUser.Name,
|
ActUserId: u.Id,
|
||||||
IsPrivate: repo.IsPrivate}); err != nil {
|
ActUserName: u.Name,
|
||||||
|
ActEmail: u.Email,
|
||||||
|
OpType: TRANSFER_REPO,
|
||||||
|
RepoId: repo.Id,
|
||||||
|
RepoUserName: newUser.Name,
|
||||||
|
RepoName: repo.Name,
|
||||||
|
IsPrivate: repo.IsPrivate,
|
||||||
|
Content: path.Join(repo.Owner.LowerName, repo.LowerName),
|
||||||
|
}
|
||||||
|
if err = NotifyWatchers(action); err != nil {
|
||||||
log.Error(4, "NotifyWatchers: %d/%s", u.Id, repo.Name)
|
log.Error(4, "NotifyWatchers: %d/%s", u.Id, repo.Name)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove watch for organization.
|
||||||
|
if repo.Owner.IsOrganization() {
|
||||||
|
if err = WatchRepo(repo.Owner.Id, repo.Id, false); err != nil {
|
||||||
|
log.Error(4, "WatchRepo", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.Trace("action.TransferRepoAction: %s/%s", u.Name, repo.Name)
|
log.Trace("action.TransferRepoAction: %s/%s", u.Name, repo.Name)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -309,7 +382,7 @@ func GetFeeds(uid, offset int64, isProfile bool) ([]*Action, error) {
|
||||||
actions := make([]*Action, 0, 20)
|
actions := make([]*Action, 0, 20)
|
||||||
sess := x.Limit(20, int(offset)).Desc("id").Where("user_id=?", uid)
|
sess := x.Limit(20, int(offset)).Desc("id").Where("user_id=?", uid)
|
||||||
if isProfile {
|
if isProfile {
|
||||||
sess.Where("is_private=?", false).And("act_user_id=?", uid)
|
sess.And("is_private=?", false).And("act_user_id=?", uid)
|
||||||
}
|
}
|
||||||
err := sess.Find(&actions)
|
err := sess.Find(&actions)
|
||||||
return actions, err
|
return actions, err
|
||||||
|
|
|
@ -15,8 +15,7 @@ import (
|
||||||
|
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
|
|
||||||
"github.com/gogits/git"
|
"github.com/gogits/gogs/modules/git"
|
||||||
|
|
||||||
"github.com/gogits/gogs/modules/log"
|
"github.com/gogits/gogs/modules/log"
|
||||||
"github.com/gogits/gogs/modules/process"
|
"github.com/gogits/gogs/modules/process"
|
||||||
)
|
)
|
||||||
|
@ -71,7 +70,7 @@ func (diff *Diff) NumFiles() int {
|
||||||
|
|
||||||
const DIFF_HEAD = "diff --git "
|
const DIFF_HEAD = "diff --git "
|
||||||
|
|
||||||
func ParsePatch(pid int64, cmd *exec.Cmd, reader io.Reader) (*Diff, error) {
|
func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff, error) {
|
||||||
scanner := bufio.NewScanner(reader)
|
scanner := bufio.NewScanner(reader)
|
||||||
var (
|
var (
|
||||||
curFile *DiffFile
|
curFile *DiffFile
|
||||||
|
@ -80,6 +79,7 @@ func ParsePatch(pid int64, cmd *exec.Cmd, reader io.Reader) (*Diff, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
leftLine, rightLine int
|
leftLine, rightLine int
|
||||||
|
isTooLong bool
|
||||||
)
|
)
|
||||||
|
|
||||||
diff := &Diff{Files: make([]*DiffFile, 0)}
|
diff := &Diff{Files: make([]*DiffFile, 0)}
|
||||||
|
@ -91,18 +91,19 @@ func ParsePatch(pid int64, cmd *exec.Cmd, reader io.Reader) (*Diff, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
i = i + 1
|
|
||||||
|
|
||||||
// Diff data too large.
|
|
||||||
if i == 5000 {
|
|
||||||
log.Warn("Diff data too large")
|
|
||||||
return &Diff{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if line == "" {
|
if line == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
|
// Diff data too large, we only show the first about maxlines lines
|
||||||
|
if i == maxlines {
|
||||||
|
isTooLong = true
|
||||||
|
log.Warn("Diff data too large")
|
||||||
|
//return &Diff{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case line[0] == ' ':
|
case line[0] == ' ':
|
||||||
diffLine := &DiffLine{Type: DIFF_LINE_PLAIN, Content: line, LeftIdx: leftLine, RightIdx: rightLine}
|
diffLine := &DiffLine{Type: DIFF_LINE_PLAIN, Content: line, LeftIdx: leftLine, RightIdx: rightLine}
|
||||||
|
@ -111,6 +112,10 @@ func ParsePatch(pid int64, cmd *exec.Cmd, reader io.Reader) (*Diff, error) {
|
||||||
curSection.Lines = append(curSection.Lines, diffLine)
|
curSection.Lines = append(curSection.Lines, diffLine)
|
||||||
continue
|
continue
|
||||||
case line[0] == '@':
|
case line[0] == '@':
|
||||||
|
if isTooLong {
|
||||||
|
return diff, nil
|
||||||
|
}
|
||||||
|
|
||||||
curSection = &DiffSection{}
|
curSection = &DiffSection{}
|
||||||
curFile.Sections = append(curFile.Sections, curSection)
|
curFile.Sections = append(curFile.Sections, curSection)
|
||||||
ss := strings.Split(line, "@@")
|
ss := strings.Split(line, "@@")
|
||||||
|
@ -144,6 +149,10 @@ func ParsePatch(pid int64, cmd *exec.Cmd, reader io.Reader) (*Diff, error) {
|
||||||
|
|
||||||
// Get new file.
|
// Get new file.
|
||||||
if strings.HasPrefix(line, DIFF_HEAD) {
|
if strings.HasPrefix(line, DIFF_HEAD) {
|
||||||
|
if isTooLong {
|
||||||
|
return diff, nil
|
||||||
|
}
|
||||||
|
|
||||||
fs := strings.Split(line[len(DIFF_HEAD):], " ")
|
fs := strings.Split(line[len(DIFF_HEAD):], " ")
|
||||||
a := fs[0]
|
a := fs[0]
|
||||||
|
|
||||||
|
@ -175,25 +184,30 @@ func ParsePatch(pid int64, cmd *exec.Cmd, reader io.Reader) (*Diff, error) {
|
||||||
return diff, nil
|
return diff, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDiff(repoPath, commitid string) (*Diff, error) {
|
func GetDiffRange(repoPath, beforeCommitId string, afterCommitId string, maxlines int) (*Diff, error) {
|
||||||
repo, err := git.OpenRepository(repoPath)
|
repo, err := git.OpenRepository(repoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
commit, err := repo.GetCommit(commitid)
|
commit, err := repo.GetCommit(afterCommitId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rd, wr := io.Pipe()
|
rd, wr := io.Pipe()
|
||||||
var cmd *exec.Cmd
|
var cmd *exec.Cmd
|
||||||
|
// if "after" commit given
|
||||||
|
if beforeCommitId == "" {
|
||||||
// First commit of repository.
|
// First commit of repository.
|
||||||
if commit.ParentCount() == 0 {
|
if commit.ParentCount() == 0 {
|
||||||
cmd = exec.Command("git", "show", commitid)
|
cmd = exec.Command("git", "show", afterCommitId)
|
||||||
} else {
|
} else {
|
||||||
c, _ := commit.Parent(0)
|
c, _ := commit.Parent(0)
|
||||||
cmd = exec.Command("git", "diff", c.Id.String(), commitid)
|
cmd = exec.Command("git", "diff", c.Id.String(), afterCommitId)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("git", "diff", beforeCommitId, afterCommitId)
|
||||||
}
|
}
|
||||||
cmd.Dir = repoPath
|
cmd.Dir = repoPath
|
||||||
cmd.Stdout = wr
|
cmd.Stdout = wr
|
||||||
|
@ -208,7 +222,7 @@ func GetDiff(repoPath, commitid string) (*Diff, error) {
|
||||||
}()
|
}()
|
||||||
defer rd.Close()
|
defer rd.Close()
|
||||||
|
|
||||||
desc := fmt.Sprintf("GetDiff(%s)", repoPath)
|
desc := fmt.Sprintf("GetDiffRange(%s)", repoPath)
|
||||||
pid := process.Add(desc, cmd)
|
pid := process.Add(desc, cmd)
|
||||||
go func() {
|
go func() {
|
||||||
// In case process became zombie.
|
// In case process became zombie.
|
||||||
|
@ -224,5 +238,9 @@ func GetDiff(repoPath, commitid string) (*Diff, error) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return ParsePatch(pid, cmd, rd)
|
return ParsePatch(pid, maxlines, cmd, rd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDiffCommit(repoPath, commitId string, maxlines int) (*Diff, error) {
|
||||||
|
return GetDiffRange(repoPath, "", commitId, maxlines)
|
||||||
}
|
}
|
||||||
|
|
|
@ -612,7 +612,7 @@ type Milestone struct {
|
||||||
RepoId int64 `xorm:"INDEX"`
|
RepoId int64 `xorm:"INDEX"`
|
||||||
Index int64
|
Index int64
|
||||||
Name string
|
Name string
|
||||||
Content string
|
Content string `xorm:"TEXT"`
|
||||||
RenderedContent string `xorm:"-"`
|
RenderedContent string `xorm:"-"`
|
||||||
IsClosed bool
|
IsClosed bool
|
||||||
NumIssues int
|
NumIssues int
|
||||||
|
|
|
@ -161,12 +161,8 @@ func UserSignIn(uname, passwd string) (*User, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if u.LoginType == NOTYPE {
|
if u.LoginType == NOTYPE && has {
|
||||||
if has {
|
|
||||||
u.LoginType = PLAIN
|
u.LoginType = PLAIN
|
||||||
} else {
|
|
||||||
return nil, ErrUserNotExist
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For plain login, user must exist to reach this line.
|
// For plain login, user must exist to reach this line.
|
||||||
|
|
|
@ -55,11 +55,12 @@ func LoadModelsConfig() {
|
||||||
DbCfg.Path = setting.Cfg.MustValue("database", "PATH", "data/gogs.db")
|
DbCfg.Path = setting.Cfg.MustValue("database", "PATH", "data/gogs.db")
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTestEngine(x *xorm.Engine) (err error) {
|
func getEngine() (*xorm.Engine, error) {
|
||||||
|
cnnstr := ""
|
||||||
switch DbCfg.Type {
|
switch DbCfg.Type {
|
||||||
case "mysql":
|
case "mysql":
|
||||||
x, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",
|
cnnstr = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",
|
||||||
DbCfg.User, DbCfg.Pwd, DbCfg.Host, DbCfg.Name))
|
DbCfg.User, DbCfg.Pwd, DbCfg.Host, DbCfg.Name)
|
||||||
case "postgres":
|
case "postgres":
|
||||||
var host, port = "127.0.0.1", "5432"
|
var host, port = "127.0.0.1", "5432"
|
||||||
fields := strings.Split(DbCfg.Host, ":")
|
fields := strings.Split(DbCfg.Host, ":")
|
||||||
|
@ -69,48 +70,33 @@ func NewTestEngine(x *xorm.Engine) (err error) {
|
||||||
if len(fields) > 1 && len(strings.TrimSpace(fields[1])) > 0 {
|
if len(fields) > 1 && len(strings.TrimSpace(fields[1])) > 0 {
|
||||||
port = fields[1]
|
port = fields[1]
|
||||||
}
|
}
|
||||||
cnnstr := fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s",
|
cnnstr = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s",
|
||||||
DbCfg.User, DbCfg.Pwd, host, port, DbCfg.Name, DbCfg.SslMode)
|
DbCfg.User, DbCfg.Pwd, host, port, DbCfg.Name, DbCfg.SslMode)
|
||||||
x, err = xorm.NewEngine("postgres", cnnstr)
|
|
||||||
case "sqlite3":
|
case "sqlite3":
|
||||||
if !EnableSQLite3 {
|
if !EnableSQLite3 {
|
||||||
return fmt.Errorf("Unknown database type: %s", DbCfg.Type)
|
return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
|
||||||
}
|
}
|
||||||
os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm)
|
os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm)
|
||||||
x, err = xorm.NewEngine("sqlite3", DbCfg.Path)
|
cnnstr = "file:" + DbCfg.Path + "?cache=shared&mode=rwc"
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Unknown database type: %s", DbCfg.Type)
|
return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
|
||||||
}
|
}
|
||||||
|
return xorm.NewEngine(DbCfg.Type, cnnstr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTestEngine(x *xorm.Engine) (err error) {
|
||||||
|
x, err = getEngine()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("models.init(fail to conntect database): %v", err)
|
return fmt.Errorf("models.init(fail to connect to database): %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return x.Sync(tables...)
|
return x.Sync(tables...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetEngine() (err error) {
|
func SetEngine() (err error) {
|
||||||
switch DbCfg.Type {
|
x, err = getEngine()
|
||||||
case "mysql":
|
|
||||||
x, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",
|
|
||||||
DbCfg.User, DbCfg.Pwd, DbCfg.Host, DbCfg.Name))
|
|
||||||
case "postgres":
|
|
||||||
var host, port = "127.0.0.1", "5432"
|
|
||||||
fields := strings.Split(DbCfg.Host, ":")
|
|
||||||
if len(fields) > 0 && len(strings.TrimSpace(fields[0])) > 0 {
|
|
||||||
host = fields[0]
|
|
||||||
}
|
|
||||||
if len(fields) > 1 && len(strings.TrimSpace(fields[1])) > 0 {
|
|
||||||
port = fields[1]
|
|
||||||
}
|
|
||||||
x, err = xorm.NewEngine("postgres", fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s",
|
|
||||||
DbCfg.User, DbCfg.Pwd, host, port, DbCfg.Name, DbCfg.SslMode))
|
|
||||||
case "sqlite3":
|
|
||||||
os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm)
|
|
||||||
x, err = xorm.NewEngine("sqlite3", DbCfg.Path)
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("Unknown database type: %s", DbCfg.Type)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("models.init(fail to conntect database): %v", err)
|
return fmt.Errorf("models.init(fail to connect to database): %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WARNNING: for serv command, MUST remove the output to os.stdout,
|
// WARNNING: for serv command, MUST remove the output to os.stdout,
|
||||||
|
@ -125,6 +111,7 @@ func SetEngine() (err error) {
|
||||||
x.Logger = xorm.NewSimpleLogger(f)
|
x.Logger = xorm.NewSimpleLogger(f)
|
||||||
|
|
||||||
x.ShowSQL = true
|
x.ShowSQL = true
|
||||||
|
x.ShowInfo = true
|
||||||
x.ShowDebug = true
|
x.ShowDebug = true
|
||||||
x.ShowErr = true
|
x.ShowErr = true
|
||||||
x.ShowWarn = true
|
x.ShowWarn = true
|
||||||
|
|
|
@ -507,7 +507,7 @@ func (t *Team) AddRepository(repo *Repository) (err error) {
|
||||||
mode := AuthorizeToAccessType(t.Authorize)
|
mode := AuthorizeToAccessType(t.Authorize)
|
||||||
|
|
||||||
for _, u := range t.Members {
|
for _, u := range t.Members {
|
||||||
auth, err := GetHighestAuthorize(t.OrgId, u.Id, t.Id, repo.Id)
|
auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, t.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
|
@ -517,13 +517,7 @@ func (t *Team) AddRepository(repo *Repository) (err error) {
|
||||||
UserName: u.LowerName,
|
UserName: u.LowerName,
|
||||||
RepoName: path.Join(repo.Owner.LowerName, repo.LowerName),
|
RepoName: path.Join(repo.Owner.LowerName, repo.LowerName),
|
||||||
}
|
}
|
||||||
if auth == 0 {
|
if auth < t.Authorize {
|
||||||
access.Mode = mode
|
|
||||||
if _, err = sess.Insert(access); err != nil {
|
|
||||||
sess.Rollback()
|
|
||||||
return fmt.Errorf("fail to insert access: %v", err)
|
|
||||||
}
|
|
||||||
} else if auth < t.Authorize {
|
|
||||||
if err = addAccessWithAuthorize(sess, access, mode); err != nil {
|
if err = addAccessWithAuthorize(sess, access, mode); err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
|
@ -570,7 +564,7 @@ func (t *Team) RemoveRepository(repoId int64) error {
|
||||||
|
|
||||||
// Remove access to team members.
|
// Remove access to team members.
|
||||||
for _, u := range t.Members {
|
for _, u := range t.Members {
|
||||||
auth, err := GetHighestAuthorize(t.OrgId, u.Id, t.Id, repo.Id)
|
auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, t.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
|
@ -668,7 +662,7 @@ func GetTeamById(teamId int64) (*Team, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHighestAuthorize returns highest repository authorize level for given user and team.
|
// GetHighestAuthorize returns highest repository authorize level for given user and team.
|
||||||
func GetHighestAuthorize(orgId, uid, teamId, repoId int64) (AuthorizeType, error) {
|
func GetHighestAuthorize(orgId, uid, repoId, teamId int64) (AuthorizeType, error) {
|
||||||
ts, err := GetUserTeams(orgId, uid)
|
ts, err := GetUserTeams(orgId, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
@ -687,6 +681,7 @@ func GetHighestAuthorize(orgId, uid, teamId, repoId int64) (AuthorizeType, error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return auth, nil
|
return auth, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -728,7 +723,7 @@ func UpdateTeam(t *Team, authChanged bool) (err error) {
|
||||||
// ORG_WRITABLE is the highest authorize level for now.
|
// ORG_WRITABLE is the highest authorize level for now.
|
||||||
// Skip checking others if current team has this level.
|
// Skip checking others if current team has this level.
|
||||||
if t.Authorize < ORG_WRITABLE {
|
if t.Authorize < ORG_WRITABLE {
|
||||||
auth, err := GetHighestAuthorize(org.Id, u.Id, t.Id, repo.Id)
|
auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, t.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
|
@ -782,7 +777,7 @@ func DeleteTeam(t *Team) error {
|
||||||
// Delete all accesses.
|
// Delete all accesses.
|
||||||
for _, repo := range t.Repos {
|
for _, repo := range t.Repos {
|
||||||
for _, u := range t.Members {
|
for _, u := range t.Members {
|
||||||
auth, err := GetHighestAuthorize(org.Id, u.Id, t.Id, repo.Id)
|
auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, t.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
|
@ -943,7 +938,7 @@ func AddTeamMember(orgId, teamId, uid int64) error {
|
||||||
// Give access to team repositories.
|
// Give access to team repositories.
|
||||||
mode := AuthorizeToAccessType(t.Authorize)
|
mode := AuthorizeToAccessType(t.Authorize)
|
||||||
for _, repo := range t.Repos {
|
for _, repo := range t.Repos {
|
||||||
auth, err := GetHighestAuthorize(orgId, uid, teamId, repo.Id)
|
auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, teamId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
|
@ -953,14 +948,7 @@ func AddTeamMember(orgId, teamId, uid int64) error {
|
||||||
UserName: u.LowerName,
|
UserName: u.LowerName,
|
||||||
RepoName: path.Join(org.LowerName, repo.LowerName),
|
RepoName: path.Join(org.LowerName, repo.LowerName),
|
||||||
}
|
}
|
||||||
// Equal 0 means given access doesn't exist.
|
if auth < t.Authorize {
|
||||||
if auth == 0 {
|
|
||||||
access.Mode = mode
|
|
||||||
if _, err = sess.Insert(access); err != nil {
|
|
||||||
sess.Rollback()
|
|
||||||
return fmt.Errorf("fail to insert access: %v", err)
|
|
||||||
}
|
|
||||||
} else if auth < t.Authorize {
|
|
||||||
if err = addAccessWithAuthorize(sess, access, mode); err != nil {
|
if err = addAccessWithAuthorize(sess, access, mode); err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
|
@ -1037,7 +1025,7 @@ func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) erro
|
||||||
|
|
||||||
// Delete access to team repositories.
|
// Delete access to team repositories.
|
||||||
for _, repo := range t.Repos {
|
for _, repo := range t.Repos {
|
||||||
auth, err := GetHighestAuthorize(orgId, uid, teamId, repo.Id)
|
auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, teamId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
|
|
||||||
"github.com/gogits/gogs/modules/log"
|
"github.com/gogits/gogs/modules/log"
|
||||||
"github.com/gogits/gogs/modules/process"
|
"github.com/gogits/gogs/modules/process"
|
||||||
|
"github.com/gogits/gogs/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -100,6 +101,7 @@ var (
|
||||||
"(MCE)": 1702,
|
"(MCE)": 1702,
|
||||||
"(McE)": 1702,
|
"(McE)": 1702,
|
||||||
"(RSA)": 2048,
|
"(RSA)": 2048,
|
||||||
|
"(DSA)": 1024,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -119,23 +121,30 @@ func CheckPublicKeyString(content string) (bool, error) {
|
||||||
tmpFile.WriteString(content)
|
tmpFile.WriteString(content)
|
||||||
tmpFile.Close()
|
tmpFile.Close()
|
||||||
|
|
||||||
// … see if ssh-keygen recognizes its contents
|
// Check if ssh-keygen recognizes its contents.
|
||||||
stdout, stderr, err := process.Exec("CheckPublicKeyString", "ssh-keygen", "-l", "-f", tmpPath)
|
stdout, stderr, err := process.Exec("CheckPublicKeyString", "ssh-keygen", "-l", "-f", tmpPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, errors.New("ssh-keygen -l -f: " + stderr)
|
return false, errors.New("ssh-keygen -l -f: " + stderr)
|
||||||
} else if len(stdout) < 2 {
|
} else if len(stdout) < 2 {
|
||||||
return false, errors.New("ssh-keygen returned not enough output to evaluate the key")
|
return false, errors.New("ssh-keygen returned not enough output to evaluate the key")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The ssh-keygen in Windows does not print key type, so no need go further.
|
||||||
|
if setting.IsWindows {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
sshKeygenOutput := strings.Split(stdout, " ")
|
sshKeygenOutput := strings.Split(stdout, " ")
|
||||||
if len(sshKeygenOutput) < 4 {
|
if len(sshKeygenOutput) < 4 {
|
||||||
return false, errors.New("Not enough fields returned by ssh-keygen -l -f")
|
return false, errors.New("Not enough fields returned by ssh-keygen -l -f")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if key type and key size match.
|
||||||
keySize, err := com.StrTo(sshKeygenOutput[0]).Int()
|
keySize, err := com.StrTo(sshKeygenOutput[0]).Int()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, errors.New("Cannot get key size of the given key")
|
return false, errors.New("Cannot get key size of the given key")
|
||||||
}
|
}
|
||||||
keyType := strings.TrimSpace(sshKeygenOutput[len(sshKeygenOutput)-1])
|
keyType := strings.TrimSpace(sshKeygenOutput[len(sshKeygenOutput)-1])
|
||||||
|
|
||||||
if minimumKeySize := MinimumKeySize[keyType]; minimumKeySize == 0 {
|
if minimumKeySize := MinimumKeySize[keyType]; minimumKeySize == 0 {
|
||||||
return false, errors.New("Sorry, unrecognized public key type")
|
return false, errors.New("Sorry, unrecognized public key type")
|
||||||
} else if keySize < minimumKeySize {
|
} else if keySize < minimumKeySize {
|
||||||
|
@ -160,12 +169,16 @@ func saveAuthorizedKeyFile(key *PublicKey) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: following command does not support in Windows.
|
||||||
|
if !setting.IsWindows {
|
||||||
if finfo.Mode().Perm() > 0600 {
|
if finfo.Mode().Perm() > 0600 {
|
||||||
log.Error(4, "authorized_keys file has unusual permission flags: %s - setting to -rw-------", finfo.Mode().Perm().String())
|
log.Error(4, "authorized_keys file has unusual permission flags: %s - setting to -rw-------", finfo.Mode().Perm().String())
|
||||||
if err = f.Chmod(0600); err != nil {
|
if err = f.Chmod(0600); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_, err = f.WriteString(key.GetAuthorizedString())
|
_, err = f.WriteString(key.GetAuthorizedString())
|
||||||
return err
|
return err
|
||||||
|
|
159
models/repo.go
159
models/repo.go
|
@ -95,24 +95,35 @@ func NewRepoContext() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(4, "Fail to get Git version: %v", err)
|
log.Fatal(4, "Fail to get Git version: %v", err)
|
||||||
}
|
}
|
||||||
if ver.Major < 2 && ver.Minor < 8 {
|
|
||||||
log.Fatal(4, "Gogs requires Git version greater or equal to 1.8.0")
|
reqVer, err := git.ParseVersion("1.7.1")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(4, "Fail to parse required Git version: %v", err)
|
||||||
|
}
|
||||||
|
if ver.LessThan(reqVer) {
|
||||||
|
log.Fatal(4, "Gogs requires Git version greater or equal to 1.7.1")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if server has basic git setting.
|
// Check if server has basic git setting and set if not.
|
||||||
stdout, stderr, err := process.Exec("NewRepoContext(get setting)", "git", "config", "--get", "user.name")
|
if stdout, stderr, err := process.Exec("NewRepoContext(get setting)", "git", "config", "--get", "user.name"); err != nil || strings.TrimSpace(stdout) == "" {
|
||||||
if err != nil {
|
// ExitError indicates user.name is not set
|
||||||
log.Fatal(4, "Fail to get git user.name: %s", stderr)
|
if _, ok := err.(*exec.ExitError); ok || strings.TrimSpace(stdout) == "" {
|
||||||
} else if err != nil || len(strings.TrimSpace(stdout)) == 0 {
|
stndrdUserName := "Gogs"
|
||||||
if _, stderr, err = process.Exec("NewRepoContext(set email)", "git", "config", "--global", "user.email", "gogitservice@gmail.com"); err != nil {
|
stndrdUserEmail := "gogitservice@gmail.com"
|
||||||
log.Fatal(4, "Fail to set git user.email: %s", stderr)
|
if _, stderr, gerr := process.Exec("NewRepoContext(set name)", "git", "config", "--global", "user.name", stndrdUserName); gerr != nil {
|
||||||
} else if _, stderr, err = process.Exec("NewRepoContext(set name)", "git", "config", "--global", "user.name", "Gogs"); err != nil {
|
log.Fatal(4, "Fail to set git user.name(%s): %s", gerr, stderr)
|
||||||
log.Fatal(4, "Fail to set git user.name: %s", stderr)
|
}
|
||||||
|
if _, stderr, gerr := process.Exec("NewRepoContext(set email)", "git", "config", "--global", "user.email", stndrdUserEmail); gerr != nil {
|
||||||
|
log.Fatal(4, "Fail to set git user.email(%s): %s", gerr, stderr)
|
||||||
|
}
|
||||||
|
log.Info("Git user.name and user.email set to %s <%s>", stndrdUserName, stndrdUserEmail)
|
||||||
|
} else {
|
||||||
|
log.Fatal(4, "Fail to get git user.name(%s): %s", err, stderr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set git some configurations.
|
// Set git some configurations.
|
||||||
if _, stderr, err = process.Exec("NewRepoContext(git config --global core.quotepath false)",
|
if _, stderr, err := process.Exec("NewRepoContext(git config --global core.quotepath false)",
|
||||||
"git", "config", "--global", "core.quotepath", "false"); err != nil {
|
"git", "config", "--global", "core.quotepath", "false"); err != nil {
|
||||||
log.Fatal(4, "Fail to execute 'git config --global core.quotepath false': %s", stderr)
|
log.Fatal(4, "Fail to execute 'git config --global core.quotepath false': %s", stderr)
|
||||||
}
|
}
|
||||||
|
@ -305,30 +316,17 @@ func MigrateRepository(u *User, name, desc string, private, mirror bool, url str
|
||||||
}
|
}
|
||||||
repo.IsMirror = true
|
repo.IsMirror = true
|
||||||
return repo, UpdateRepository(repo)
|
return repo, UpdateRepository(repo)
|
||||||
|
} else {
|
||||||
|
os.RemoveAll(repoPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone from local repository.
|
// this command could for both migrate and mirror
|
||||||
_, stderr, err := process.ExecTimeout(10*time.Minute,
|
_, stderr, err := process.ExecTimeout(10*time.Minute,
|
||||||
fmt.Sprintf("MigrateRepository(git clone): %s", repoPath),
|
fmt.Sprintf("MigrateRepository: %s", repoPath),
|
||||||
"git", "clone", repoPath, tmpDir)
|
"git", "clone", "--mirror", "--bare", url, repoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return repo, errors.New("git clone: " + stderr)
|
return repo, errors.New("git clone: " + stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add remote and fetch data.
|
|
||||||
if _, stderr, err = process.ExecDir(3*time.Minute,
|
|
||||||
tmpDir, fmt.Sprintf("MigrateRepository(git pull): %s", repoPath),
|
|
||||||
"git", "remote", "add", "-f", "--tags", "upstream", url); err != nil {
|
|
||||||
return repo, errors.New("git remote: " + stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push data to local repository.
|
|
||||||
if _, stderr, err = process.ExecDir(3*time.Minute,
|
|
||||||
tmpDir, fmt.Sprintf("MigrateRepository(git push): %s", repoPath),
|
|
||||||
"git", "push", "--tags", "origin", "refs/remotes/upstream/*:refs/heads/*"); err != nil {
|
|
||||||
return repo, errors.New("git push: " + stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return repo, UpdateRepository(repo)
|
return repo, UpdateRepository(repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,29 +649,54 @@ func RepoPath(userName, repoName string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransferOwnership transfers all corresponding setting from old user to new one.
|
// TransferOwnership transfers all corresponding setting from old user to new one.
|
||||||
func TransferOwnership(u *User, newOwner string, repo *Repository) (err error) {
|
func TransferOwnership(u *User, newOwner string, repo *Repository) error {
|
||||||
newUser, err := GetUserByName(newOwner)
|
newUser, err := GetUserByName(newOwner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if new owner has repository with same name.
|
||||||
|
has, err := IsRepositoryExist(newUser, repo.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if has {
|
||||||
|
return ErrRepoAlreadyExist
|
||||||
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
defer sess.Close()
|
defer sess.Close()
|
||||||
if err = sess.Begin(); err != nil {
|
if err = sess.Begin(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = sess.Where("repo_name = ?", u.LowerName+"/"+repo.LowerName).
|
owner := repo.Owner
|
||||||
And("user_name = ?", u.LowerName).Update(&Access{UserName: newUser.LowerName}); err != nil {
|
oldRepoLink := path.Join(owner.LowerName, repo.LowerName)
|
||||||
|
// Delete all access first if current owner is an organization.
|
||||||
|
if owner.IsOrganization() {
|
||||||
|
if _, err = sess.Where("repo_name=?", oldRepoLink).Delete(new(Access)); err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return fmt.Errorf("fail to delete current accesses: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Delete current owner access.
|
||||||
|
if _, err = sess.Where("repo_name=?", oldRepoLink).And("user_name=?", owner.LowerName).
|
||||||
|
Delete(new(Access)); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return fmt.Errorf("fail to delete access(owner): %v", err)
|
||||||
|
}
|
||||||
|
// In case new owner has access.
|
||||||
|
if _, err = sess.Where("repo_name=?", oldRepoLink).And("user_name=?", newUser.LowerName).
|
||||||
|
Delete(new(Access)); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return fmt.Errorf("fail to delete access(new user): %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = sess.Where("repo_name = ?", u.LowerName+"/"+repo.LowerName).Update(&Access{
|
// Change accesses to new repository path.
|
||||||
RepoName: newUser.LowerName + "/" + repo.LowerName,
|
if _, err = sess.Where("repo_name=?", oldRepoLink).
|
||||||
}); err != nil {
|
Update(&Access{RepoName: path.Join(newUser.LowerName, repo.LowerName)}); err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return fmt.Errorf("fail to update access(change reponame): %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update repository.
|
// Update repository.
|
||||||
|
@ -689,17 +712,17 @@ func TransferOwnership(u *User, newOwner string, repo *Repository) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos - 1 WHERE id = ?", u.Id); err != nil {
|
if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos - 1 WHERE id = ?", owner.Id); err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// New owner is organization.
|
|
||||||
if newUser.IsOrganization() {
|
|
||||||
mode := WRITABLE
|
mode := WRITABLE
|
||||||
if repo.IsMirror {
|
if repo.IsMirror {
|
||||||
mode = READABLE
|
mode = READABLE
|
||||||
}
|
}
|
||||||
|
// New owner is organization.
|
||||||
|
if newUser.IsOrganization() {
|
||||||
access := &Access{
|
access := &Access{
|
||||||
RepoName: path.Join(newUser.LowerName, repo.LowerName),
|
RepoName: path.Join(newUser.LowerName, repo.LowerName),
|
||||||
Mode: mode,
|
Mode: mode,
|
||||||
|
@ -724,12 +747,6 @@ func TransferOwnership(u *User, newOwner string, repo *Repository) (err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = sess.Exec(
|
|
||||||
"UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil {
|
|
||||||
sess.Rollback()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update owner team info and count.
|
// Update owner team info and count.
|
||||||
t.RepoIds += "$" + com.ToStr(repo.Id) + "|"
|
t.RepoIds += "$" + com.ToStr(repo.Id) + "|"
|
||||||
t.NumRepos++
|
t.NumRepos++
|
||||||
|
@ -737,10 +754,20 @@ func TransferOwnership(u *User, newOwner string, repo *Repository) (err error) {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
access := &Access{
|
||||||
|
RepoName: path.Join(newUser.LowerName, repo.LowerName),
|
||||||
|
UserName: newUser.LowerName,
|
||||||
|
Mode: mode,
|
||||||
|
}
|
||||||
|
if _, err = sess.Insert(access); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return fmt.Errorf("fail to insert access: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change repository directory name.
|
// Change repository directory name.
|
||||||
if err = os.Rename(RepoPath(u.Name, repo.Name), RepoPath(newUser.Name, repo.Name)); err != nil {
|
if err = os.Rename(RepoPath(owner.Name, repo.Name), RepoPath(newUser.Name, repo.Name)); err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -749,15 +776,9 @@ func TransferOwnership(u *User, newOwner string, repo *Repository) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add watch of new owner to repository.
|
|
||||||
if !newUser.IsOrganization() {
|
|
||||||
if err = WatchRepo(newUser.Id, repo.Id, true); err != nil {
|
if err = WatchRepo(newUser.Id, repo.Id, true); err != nil {
|
||||||
log.Error(4, "WatchRepo", err)
|
log.Error(4, "WatchRepo", err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if err = WatchRepo(u.Id, repo.Id, false); err != nil {
|
|
||||||
log.Error(4, "WatchRepo2", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = TransferRepoAction(u, newUser, repo); err != nil {
|
if err = TransferRepoAction(u, newUser, repo); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -940,9 +961,9 @@ func GetRepositoryByRef(ref string) (*Repository, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRepositoryByName returns the repository by given name under user if exists.
|
// GetRepositoryByName returns the repository by given name under user if exists.
|
||||||
func GetRepositoryByName(userId int64, repoName string) (*Repository, error) {
|
func GetRepositoryByName(uid int64, repoName string) (*Repository, error) {
|
||||||
repo := &Repository{
|
repo := &Repository{
|
||||||
OwnerId: userId,
|
OwnerId: uid,
|
||||||
LowerName: strings.ToLower(repoName),
|
LowerName: strings.ToLower(repoName),
|
||||||
}
|
}
|
||||||
has, err := x.Get(repo)
|
has, err := x.Get(repo)
|
||||||
|
@ -979,8 +1000,8 @@ func GetRepositories(uid int64, private bool) ([]*Repository, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRecentUpdatedRepositories returns the list of repositories that are recently updated.
|
// GetRecentUpdatedRepositories returns the list of repositories that are recently updated.
|
||||||
func GetRecentUpdatedRepositories() (repos []*Repository, err error) {
|
func GetRecentUpdatedRepositories(num int) (repos []*Repository, err error) {
|
||||||
err = x.Where("is_private=?", false).Limit(5).Desc("updated").Find(&repos)
|
err = x.Where("is_private=?", false).Limit(num).Desc("updated").Find(&repos)
|
||||||
return repos, err
|
return repos, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1081,6 +1102,13 @@ func SearchRepositoryByName(opt SearchOption) (repos []*Repository, err error) {
|
||||||
return repos, err
|
return repos, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// __ __ __ .__
|
||||||
|
// / \ / \_____ _/ |_ ____ | |__
|
||||||
|
// \ \/\/ /\__ \\ __\/ ___\| | \
|
||||||
|
// \ / / __ \| | \ \___| Y \
|
||||||
|
// \__/\ / (____ /__| \___ >___| /
|
||||||
|
// \/ \/ \/ \/
|
||||||
|
|
||||||
// Watch is connection request for receiving repository notifycation.
|
// Watch is connection request for receiving repository notifycation.
|
||||||
type Watch struct {
|
type Watch struct {
|
||||||
Id int64
|
Id int64
|
||||||
|
@ -1151,6 +1179,13 @@ func NotifyWatchers(act *Action) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// _________ __
|
||||||
|
// / _____// |______ _______
|
||||||
|
// \_____ \\ __\__ \\_ __ \
|
||||||
|
// / \| | / __ \| | \/
|
||||||
|
// /_______ /|__| (____ /__|
|
||||||
|
// \/ \/
|
||||||
|
|
||||||
type Star struct {
|
type Star struct {
|
||||||
Id int64
|
Id int64
|
||||||
Uid int64 `xorm:"UNIQUE(s)"`
|
Uid int64 `xorm:"UNIQUE(s)"`
|
||||||
|
@ -1165,16 +1200,20 @@ func StarRepo(uid, repoId int64, star bool) (err error) {
|
||||||
}
|
}
|
||||||
if _, err = x.Insert(&Star{Uid: uid, RepoId: repoId}); err != nil {
|
if _, err = x.Insert(&Star{Uid: uid, RepoId: repoId}); err != nil {
|
||||||
return err
|
return err
|
||||||
|
} else if _, err = x.Exec("UPDATE `repository` SET num_stars = num_stars + 1 WHERE id = ?", repoId); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
_, err = x.Exec("UPDATE `repository` SET num_stars = num_stars + 1 WHERE id = ?", repoId)
|
_, err = x.Exec("UPDATE `user` SET num_stars = num_stars + 1 WHERE id = ?", uid)
|
||||||
} else {
|
} else {
|
||||||
if !IsStaring(uid, repoId) {
|
if !IsStaring(uid, repoId) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if _, err = x.Delete(&Star{0, uid, repoId}); err != nil {
|
if _, err = x.Delete(&Star{0, uid, repoId}); err != nil {
|
||||||
return err
|
return err
|
||||||
|
} else if _, err = x.Exec("UPDATE `repository` SET num_stars = num_stars - 1 WHERE id = ?", repoId); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
_, err = x.Exec("UPDATE `repository` SET num_stars = num_stars - 1 WHERE id = ?", repoId)
|
_, err = x.Exec("UPDATE `user` SET num_stars = num_stars - 1 WHERE id = ?", uid)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
125
models/slack.go
Normal file
125
models/slack.go
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SLACK_COLOR string = "#dd4b39"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Slack struct {
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
Channel string `json:"channel"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SlackPayload struct {
|
||||||
|
Channel string `json:"channel"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
IconUrl string `json:"icon_url"`
|
||||||
|
UnfurlLinks int `json:"unfurl_links"`
|
||||||
|
LinkNames int `json:"link_names"`
|
||||||
|
Attachments []SlackAttachment `json:"attachments"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SlackAttachment struct {
|
||||||
|
Color string `json:"color"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSlackURL(domain string, token string) string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"https://%s.slack.com/services/hooks/incoming-webhook?token=%s",
|
||||||
|
domain,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p SlackPayload) GetJSONPayload() ([]byte, error) {
|
||||||
|
data, err := json.Marshal(p)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSlackPayload(p *Payload, meta string) (*SlackPayload, error) {
|
||||||
|
slack := &Slack{}
|
||||||
|
slackPayload := &SlackPayload{}
|
||||||
|
if err := json.Unmarshal([]byte(meta), &slack); err != nil {
|
||||||
|
return slackPayload, errors.New("GetSlackPayload meta json:" + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle different payload types: push, new branch, delete branch etc.
|
||||||
|
// when they are added to gogs. Only handles push now
|
||||||
|
return getSlackPushPayload(p, slack)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSlackPushPayload(p *Payload, slack *Slack) (*SlackPayload, error) {
|
||||||
|
// n new commits
|
||||||
|
refSplit := strings.Split(p.Ref, "/")
|
||||||
|
branchName := refSplit[len(refSplit)-1]
|
||||||
|
var commitString string
|
||||||
|
|
||||||
|
if len(p.Commits) == 1 {
|
||||||
|
commitString = "1 new commit"
|
||||||
|
if p.CompareUrl != "" {
|
||||||
|
commitString = SlackLinkFormatter(p.CompareUrl, commitString)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
commitString = fmt.Sprintf("%d new commits", len(p.Commits))
|
||||||
|
if p.CompareUrl != "" {
|
||||||
|
commitString = SlackLinkFormatter(p.CompareUrl, commitString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repoLink := SlackLinkFormatter(p.Repo.Url, p.Repo.Name)
|
||||||
|
branchLink := SlackLinkFormatter(p.Repo.Url+"/src/"+branchName, branchName)
|
||||||
|
text := fmt.Sprintf("[%s:%s] %s pushed by %s", repoLink, branchLink, commitString, p.Pusher.Name)
|
||||||
|
var attachmentText string
|
||||||
|
|
||||||
|
// for each commit, generate attachment text
|
||||||
|
for i, commit := range p.Commits {
|
||||||
|
attachmentText += fmt.Sprintf("%s: %s - %s", SlackLinkFormatter(commit.Url, commit.Id[:7]), SlackTextFormatter(commit.Message), SlackTextFormatter(commit.Author.Name))
|
||||||
|
// add linebreak to each commit but the last
|
||||||
|
if i < len(p.Commits)-1 {
|
||||||
|
attachmentText += "\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slackAttachments := []SlackAttachment{{Color: SLACK_COLOR, Text: attachmentText}}
|
||||||
|
|
||||||
|
return &SlackPayload{
|
||||||
|
Channel: slack.Channel,
|
||||||
|
Text: text,
|
||||||
|
Username: "gogs",
|
||||||
|
IconUrl: "https://raw.githubusercontent.com/gogits/gogs/master/public/img/favicon.png",
|
||||||
|
UnfurlLinks: 0,
|
||||||
|
LinkNames: 0,
|
||||||
|
Attachments: slackAttachments,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// see: https://api.slack.com/docs/formatting
|
||||||
|
func SlackTextFormatter(s string) string {
|
||||||
|
// take only first line of commit
|
||||||
|
first := strings.Split(s, "\n")[0]
|
||||||
|
// replace & < >
|
||||||
|
first = strings.Replace(first, "&", "&", -1)
|
||||||
|
first = strings.Replace(first, "<", "<", -1)
|
||||||
|
first = strings.Replace(first, ">", ">", -1)
|
||||||
|
return first
|
||||||
|
}
|
||||||
|
|
||||||
|
func SlackLinkFormatter(url string, text string) string {
|
||||||
|
return fmt.Sprintf("<%s|%s>", url, SlackTextFormatter(text))
|
||||||
|
}
|
|
@ -23,6 +23,10 @@ type UpdateTask struct {
|
||||||
NewCommitId string
|
NewCommitId string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
MAX_COMMITS int = 5
|
||||||
|
)
|
||||||
|
|
||||||
func AddUpdateTask(task *UpdateTask) error {
|
func AddUpdateTask(task *UpdateTask) error {
|
||||||
_, err := x.Insert(task)
|
_, err := x.Insert(task)
|
||||||
return err
|
return err
|
||||||
|
@ -101,7 +105,7 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
|
||||||
commit := &base.PushCommits{}
|
commit := &base.PushCommits{}
|
||||||
|
|
||||||
if err = CommitRepoAction(userId, ru.Id, userName, actEmail,
|
if err = CommitRepoAction(userId, ru.Id, userName, actEmail,
|
||||||
repos.Id, repoUserName, repoName, refName, commit); err != nil {
|
repos.Id, repoUserName, repoName, refName, commit, oldCommitId, newCommitId); err != nil {
|
||||||
log.GitLogger.Fatal(4, "runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
|
log.GitLogger.Fatal(4, "runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
@ -132,7 +136,6 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
|
||||||
|
|
||||||
// if commits push
|
// if commits push
|
||||||
commits := make([]*base.PushCommit, 0)
|
commits := make([]*base.PushCommit, 0)
|
||||||
var maxCommits = 2
|
|
||||||
var actEmail string
|
var actEmail string
|
||||||
for e := l.Front(); e != nil; e = e.Next() {
|
for e := l.Front(); e != nil; e = e.Next() {
|
||||||
commit := e.Value.(*git.Commit)
|
commit := e.Value.(*git.Commit)
|
||||||
|
@ -145,14 +148,14 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
|
||||||
commit.Message(),
|
commit.Message(),
|
||||||
commit.Author.Email,
|
commit.Author.Email,
|
||||||
commit.Author.Name})
|
commit.Author.Name})
|
||||||
if len(commits) >= maxCommits {
|
if len(commits) >= MAX_COMMITS {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//commits = append(commits, []string{lastCommit.Id().String(), lastCommit.Message()})
|
//commits = append(commits, []string{lastCommit.Id().String(), lastCommit.Message()})
|
||||||
if err = CommitRepoAction(userId, ru.Id, userName, actEmail,
|
if err = CommitRepoAction(userId, ru.Id, userName, actEmail,
|
||||||
repos.Id, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits}); err != nil {
|
repos.Id, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits}, oldCommitId, newCommitId); err != nil {
|
||||||
return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
|
return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"container/list"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -82,22 +83,22 @@ type User struct {
|
||||||
// DashboardLink returns the user dashboard page link.
|
// DashboardLink returns the user dashboard page link.
|
||||||
func (u *User) DashboardLink() string {
|
func (u *User) DashboardLink() string {
|
||||||
if u.IsOrganization() {
|
if u.IsOrganization() {
|
||||||
return "/org/" + u.Name + "/dashboard/"
|
return setting.AppSubUrl + "/org/" + u.Name + "/dashboard/"
|
||||||
}
|
}
|
||||||
return "/"
|
return setting.AppSubUrl + "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
// HomeLink returns the user home page link.
|
// HomeLink returns the user home page link.
|
||||||
func (u *User) HomeLink() string {
|
func (u *User) HomeLink() string {
|
||||||
return "/user/" + u.Name
|
return setting.AppSubUrl + "/" + u.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// AvatarLink returns user gravatar link.
|
// AvatarLink returns user gravatar link.
|
||||||
func (u *User) AvatarLink() string {
|
func (u *User) AvatarLink() string {
|
||||||
if setting.DisableGravatar {
|
if setting.DisableGravatar {
|
||||||
return "/img/avatar_default.jpg"
|
return setting.AppSubUrl + "/img/avatar_default.jpg"
|
||||||
} else if setting.Service.EnableCacheAvatar {
|
} else if setting.Service.EnableCacheAvatar {
|
||||||
return "/avatar/" + u.Avatar
|
return setting.AppSubUrl + "/avatar/" + u.Avatar
|
||||||
}
|
}
|
||||||
return "//1.gravatar.com/avatar/" + u.Avatar
|
return "//1.gravatar.com/avatar/" + u.Avatar
|
||||||
}
|
}
|
||||||
|
@ -167,6 +168,14 @@ func (u *User) GetOrganizations() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFullNameFallback returns Full Name if set, otherwise username
|
||||||
|
func (u *User) GetFullNameFallback() string {
|
||||||
|
if u.FullName == "" {
|
||||||
|
return u.Name
|
||||||
|
}
|
||||||
|
return u.FullName
|
||||||
|
}
|
||||||
|
|
||||||
// IsUserExist checks if given user name exist,
|
// IsUserExist checks if given user name exist,
|
||||||
// the user name should be noncased unique.
|
// the user name should be noncased unique.
|
||||||
func IsUserExist(name string) (bool, error) {
|
func IsUserExist(name string) (bool, error) {
|
||||||
|
@ -505,6 +514,49 @@ func GetUserIdsByNames(names []string) []int64 {
|
||||||
return ids
|
return ids
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserCommit represtns a commit with validation of user.
|
||||||
|
type UserCommit struct {
|
||||||
|
UserName string
|
||||||
|
*git.Commit
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateCommitWithEmail chceck if author's e-mail of commit is corresponsind to a user.
|
||||||
|
func ValidateCommitWithEmail(c *git.Commit) (uname string) {
|
||||||
|
u, err := GetUserByEmail(c.Author.Email)
|
||||||
|
if err == nil {
|
||||||
|
uname = u.Name
|
||||||
|
}
|
||||||
|
return uname
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateCommitsWithEmails checks if authors' e-mails of commits are corresponding to users.
|
||||||
|
func ValidateCommitsWithEmails(oldCommits *list.List) *list.List {
|
||||||
|
emails := map[string]string{}
|
||||||
|
newCommits := list.New()
|
||||||
|
e := oldCommits.Front()
|
||||||
|
for e != nil {
|
||||||
|
c := e.Value.(*git.Commit)
|
||||||
|
|
||||||
|
uname := ""
|
||||||
|
if v, ok := emails[c.Author.Email]; !ok {
|
||||||
|
u, err := GetUserByEmail(c.Author.Email)
|
||||||
|
if err == nil {
|
||||||
|
uname = u.Name
|
||||||
|
}
|
||||||
|
emails[c.Author.Email] = uname
|
||||||
|
} else {
|
||||||
|
uname = v
|
||||||
|
}
|
||||||
|
|
||||||
|
newCommits.PushBack(UserCommit{
|
||||||
|
UserName: uname,
|
||||||
|
Commit: c,
|
||||||
|
})
|
||||||
|
e = e.Next()
|
||||||
|
}
|
||||||
|
return newCommits
|
||||||
|
}
|
||||||
|
|
||||||
// GetUserByEmail returns the user object by given e-mail if exists.
|
// GetUserByEmail returns the user object by given e-mail if exists.
|
||||||
func GetUserByEmail(email string) (*User, error) {
|
func GetUserByEmail(email string) (*User, error) {
|
||||||
if len(email) == 0 {
|
if len(email) == 0 {
|
||||||
|
@ -548,27 +600,27 @@ type Follow struct {
|
||||||
|
|
||||||
// FollowUser marks someone be another's follower.
|
// FollowUser marks someone be another's follower.
|
||||||
func FollowUser(userId int64, followId int64) (err error) {
|
func FollowUser(userId int64, followId int64) (err error) {
|
||||||
session := x.NewSession()
|
sess := x.NewSession()
|
||||||
defer session.Close()
|
defer sess.Close()
|
||||||
session.Begin()
|
sess.Begin()
|
||||||
|
|
||||||
if _, err = session.Insert(&Follow{UserId: userId, FollowId: followId}); err != nil {
|
if _, err = sess.Insert(&Follow{UserId: userId, FollowId: followId}); err != nil {
|
||||||
session.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rawSql := "UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?"
|
rawSql := "UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?"
|
||||||
if _, err = session.Exec(rawSql, followId); err != nil {
|
if _, err = sess.Exec(rawSql, followId); err != nil {
|
||||||
session.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rawSql = "UPDATE `user` SET num_followings = num_followings + 1 WHERE id = ?"
|
rawSql = "UPDATE `user` SET num_followings = num_followings + 1 WHERE id = ?"
|
||||||
if _, err = session.Exec(rawSql, userId); err != nil {
|
if _, err = sess.Exec(rawSql, userId); err != nil {
|
||||||
session.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return session.Commit()
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnFollowUser unmarks someone be another's follower.
|
// UnFollowUser unmarks someone be another's follower.
|
||||||
|
|
|
@ -7,6 +7,7 @@ package models
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gogits/gogs/modules/httplib"
|
"github.com/gogits/gogs/modules/httplib"
|
||||||
|
@ -42,6 +43,9 @@ type Webhook struct {
|
||||||
*HookEvent `xorm:"-"`
|
*HookEvent `xorm:"-"`
|
||||||
IsSsl bool
|
IsSsl bool
|
||||||
IsActive bool
|
IsActive bool
|
||||||
|
HookTaskType HookTaskType
|
||||||
|
Meta string `xorm:"TEXT"` // store hook-specific attributes
|
||||||
|
OrgId int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEvent handles conversion from Events to HookEvent.
|
// GetEvent handles conversion from Events to HookEvent.
|
||||||
|
@ -52,6 +56,14 @@ func (w *Webhook) GetEvent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Webhook) GetSlackHook() *Slack {
|
||||||
|
s := &Slack{}
|
||||||
|
if err := json.Unmarshal([]byte(w.Meta), s); err != nil {
|
||||||
|
log.Error(4, "webhook.GetSlackHook(%d): %v", w.Id, err)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateEvent handles conversion from HookEvent to Events.
|
// UpdateEvent handles conversion from HookEvent to Events.
|
||||||
func (w *Webhook) UpdateEvent() error {
|
func (w *Webhook) UpdateEvent() error {
|
||||||
data, err := json.Marshal(w.HookEvent)
|
data, err := json.Marshal(w.HookEvent)
|
||||||
|
@ -87,7 +99,7 @@ func GetWebhookById(hookId int64) (*Webhook, error) {
|
||||||
|
|
||||||
// GetActiveWebhooksByRepoId returns all active webhooks of repository.
|
// GetActiveWebhooksByRepoId returns all active webhooks of repository.
|
||||||
func GetActiveWebhooksByRepoId(repoId int64) (ws []*Webhook, err error) {
|
func GetActiveWebhooksByRepoId(repoId int64) (ws []*Webhook, err error) {
|
||||||
err = x.Find(&ws, &Webhook{RepoId: repoId, IsActive: true})
|
err = x.Where("repo_id=?", repoId).And("is_active=?", true).Find(&ws)
|
||||||
return ws, err
|
return ws, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +121,18 @@ func DeleteWebhook(hookId int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetWebhooksByOrgId returns all webhooks for an organization.
|
||||||
|
func GetWebhooksByOrgId(orgId int64) (ws []*Webhook, err error) {
|
||||||
|
err = x.Find(&ws, &Webhook{OrgId: orgId})
|
||||||
|
return ws, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetActiveWebhooksByOrgId returns all active webhooks for an organization.
|
||||||
|
func GetActiveWebhooksByOrgId(orgId int64) (ws []*Webhook, err error) {
|
||||||
|
err = x.Where("org_id=?", orgId).And("is_active=?", true).Find(&ws)
|
||||||
|
return ws, err
|
||||||
|
}
|
||||||
|
|
||||||
// ___ ___ __ ___________ __
|
// ___ ___ __ ___________ __
|
||||||
// / | \ ____ ____ | | _\__ ___/____ _____| | __
|
// / | \ ____ ____ | | _\__ ___/____ _____| | __
|
||||||
// / ~ \/ _ \ / _ \| |/ / | | \__ \ / ___/ |/ /
|
// / ~ \/ _ \ / _ \| |/ / | | \__ \ / ___/ |/ /
|
||||||
|
@ -119,8 +143,8 @@ func DeleteWebhook(hookId int64) error {
|
||||||
type HookTaskType int
|
type HookTaskType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
WEBHOOK HookTaskType = iota + 1
|
GOGS HookTaskType = iota + 1
|
||||||
SERVICE
|
SLACK
|
||||||
)
|
)
|
||||||
|
|
||||||
type HookEventType string
|
type HookEventType string
|
||||||
|
@ -132,6 +156,7 @@ const (
|
||||||
type PayloadAuthor struct {
|
type PayloadAuthor struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
|
UserName string `json:"username"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PayloadCommit struct {
|
type PayloadCommit struct {
|
||||||
|
@ -148,10 +173,14 @@ type PayloadRepo struct {
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Website string `json:"website"`
|
Website string `json:"website"`
|
||||||
Watchers int `json:"watchers"`
|
Watchers int `json:"watchers"`
|
||||||
Owner *PayloadAuthor `json:"author"`
|
Owner *PayloadAuthor `json:"owner"`
|
||||||
Private bool `json:"private"`
|
Private bool `json:"private"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BasePayload interface {
|
||||||
|
GetJSONPayload() ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
// Payload represents a payload information of hook.
|
// Payload represents a payload information of hook.
|
||||||
type Payload struct {
|
type Payload struct {
|
||||||
Secret string `json:"secret"`
|
Secret string `json:"secret"`
|
||||||
|
@ -159,6 +188,17 @@ type Payload struct {
|
||||||
Commits []*PayloadCommit `json:"commits"`
|
Commits []*PayloadCommit `json:"commits"`
|
||||||
Repo *PayloadRepo `json:"repository"`
|
Repo *PayloadRepo `json:"repository"`
|
||||||
Pusher *PayloadAuthor `json:"pusher"`
|
Pusher *PayloadAuthor `json:"pusher"`
|
||||||
|
Before string `json:"before"`
|
||||||
|
After string `json:"after"`
|
||||||
|
CompareUrl string `json:"compare_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Payload) GetJSONPayload() ([]byte, error) {
|
||||||
|
data, err := json.Marshal(p)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HookTask represents a hook task.
|
// HookTask represents a hook task.
|
||||||
|
@ -167,19 +207,19 @@ type HookTask struct {
|
||||||
Uuid string
|
Uuid string
|
||||||
Type HookTaskType
|
Type HookTaskType
|
||||||
Url string
|
Url string
|
||||||
*Payload `xorm:"-"`
|
BasePayload `xorm:"-"`
|
||||||
PayloadContent string `xorm:"TEXT"`
|
PayloadContent string `xorm:"TEXT"`
|
||||||
ContentType HookContentType
|
ContentType HookContentType
|
||||||
EventType HookEventType
|
EventType HookEventType
|
||||||
IsSsl bool
|
IsSsl bool
|
||||||
IsDeliveried bool
|
IsDelivered bool
|
||||||
IsSucceed bool
|
IsSucceed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateHookTask creates a new hook task,
|
// CreateHookTask creates a new hook task,
|
||||||
// it handles conversion from Payload to PayloadContent.
|
// it handles conversion from Payload to PayloadContent.
|
||||||
func CreateHookTask(t *HookTask) error {
|
func CreateHookTask(t *HookTask) error {
|
||||||
data, err := json.Marshal(t.Payload)
|
data, err := t.BasePayload.GetJSONPayload()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -191,14 +231,15 @@ func CreateHookTask(t *HookTask) error {
|
||||||
|
|
||||||
// UpdateHookTask updates information of hook task.
|
// UpdateHookTask updates information of hook task.
|
||||||
func UpdateHookTask(t *HookTask) error {
|
func UpdateHookTask(t *HookTask) error {
|
||||||
_, err := x.AllCols().Update(t)
|
_, err := x.Id(t.Id).AllCols().Update(t)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeliverHooks checks and delivers undelivered hooks.
|
// DeliverHooks checks and delivers undelivered hooks.
|
||||||
func DeliverHooks() {
|
func DeliverHooks() {
|
||||||
|
tasks := make([]*HookTask, 0, 10)
|
||||||
timeout := time.Duration(setting.WebhookDeliverTimeout) * time.Second
|
timeout := time.Duration(setting.WebhookDeliverTimeout) * time.Second
|
||||||
x.Where("is_deliveried=?", false).Iterate(new(HookTask),
|
x.Where("is_delivered=?", false).Iterate(new(HookTask),
|
||||||
func(idx int, bean interface{}) error {
|
func(idx int, bean interface{}) error {
|
||||||
t := bean.(*HookTask)
|
t := bean.(*HookTask)
|
||||||
req := httplib.Post(t.Url).SetTimeout(timeout, timeout).
|
req := httplib.Post(t.Url).SetTimeout(timeout, timeout).
|
||||||
|
@ -212,21 +253,50 @@ func DeliverHooks() {
|
||||||
req.Param("payload", t.PayloadContent)
|
req.Param("payload", t.PayloadContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.IsDeliveried = true
|
t.IsDelivered = true
|
||||||
|
|
||||||
// TODO: record response.
|
// TODO: record response.
|
||||||
|
switch t.Type {
|
||||||
|
case GOGS:
|
||||||
|
{
|
||||||
if _, err := req.Response(); err != nil {
|
if _, err := req.Response(); err != nil {
|
||||||
log.Error(4, "Delivery: %v", err)
|
log.Error(4, "Delivery: %v", err)
|
||||||
} else {
|
} else {
|
||||||
t.IsSucceed = true
|
t.IsSucceed = true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if err := UpdateHookTask(t); err != nil {
|
case SLACK:
|
||||||
log.Error(4, "UpdateHookTask: %v", err)
|
{
|
||||||
return nil
|
if res, err := req.Response(); err != nil {
|
||||||
|
log.Error(4, "Delivery: %v", err)
|
||||||
|
} else {
|
||||||
|
defer res.Body.Close()
|
||||||
|
contents, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(4, "%s", err)
|
||||||
|
} else {
|
||||||
|
if string(contents) != "ok" {
|
||||||
|
log.Error(4, "slack failed with: %s", string(contents))
|
||||||
|
} else {
|
||||||
|
t.IsSucceed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks = append(tasks, t)
|
||||||
|
|
||||||
|
if t.IsSucceed {
|
||||||
log.Trace("Hook delivered(%s): %s", t.Uuid, t.PayloadContent)
|
log.Trace("Hook delivered(%s): %s", t.Uuid, t.PayloadContent)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Update hook task status.
|
||||||
|
for _, t := range tasks {
|
||||||
|
if err := UpdateHookTask(t); err != nil {
|
||||||
|
log.Error(4, "UpdateHookTask(%d): %v", t.Id, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
27
modules/asn1-ber/LICENSE
Normal file
27
modules/asn1-ber/LICENSE
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
11
modules/asn1-ber/Makefile
Normal file
11
modules/asn1-ber/Makefile
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
include $(GOROOT)/src/Make.inc
|
||||||
|
|
||||||
|
TARG=github.com/mmitton/asn1-ber
|
||||||
|
GOFILES=\
|
||||||
|
ber.go\
|
||||||
|
|
||||||
|
include $(GOROOT)/src/Make.pkg
|
14
modules/asn1-ber/README
Normal file
14
modules/asn1-ber/README
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
ASN1 BER Encoding / Decoding Library for the GO programming language.
|
||||||
|
|
||||||
|
Required Librarys:
|
||||||
|
None
|
||||||
|
|
||||||
|
Working:
|
||||||
|
Very basic encoding / decoding needed for LDAP protocol
|
||||||
|
|
||||||
|
Tests Implemented:
|
||||||
|
None
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
Fix all encoding / decoding to conform to ASN1 BER spec
|
||||||
|
Implement Tests / Benchmarks
|
492
modules/asn1-ber/ber.go
Normal file
492
modules/asn1-ber/ber.go
Normal file
|
@ -0,0 +1,492 @@
|
||||||
|
package ber
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Packet struct {
|
||||||
|
ClassType uint8
|
||||||
|
TagType uint8
|
||||||
|
Tag uint8
|
||||||
|
Value interface{}
|
||||||
|
ByteValue []byte
|
||||||
|
Data *bytes.Buffer
|
||||||
|
Children []*Packet
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
TagEOC = 0x00
|
||||||
|
TagBoolean = 0x01
|
||||||
|
TagInteger = 0x02
|
||||||
|
TagBitString = 0x03
|
||||||
|
TagOctetString = 0x04
|
||||||
|
TagNULL = 0x05
|
||||||
|
TagObjectIdentifier = 0x06
|
||||||
|
TagObjectDescriptor = 0x07
|
||||||
|
TagExternal = 0x08
|
||||||
|
TagRealFloat = 0x09
|
||||||
|
TagEnumerated = 0x0a
|
||||||
|
TagEmbeddedPDV = 0x0b
|
||||||
|
TagUTF8String = 0x0c
|
||||||
|
TagRelativeOID = 0x0d
|
||||||
|
TagSequence = 0x10
|
||||||
|
TagSet = 0x11
|
||||||
|
TagNumericString = 0x12
|
||||||
|
TagPrintableString = 0x13
|
||||||
|
TagT61String = 0x14
|
||||||
|
TagVideotexString = 0x15
|
||||||
|
TagIA5String = 0x16
|
||||||
|
TagUTCTime = 0x17
|
||||||
|
TagGeneralizedTime = 0x18
|
||||||
|
TagGraphicString = 0x19
|
||||||
|
TagVisibleString = 0x1a
|
||||||
|
TagGeneralString = 0x1b
|
||||||
|
TagUniversalString = 0x1c
|
||||||
|
TagCharacterString = 0x1d
|
||||||
|
TagBMPString = 0x1e
|
||||||
|
TagBitmask = 0x1f // xxx11111b
|
||||||
|
)
|
||||||
|
|
||||||
|
var TagMap = map[uint8]string{
|
||||||
|
TagEOC: "EOC (End-of-Content)",
|
||||||
|
TagBoolean: "Boolean",
|
||||||
|
TagInteger: "Integer",
|
||||||
|
TagBitString: "Bit String",
|
||||||
|
TagOctetString: "Octet String",
|
||||||
|
TagNULL: "NULL",
|
||||||
|
TagObjectIdentifier: "Object Identifier",
|
||||||
|
TagObjectDescriptor: "Object Descriptor",
|
||||||
|
TagExternal: "External",
|
||||||
|
TagRealFloat: "Real (float)",
|
||||||
|
TagEnumerated: "Enumerated",
|
||||||
|
TagEmbeddedPDV: "Embedded PDV",
|
||||||
|
TagUTF8String: "UTF8 String",
|
||||||
|
TagRelativeOID: "Relative-OID",
|
||||||
|
TagSequence: "Sequence and Sequence of",
|
||||||
|
TagSet: "Set and Set OF",
|
||||||
|
TagNumericString: "Numeric String",
|
||||||
|
TagPrintableString: "Printable String",
|
||||||
|
TagT61String: "T61 String",
|
||||||
|
TagVideotexString: "Videotex String",
|
||||||
|
TagIA5String: "IA5 String",
|
||||||
|
TagUTCTime: "UTC Time",
|
||||||
|
TagGeneralizedTime: "Generalized Time",
|
||||||
|
TagGraphicString: "Graphic String",
|
||||||
|
TagVisibleString: "Visible String",
|
||||||
|
TagGeneralString: "General String",
|
||||||
|
TagUniversalString: "Universal String",
|
||||||
|
TagCharacterString: "Character String",
|
||||||
|
TagBMPString: "BMP String",
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
ClassUniversal = 0 // 00xxxxxxb
|
||||||
|
ClassApplication = 64 // 01xxxxxxb
|
||||||
|
ClassContext = 128 // 10xxxxxxb
|
||||||
|
ClassPrivate = 192 // 11xxxxxxb
|
||||||
|
ClassBitmask = 192 // 11xxxxxxb
|
||||||
|
)
|
||||||
|
|
||||||
|
var ClassMap = map[uint8]string{
|
||||||
|
ClassUniversal: "Universal",
|
||||||
|
ClassApplication: "Application",
|
||||||
|
ClassContext: "Context",
|
||||||
|
ClassPrivate: "Private",
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypePrimitive = 0 // xx0xxxxxb
|
||||||
|
TypeConstructed = 32 // xx1xxxxxb
|
||||||
|
TypeBitmask = 32 // xx1xxxxxb
|
||||||
|
)
|
||||||
|
|
||||||
|
var TypeMap = map[uint8]string{
|
||||||
|
TypePrimitive: "Primative",
|
||||||
|
TypeConstructed: "Constructed",
|
||||||
|
}
|
||||||
|
|
||||||
|
var Debug bool = false
|
||||||
|
|
||||||
|
func PrintBytes(buf []byte, indent string) {
|
||||||
|
data_lines := make([]string, (len(buf)/30)+1)
|
||||||
|
num_lines := make([]string, (len(buf)/30)+1)
|
||||||
|
|
||||||
|
for i, b := range buf {
|
||||||
|
data_lines[i/30] += fmt.Sprintf("%02x ", b)
|
||||||
|
num_lines[i/30] += fmt.Sprintf("%02d ", (i+1)%100)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(data_lines); i++ {
|
||||||
|
fmt.Print(indent + data_lines[i] + "\n")
|
||||||
|
fmt.Print(indent + num_lines[i] + "\n\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintPacket(p *Packet) {
|
||||||
|
printPacket(p, 0, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printPacket(p *Packet, indent int, printBytes bool) {
|
||||||
|
indent_str := ""
|
||||||
|
|
||||||
|
for len(indent_str) != indent {
|
||||||
|
indent_str += " "
|
||||||
|
}
|
||||||
|
|
||||||
|
class_str := ClassMap[p.ClassType]
|
||||||
|
|
||||||
|
tagtype_str := TypeMap[p.TagType]
|
||||||
|
|
||||||
|
tag_str := fmt.Sprintf("0x%02X", p.Tag)
|
||||||
|
|
||||||
|
if p.ClassType == ClassUniversal {
|
||||||
|
tag_str = TagMap[p.Tag]
|
||||||
|
}
|
||||||
|
|
||||||
|
value := fmt.Sprint(p.Value)
|
||||||
|
description := ""
|
||||||
|
|
||||||
|
if p.Description != "" {
|
||||||
|
description = p.Description + ": "
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s%s(%s, %s, %s) Len=%d %q\n", indent_str, description, class_str, tagtype_str, tag_str, p.Data.Len(), value)
|
||||||
|
|
||||||
|
if printBytes {
|
||||||
|
PrintBytes(p.Bytes(), indent_str)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, child := range p.Children {
|
||||||
|
printPacket(child, indent+1, printBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resizeBuffer(in []byte, new_size uint64) (out []byte) {
|
||||||
|
out = make([]byte, new_size)
|
||||||
|
|
||||||
|
copy(out, in)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func readBytes(reader io.Reader, buf []byte) error {
|
||||||
|
idx := 0
|
||||||
|
buflen := len(buf)
|
||||||
|
|
||||||
|
for idx < buflen {
|
||||||
|
n, err := reader.Read(buf[idx:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
idx += n
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadPacket(reader io.Reader) (*Packet, error) {
|
||||||
|
buf := make([]byte, 2)
|
||||||
|
|
||||||
|
err := readBytes(reader, buf)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
idx := uint64(2)
|
||||||
|
datalen := uint64(buf[1])
|
||||||
|
|
||||||
|
if Debug {
|
||||||
|
fmt.Printf("Read: datalen = %d len(buf) = %d ", datalen, len(buf))
|
||||||
|
|
||||||
|
for _, b := range buf {
|
||||||
|
fmt.Printf("%02X ", b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if datalen&128 != 0 {
|
||||||
|
a := datalen - 128
|
||||||
|
|
||||||
|
idx += a
|
||||||
|
buf = resizeBuffer(buf, 2+a)
|
||||||
|
|
||||||
|
err := readBytes(reader, buf[2:])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
datalen = DecodeInteger(buf[2 : 2+a])
|
||||||
|
|
||||||
|
if Debug {
|
||||||
|
fmt.Printf("Read: a = %d idx = %d datalen = %d len(buf) = %d", a, idx, datalen, len(buf))
|
||||||
|
|
||||||
|
for _, b := range buf {
|
||||||
|
fmt.Printf("%02X ", b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = resizeBuffer(buf, idx+datalen)
|
||||||
|
err = readBytes(reader, buf[idx:])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if Debug {
|
||||||
|
fmt.Printf("Read: len( buf ) = %d idx=%d datalen=%d idx+datalen=%d\n", len(buf), idx, datalen, idx+datalen)
|
||||||
|
|
||||||
|
for _, b := range buf {
|
||||||
|
fmt.Printf("%02X ", b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p := DecodePacket(buf)
|
||||||
|
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeString(data []byte) (ret string) {
|
||||||
|
for _, c := range data {
|
||||||
|
ret += fmt.Sprintf("%c", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeInteger(data []byte) (ret uint64) {
|
||||||
|
for _, i := range data {
|
||||||
|
ret = ret * 256
|
||||||
|
ret = ret + uint64(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func EncodeInteger(val uint64) []byte {
|
||||||
|
var out bytes.Buffer
|
||||||
|
|
||||||
|
found := false
|
||||||
|
|
||||||
|
shift := uint(56)
|
||||||
|
|
||||||
|
mask := uint64(0xFF00000000000000)
|
||||||
|
|
||||||
|
for mask > 0 {
|
||||||
|
if !found && (val&mask != 0) {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if found || (shift == 0) {
|
||||||
|
out.Write([]byte{byte((val & mask) >> shift)})
|
||||||
|
}
|
||||||
|
|
||||||
|
shift -= 8
|
||||||
|
mask = mask >> 8
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodePacket(data []byte) *Packet {
|
||||||
|
p, _ := decodePacket(data)
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodePacket(data []byte) (*Packet, []byte) {
|
||||||
|
if Debug {
|
||||||
|
fmt.Printf("decodePacket: enter %d\n", len(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
p := new(Packet)
|
||||||
|
|
||||||
|
p.ClassType = data[0] & ClassBitmask
|
||||||
|
p.TagType = data[0] & TypeBitmask
|
||||||
|
p.Tag = data[0] & TagBitmask
|
||||||
|
|
||||||
|
datalen := DecodeInteger(data[1:2])
|
||||||
|
datapos := uint64(2)
|
||||||
|
|
||||||
|
if datalen&128 != 0 {
|
||||||
|
datalen -= 128
|
||||||
|
datapos += datalen
|
||||||
|
datalen = DecodeInteger(data[2 : 2+datalen])
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Data = new(bytes.Buffer)
|
||||||
|
|
||||||
|
p.Children = make([]*Packet, 0, 2)
|
||||||
|
|
||||||
|
p.Value = nil
|
||||||
|
|
||||||
|
value_data := data[datapos : datapos+datalen]
|
||||||
|
|
||||||
|
if p.TagType == TypeConstructed {
|
||||||
|
for len(value_data) != 0 {
|
||||||
|
var child *Packet
|
||||||
|
|
||||||
|
child, value_data = decodePacket(value_data)
|
||||||
|
p.AppendChild(child)
|
||||||
|
}
|
||||||
|
} else if p.ClassType == ClassUniversal {
|
||||||
|
p.Data.Write(data[datapos : datapos+datalen])
|
||||||
|
p.ByteValue = value_data
|
||||||
|
|
||||||
|
switch p.Tag {
|
||||||
|
case TagEOC:
|
||||||
|
case TagBoolean:
|
||||||
|
val := DecodeInteger(value_data)
|
||||||
|
|
||||||
|
p.Value = val != 0
|
||||||
|
case TagInteger:
|
||||||
|
p.Value = DecodeInteger(value_data)
|
||||||
|
case TagBitString:
|
||||||
|
case TagOctetString:
|
||||||
|
p.Value = DecodeString(value_data)
|
||||||
|
case TagNULL:
|
||||||
|
case TagObjectIdentifier:
|
||||||
|
case TagObjectDescriptor:
|
||||||
|
case TagExternal:
|
||||||
|
case TagRealFloat:
|
||||||
|
case TagEnumerated:
|
||||||
|
p.Value = DecodeInteger(value_data)
|
||||||
|
case TagEmbeddedPDV:
|
||||||
|
case TagUTF8String:
|
||||||
|
case TagRelativeOID:
|
||||||
|
case TagSequence:
|
||||||
|
case TagSet:
|
||||||
|
case TagNumericString:
|
||||||
|
case TagPrintableString:
|
||||||
|
p.Value = DecodeString(value_data)
|
||||||
|
case TagT61String:
|
||||||
|
case TagVideotexString:
|
||||||
|
case TagIA5String:
|
||||||
|
case TagUTCTime:
|
||||||
|
case TagGeneralizedTime:
|
||||||
|
case TagGraphicString:
|
||||||
|
case TagVisibleString:
|
||||||
|
case TagGeneralString:
|
||||||
|
case TagUniversalString:
|
||||||
|
case TagCharacterString:
|
||||||
|
case TagBMPString:
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p.Data.Write(data[datapos : datapos+datalen])
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, data[datapos+datalen:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Packet) DataLength() uint64 {
|
||||||
|
return uint64(p.Data.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Packet) Bytes() []byte {
|
||||||
|
var out bytes.Buffer
|
||||||
|
|
||||||
|
out.Write([]byte{p.ClassType | p.TagType | p.Tag})
|
||||||
|
packet_length := EncodeInteger(p.DataLength())
|
||||||
|
|
||||||
|
if p.DataLength() > 127 || len(packet_length) > 1 {
|
||||||
|
out.Write([]byte{byte(len(packet_length) | 128)})
|
||||||
|
out.Write(packet_length)
|
||||||
|
} else {
|
||||||
|
out.Write(packet_length)
|
||||||
|
}
|
||||||
|
|
||||||
|
out.Write(p.Data.Bytes())
|
||||||
|
|
||||||
|
return out.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Packet) AppendChild(child *Packet) {
|
||||||
|
p.Data.Write(child.Bytes())
|
||||||
|
|
||||||
|
if len(p.Children) == cap(p.Children) {
|
||||||
|
newChildren := make([]*Packet, cap(p.Children)*2)
|
||||||
|
|
||||||
|
copy(newChildren, p.Children)
|
||||||
|
p.Children = newChildren[0:len(p.Children)]
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Children = p.Children[0 : len(p.Children)+1]
|
||||||
|
p.Children[len(p.Children)-1] = child
|
||||||
|
}
|
||||||
|
|
||||||
|
func Encode(ClassType, TagType, Tag uint8, Value interface{}, Description string) *Packet {
|
||||||
|
p := new(Packet)
|
||||||
|
|
||||||
|
p.ClassType = ClassType
|
||||||
|
p.TagType = TagType
|
||||||
|
p.Tag = Tag
|
||||||
|
p.Data = new(bytes.Buffer)
|
||||||
|
|
||||||
|
p.Children = make([]*Packet, 0, 2)
|
||||||
|
|
||||||
|
p.Value = Value
|
||||||
|
p.Description = Description
|
||||||
|
|
||||||
|
if Value != nil {
|
||||||
|
v := reflect.ValueOf(Value)
|
||||||
|
|
||||||
|
if ClassType == ClassUniversal {
|
||||||
|
switch Tag {
|
||||||
|
case TagOctetString:
|
||||||
|
sv, ok := v.Interface().(string)
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
p.Data.Write([]byte(sv))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSequence(Description string) *Packet {
|
||||||
|
return Encode(ClassUniversal, TypePrimitive, TagSequence, nil, Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBoolean(ClassType, TagType, Tag uint8, Value bool, Description string) *Packet {
|
||||||
|
intValue := 0
|
||||||
|
|
||||||
|
if Value {
|
||||||
|
intValue = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
p := Encode(ClassType, TagType, Tag, nil, Description)
|
||||||
|
|
||||||
|
p.Value = Value
|
||||||
|
p.Data.Write(EncodeInteger(uint64(intValue)))
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInteger(ClassType, TagType, Tag uint8, Value uint64, Description string) *Packet {
|
||||||
|
p := Encode(ClassType, TagType, Tag, nil, Description)
|
||||||
|
|
||||||
|
p.Value = Value
|
||||||
|
p.Data.Write(EncodeInteger(Value))
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewString(ClassType, TagType, Tag uint8, Value, Description string) *Packet {
|
||||||
|
p := Encode(ClassType, TagType, Tag, nil, Description)
|
||||||
|
|
||||||
|
p.Value = Value
|
||||||
|
p.Data.Write([]byte(Value))
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
|
@ -9,8 +9,8 @@ package ldap
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/ldap"
|
||||||
"github.com/gogits/gogs/modules/log"
|
"github.com/gogits/gogs/modules/log"
|
||||||
goldap "github.com/juju2013/goldap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Basic LDAP authentication service
|
// Basic LDAP authentication service
|
||||||
|
@ -68,9 +68,9 @@ func (ls Ldapsource) SearchEntry(name, passwd string) (string, bool) {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
search := goldap.NewSearchRequest(
|
search := ldap.NewSearchRequest(
|
||||||
ls.BaseDN,
|
ls.BaseDN,
|
||||||
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
|
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
fmt.Sprintf(ls.Filter, name),
|
fmt.Sprintf(ls.Filter, name),
|
||||||
[]string{ls.Attributes},
|
[]string{ls.Attributes},
|
||||||
nil)
|
nil)
|
||||||
|
@ -87,10 +87,10 @@ func (ls Ldapsource) SearchEntry(name, passwd string) (string, bool) {
|
||||||
return "", true
|
return "", true
|
||||||
}
|
}
|
||||||
|
|
||||||
func ldapDial(ls Ldapsource) (*goldap.Conn, error) {
|
func ldapDial(ls Ldapsource) (*ldap.Conn, error) {
|
||||||
if ls.UseSSL {
|
if ls.UseSSL {
|
||||||
return goldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port), nil)
|
return ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port), nil)
|
||||||
} else {
|
} else {
|
||||||
return goldap.Dial("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port))
|
return ldap.Dial("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
|
|
||||||
type CreateRepoForm struct {
|
type CreateRepoForm struct {
|
||||||
Uid int64 `form:"uid" binding:"Required"`
|
Uid int64 `form:"uid" binding:"Required"`
|
||||||
RepoName string `form:"repo_name" binding:"Required;AlphaDash;MaxSize(100)"`
|
RepoName string `form:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||||
Private bool `form:"private"`
|
Private bool `form:"private"`
|
||||||
Description string `form:"desc" binding:"MaxSize(255)"`
|
Description string `form:"desc" binding:"MaxSize(255)"`
|
||||||
Gitignore string `form:"gitignore"`
|
Gitignore string `form:"gitignore"`
|
||||||
|
@ -33,11 +33,11 @@ func (f *CreateRepoForm) Validate(ctx *macaron.Context, errs *binding.Errors, l
|
||||||
}
|
}
|
||||||
|
|
||||||
type MigrateRepoForm struct {
|
type MigrateRepoForm struct {
|
||||||
HttpsUrl string `form:"url" binding:"Url"`
|
HttpsUrl string `form:"url" binding:"Required;Url"`
|
||||||
AuthUserName string `form:"auth_username"`
|
AuthUserName string `form:"auth_username"`
|
||||||
AuthPasswd string `form:"auth_password"`
|
AuthPasswd string `form:"auth_password"`
|
||||||
Uid int64 `form:"uid" binding:"Required"`
|
Uid int64 `form:"uid" binding:"Required"`
|
||||||
RepoName string `form:"repo_name" binding:"Required;AlphaDash;MaxSize(100)"`
|
RepoName string `form:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||||
Mirror bool `form:"mirror"`
|
Mirror bool `form:"mirror"`
|
||||||
Private bool `form:"private"`
|
Private bool `form:"private"`
|
||||||
Description string `form:"desc" binding:"MaxSize(255)"`
|
Description string `form:"desc" binding:"MaxSize(255)"`
|
||||||
|
@ -48,7 +48,7 @@ func (f *MigrateRepoForm) Validate(ctx *macaron.Context, errs *binding.Errors, l
|
||||||
}
|
}
|
||||||
|
|
||||||
type RepoSettingForm struct {
|
type RepoSettingForm struct {
|
||||||
RepoName string `form:"repo_name" binding:"Required;AlphaDash;MaxSize(100)"`
|
RepoName string `form:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||||
Description string `form:"desc" binding:"MaxSize(255)"`
|
Description string `form:"desc" binding:"MaxSize(255)"`
|
||||||
Website string `form:"site" binding:"Url;MaxSize(100)"`
|
Website string `form:"site" binding:"Url;MaxSize(100)"`
|
||||||
Branch string `form:"branch"`
|
Branch string `form:"branch"`
|
||||||
|
@ -69,6 +69,7 @@ func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs *binding.Errors, l
|
||||||
// \/ \/ \/ \/ \/ \/
|
// \/ \/ \/ \/ \/ \/
|
||||||
|
|
||||||
type NewWebhookForm struct {
|
type NewWebhookForm struct {
|
||||||
|
HookTaskType string `form:"hook_type" binding:"Required"`
|
||||||
PayloadUrl string `form:"payload_url" binding:"Required;Url"`
|
PayloadUrl string `form:"payload_url" binding:"Required;Url"`
|
||||||
ContentType string `form:"content_type" binding:"Required"`
|
ContentType string `form:"content_type" binding:"Required"`
|
||||||
Secret string `form:"secret"`
|
Secret string `form:"secret"`
|
||||||
|
@ -80,6 +81,19 @@ func (f *NewWebhookForm) Validate(ctx *macaron.Context, errs *binding.Errors, l
|
||||||
validate(errs, ctx.Data, f, l)
|
validate(errs, ctx.Data, f, l)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NewSlackHookForm struct {
|
||||||
|
HookTaskType string `form:"hook_type" binding:"Required"`
|
||||||
|
Domain string `form:"domain" binding:"Required`
|
||||||
|
Token string `form:"token" binding:"Required"`
|
||||||
|
Channel string `form:"channel" binding:"Required"`
|
||||||
|
PushOnly bool `form:"push_only"`
|
||||||
|
Active bool `form:"active"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *NewSlackHookForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) {
|
||||||
|
validate(errs, ctx.Data, f, l)
|
||||||
|
}
|
||||||
|
|
||||||
// .___
|
// .___
|
||||||
// | | ______ ________ __ ____
|
// | | ______ ________ __ ____
|
||||||
// | |/ ___// ___/ | \_/ __ \
|
// | |/ ___// ___/ | \_/ __ \
|
||||||
|
|
|
@ -13,24 +13,25 @@ import (
|
||||||
|
|
||||||
type InstallForm struct {
|
type InstallForm struct {
|
||||||
Database string `form:"database" binding:"Required"`
|
Database string `form:"database" binding:"Required"`
|
||||||
Host string `form:"host"`
|
DbHost string `form:"host"`
|
||||||
User string `form:"user"`
|
DbUser string `form:"user"`
|
||||||
Passwd string `form:"passwd"`
|
DbPasswd string `form:"passwd"`
|
||||||
DatabaseName string `form:"database_name"`
|
DatabaseName string `form:"database_name"`
|
||||||
SslMode string `form:"ssl_mode"`
|
SslMode string `form:"ssl_mode"`
|
||||||
DatabasePath string `form:"database_path"`
|
DatabasePath string `form:"database_path"`
|
||||||
RepoRootPath string `form:"repo_path"`
|
RepoRootPath string `form:"repo_path" binding:"Required"`
|
||||||
RunUser string `form:"run_user"`
|
RunUser string `form:"run_user" binding:"Required"`
|
||||||
Domain string `form:"domain"`
|
Domain string `form:"domain" binding:"Required"`
|
||||||
AppUrl string `form:"app_url"`
|
AppUrl string `form:"app_url" binding:"Required"`
|
||||||
AdminName string `form:"admin_name" binding:"Required;AlphaDashDot;MaxSize(30)"`
|
|
||||||
AdminPasswd string `form:"admin_pwd" binding:"Required;MinSize(6);MaxSize(255)"`
|
|
||||||
AdminEmail string `form:"admin_email" binding:"Required;Email;MaxSize(50)"`
|
|
||||||
SmtpHost string `form:"smtp_host"`
|
SmtpHost string `form:"smtp_host"`
|
||||||
SmtpEmail string `form:"mailer_user"`
|
SmtpEmail string `form:"mailer_user"`
|
||||||
SmtpPasswd string `form:"mailer_pwd"`
|
SmtpPasswd string `form:"mailer_pwd"`
|
||||||
RegisterConfirm string `form:"register_confirm"`
|
RegisterConfirm string `form:"register_confirm"`
|
||||||
MailNotify string `form:"mail_notify"`
|
MailNotify string `form:"mail_notify"`
|
||||||
|
AdminName string `form:"admin_name" binding:"Required;AlphaDashDot;MaxSize(30)"`
|
||||||
|
AdminPasswd string `form:"admin_pwd" binding:"Required;MinSize(6);MaxSize(255)"`
|
||||||
|
ConfirmPasswd string `form:"confirm_passwd" binding:"Required;MinSize(6);MaxSize(255)"`
|
||||||
|
AdminEmail string `form:"admin_email" binding:"Required;Email;MaxSize(50)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *InstallForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) {
|
func (f *InstallForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gogits/gfm"
|
"github.com/gogits/gfm"
|
||||||
|
"github.com/gogits/gogs/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
func isletter(c byte) bool {
|
func isletter(c byte) bool {
|
||||||
|
@ -112,7 +113,7 @@ func RenderSpecialLink(rawBytes []byte, urlPrefix string) []byte {
|
||||||
ms := MentionPattern.FindAll(line, -1)
|
ms := MentionPattern.FindAll(line, -1)
|
||||||
for _, m := range ms {
|
for _, m := range ms {
|
||||||
line = bytes.Replace(line, m,
|
line = bytes.Replace(line, m,
|
||||||
[]byte(fmt.Sprintf(`<a href="/user/%s">%s</a>`, m[1:], m)), -1)
|
[]byte(fmt.Sprintf(`<a href="%s/user/%s">%s</a>`, setting.AppSubUrl, m[1:], m)), -1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,16 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"container/list"
|
"container/list"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/mahonia"
|
||||||
"github.com/gogits/gogs/modules/setting"
|
"github.com/gogits/gogs/modules/setting"
|
||||||
|
"github.com/saintfish/chardet"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Str2html(raw string) template.HTML {
|
func Str2html(raw string) template.HTML {
|
||||||
|
@ -45,6 +48,29 @@ func ShortSha(sha1 string) string {
|
||||||
return sha1
|
return sha1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ToUtf8WithErr(content []byte) (error, string) {
|
||||||
|
detector := chardet.NewTextDetector()
|
||||||
|
result, err := detector.DetectBest(content)
|
||||||
|
if err != nil {
|
||||||
|
return err, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Charset == "utf8" {
|
||||||
|
return nil, string(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder := mahonia.NewDecoder(result.Charset)
|
||||||
|
if decoder != nil {
|
||||||
|
return nil, decoder.ConvertString(string(content))
|
||||||
|
}
|
||||||
|
return errors.New("unknow char decoder"), string(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToUtf8(content string) string {
|
||||||
|
_, res := ToUtf8WithErr([]byte(content))
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
var mailDomains = map[string]string{
|
var mailDomains = map[string]string{
|
||||||
"gmail.com": "gmail.com",
|
"gmail.com": "gmail.com",
|
||||||
}
|
}
|
||||||
|
@ -56,6 +82,9 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
|
||||||
"AppName": func() string {
|
"AppName": func() string {
|
||||||
return setting.AppName
|
return setting.AppName
|
||||||
},
|
},
|
||||||
|
"AppSubUrl": func() string {
|
||||||
|
return setting.AppSubUrl
|
||||||
|
},
|
||||||
"AppVer": func() string {
|
"AppVer": func() string {
|
||||||
return setting.AppVer
|
return setting.AppVer
|
||||||
},
|
},
|
||||||
|
@ -103,6 +132,7 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
|
||||||
"ActionContent2Commits": ActionContent2Commits,
|
"ActionContent2Commits": ActionContent2Commits,
|
||||||
"Oauth2Icon": Oauth2Icon,
|
"Oauth2Icon": Oauth2Icon,
|
||||||
"Oauth2Name": Oauth2Name,
|
"Oauth2Name": Oauth2Name,
|
||||||
|
"ToUtf8": ToUtf8,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Actioner interface {
|
type Actioner interface {
|
||||||
|
@ -119,14 +149,12 @@ type Actioner interface {
|
||||||
// and returns a icon class name.
|
// and returns a icon class name.
|
||||||
func ActionIcon(opType int) string {
|
func ActionIcon(opType int) string {
|
||||||
switch opType {
|
switch opType {
|
||||||
case 1: // Create repository.
|
case 1, 8: // Create, transfer repository.
|
||||||
return "repo"
|
return "repo"
|
||||||
case 5, 9: // Commit repository.
|
case 5, 9: // Commit repository.
|
||||||
return "git-commit"
|
return "git-commit"
|
||||||
case 6: // Create issue.
|
case 6: // Create issue.
|
||||||
return "issue-opened"
|
return "issue-opened"
|
||||||
case 8: // Transfer repository.
|
|
||||||
return "share"
|
|
||||||
case 10: // Comment issue.
|
case 10: // Comment issue.
|
||||||
return "comment"
|
return "comment"
|
||||||
default:
|
default:
|
||||||
|
@ -134,16 +162,16 @@ func ActionIcon(opType int) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Legacy
|
// FIXME: Legacy
|
||||||
const (
|
const (
|
||||||
TPL_CREATE_REPO = `<a href="/user/%s">%s</a> created repository <a href="/%s">%s</a>`
|
TPL_CREATE_REPO = `<a href="%s/user/%s">%s</a> created repository <a href="%s">%s</a>`
|
||||||
TPL_COMMIT_REPO = `<a href="/user/%s">%s</a> pushed to <a href="/%s/src/%s">%s</a> at <a href="/%s">%s</a>%s`
|
TPL_COMMIT_REPO = `<a href="%s/user/%s">%s</a> pushed to <a href="%s/src/%s">%s</a> at <a href="%s">%s</a>%s`
|
||||||
TPL_COMMIT_REPO_LI = `<div><img src="%s?s=16" alt="user-avatar"/> <a href="/%s/commit/%s" rel="nofollow">%s</a> %s</div>`
|
TPL_COMMIT_REPO_LI = `<div><img src="%s?s=16" alt="user-avatar"/> <a href="%s/commit/%s" rel="nofollow">%s</a> %s</div>`
|
||||||
TPL_CREATE_ISSUE = `<a href="/user/%s">%s</a> opened issue <a href="/%s/issues/%s">%s#%s</a>
|
TPL_CREATE_ISSUE = `<a href="%s/user/%s">%s</a> opened issue <a href="%s/issues/%s">%s#%s</a>
|
||||||
<div><img src="%s?s=16" alt="user-avatar"/> %s</div>`
|
<div><img src="%s?s=16" alt="user-avatar"/> %s</div>`
|
||||||
TPL_TRANSFER_REPO = `<a href="/user/%s">%s</a> transfered repository <code>%s</code> to <a href="/%s">%s</a>`
|
TPL_TRANSFER_REPO = `<a href="%s/user/%s">%s</a> transfered repository <code>%s</code> to <a href="%s">%s</a>`
|
||||||
TPL_PUSH_TAG = `<a href="/user/%s">%s</a> pushed tag <a href="/%s/src/%s" rel="nofollow">%s</a> at <a href="/%s">%s</a>`
|
TPL_PUSH_TAG = `<a href="%s/user/%s">%s</a> pushed tag <a href="%s/src/%s" rel="nofollow">%s</a> at <a href="%s">%s</a>`
|
||||||
TPL_COMMENT_ISSUE = `<a href="/user/%s">%s</a> commented on issue <a href="/%s/issues/%s">%s#%s</a>
|
TPL_COMMENT_ISSUE = `<a href="%s/user/%s">%s</a> commented on issue <a href="%s/issues/%s">%s#%s</a>
|
||||||
<div><img src="%s?s=16" alt="user-avatar"/> %s</div>`
|
<div><img src="%s?s=16" alt="user-avatar"/> %s</div>`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -167,7 +195,7 @@ func ActionContent2Commits(act Actioner) *PushCommits {
|
||||||
return push
|
return push
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Legacy
|
// FIXME: Legacy
|
||||||
// ActionDesc accepts int that represents action operation type
|
// ActionDesc accepts int that represents action operation type
|
||||||
// and returns the description.
|
// and returns the description.
|
||||||
func ActionDesc(act Actioner) string {
|
func ActionDesc(act Actioner) string {
|
||||||
|
@ -180,7 +208,7 @@ func ActionDesc(act Actioner) string {
|
||||||
content := act.GetContent()
|
content := act.GetContent()
|
||||||
switch act.GetOpType() {
|
switch act.GetOpType() {
|
||||||
case 1: // Create repository.
|
case 1: // Create repository.
|
||||||
return fmt.Sprintf(TPL_CREATE_REPO, actUserName, actUserName, repoLink, repoName)
|
return fmt.Sprintf(TPL_CREATE_REPO, setting.AppSubUrl, actUserName, actUserName, repoLink, repoName)
|
||||||
case 5: // Commit repository.
|
case 5: // Commit repository.
|
||||||
var push *PushCommits
|
var push *PushCommits
|
||||||
if err := json.Unmarshal([]byte(content), &push); err != nil {
|
if err := json.Unmarshal([]byte(content), &push); err != nil {
|
||||||
|
@ -191,22 +219,22 @@ func ActionDesc(act Actioner) string {
|
||||||
buf.WriteString(fmt.Sprintf(TPL_COMMIT_REPO_LI, AvatarLink(commit.AuthorEmail), repoLink, commit.Sha1, commit.Sha1[:7], commit.Message) + "\n")
|
buf.WriteString(fmt.Sprintf(TPL_COMMIT_REPO_LI, AvatarLink(commit.AuthorEmail), repoLink, commit.Sha1, commit.Sha1[:7], commit.Message) + "\n")
|
||||||
}
|
}
|
||||||
if push.Len > 3 {
|
if push.Len > 3 {
|
||||||
buf.WriteString(fmt.Sprintf(`<div><a href="/%s/%s/commits/%s" rel="nofollow">%d other commits >></a></div>`, actUserName, repoName, branch, push.Len))
|
buf.WriteString(fmt.Sprintf(`<div><a href="{{AppRootSubUrl}}/%s/%s/commits/%s" rel="nofollow">%d other commits >></a></div>`, actUserName, repoName, branch, push.Len))
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(TPL_COMMIT_REPO, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink,
|
return fmt.Sprintf(TPL_COMMIT_REPO, setting.AppSubUrl, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink,
|
||||||
buf.String())
|
buf.String())
|
||||||
case 6: // Create issue.
|
case 6: // Create issue.
|
||||||
infos := strings.SplitN(content, "|", 2)
|
infos := strings.SplitN(content, "|", 2)
|
||||||
return fmt.Sprintf(TPL_CREATE_ISSUE, actUserName, actUserName, repoLink, infos[0], repoLink, infos[0],
|
return fmt.Sprintf(TPL_CREATE_ISSUE, setting.AppSubUrl, actUserName, actUserName, repoLink, infos[0], repoLink, infos[0],
|
||||||
AvatarLink(email), infos[1])
|
AvatarLink(email), infos[1])
|
||||||
case 8: // Transfer repository.
|
case 8: // Transfer repository.
|
||||||
newRepoLink := content + "/" + repoName
|
newRepoLink := content + "/" + repoName
|
||||||
return fmt.Sprintf(TPL_TRANSFER_REPO, actUserName, actUserName, repoLink, newRepoLink, newRepoLink)
|
return fmt.Sprintf(TPL_TRANSFER_REPO, setting.AppSubUrl, actUserName, actUserName, repoLink, newRepoLink, newRepoLink)
|
||||||
case 9: // Push tag.
|
case 9: // Push tag.
|
||||||
return fmt.Sprintf(TPL_PUSH_TAG, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink)
|
return fmt.Sprintf(TPL_PUSH_TAG, setting.AppSubUrl, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink)
|
||||||
case 10: // Comment issue.
|
case 10: // Comment issue.
|
||||||
infos := strings.SplitN(content, "|", 2)
|
infos := strings.SplitN(content, "|", 2)
|
||||||
return fmt.Sprintf(TPL_COMMENT_ISSUE, actUserName, actUserName, repoLink, infos[0], repoLink, infos[0],
|
return fmt.Sprintf(TPL_COMMENT_ISSUE, setting.AppSubUrl, actUserName, actUserName, repoLink, infos[0], repoLink, infos[0],
|
||||||
AvatarLink(email), infos[1])
|
AvatarLink(email), infos[1])
|
||||||
default:
|
default:
|
||||||
return "invalid type"
|
return "invalid type"
|
||||||
|
|
|
@ -146,9 +146,9 @@ func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string
|
||||||
// AvatarLink returns avatar link by given e-mail.
|
// AvatarLink returns avatar link by given e-mail.
|
||||||
func AvatarLink(email string) string {
|
func AvatarLink(email string) string {
|
||||||
if setting.DisableGravatar {
|
if setting.DisableGravatar {
|
||||||
return "/img/avatar_default.jpg"
|
return setting.AppSubUrl + "/img/avatar_default.jpg"
|
||||||
} else if setting.Service.EnableCacheAvatar {
|
} else if setting.Service.EnableCacheAvatar {
|
||||||
return "/avatar/" + EncodeMd5(email)
|
return setting.AppSubUrl + "/avatar/" + EncodeMd5(email)
|
||||||
}
|
}
|
||||||
return "//1.gravatar.com/avatar/" + EncodeMd5(email)
|
return "//1.gravatar.com/avatar/" + EncodeMd5(email)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"container/list"
|
"container/list"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -18,6 +19,7 @@ type Commit struct {
|
||||||
CommitMessage string
|
CommitMessage string
|
||||||
|
|
||||||
parents []sha1 // sha1 strings
|
parents []sha1 // sha1 strings
|
||||||
|
submodules map[string]*SubModule
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the commit message. Same as retrieving CommitMessage directly.
|
// Return the commit message. Same as retrieving CommitMessage directly.
|
||||||
|
@ -84,3 +86,49 @@ func (c *Commit) CommitsByRange(page int) (*list.List, error) {
|
||||||
func (c *Commit) GetCommitOfRelPath(relPath string) (*Commit, error) {
|
func (c *Commit) GetCommitOfRelPath(relPath string) (*Commit, error) {
|
||||||
return c.repo.getCommitOfRelPath(c.Id, relPath)
|
return c.repo.getCommitOfRelPath(c.Id, relPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Commit) GetSubModule(entryname string) (*SubModule, error) {
|
||||||
|
moduels, err := c.GetSubModules()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return moduels[entryname], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Commit) GetSubModules() (map[string]*SubModule, error) {
|
||||||
|
if c.submodules != nil {
|
||||||
|
return c.submodules, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
entry, err := c.GetTreeEntryByPath(".gitmodules")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rd, err := entry.Blob().Data()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(rd)
|
||||||
|
c.submodules = make(map[string]*SubModule)
|
||||||
|
var ismodule bool
|
||||||
|
var path string
|
||||||
|
for scanner.Scan() {
|
||||||
|
if strings.HasPrefix(scanner.Text(), "[submodule") {
|
||||||
|
ismodule = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ismodule {
|
||||||
|
fields := strings.Split(scanner.Text(), "=")
|
||||||
|
k := strings.TrimSpace(fields[0])
|
||||||
|
if k == "path" {
|
||||||
|
path = strings.TrimSpace(fields[1])
|
||||||
|
} else if k == "url" {
|
||||||
|
c.submodules[path] = &SubModule{path, strings.TrimSpace(fields[1])}
|
||||||
|
ismodule = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.submodules, nil
|
||||||
|
}
|
||||||
|
|
|
@ -40,11 +40,11 @@ func (repo *Repository) GetCommitIdOfTag(tagName string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) GetCommitOfTag(tagName string) (*Commit, error) {
|
func (repo *Repository) GetCommitOfTag(tagName string) (*Commit, error) {
|
||||||
commitId, err := repo.GetCommitIdOfTag(tagName)
|
tag, err := repo.GetTag(tagName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return repo.GetCommit(commitId)
|
return tag.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse commit information from the (uncompressed) raw
|
// Parse commit information from the (uncompressed) raw
|
||||||
|
@ -137,6 +137,14 @@ func (repo *Repository) GetCommit(commitId string) (*Commit, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) commitsCount(id sha1) (int, error) {
|
func (repo *Repository) commitsCount(id sha1) (int, error) {
|
||||||
|
if gitVer.LessThan(MustParseVersion("1.8.0")) {
|
||||||
|
stdout, stderr, err := com.ExecCmdDirBytes(repo.Path, "git", "log", "--pretty=format:''", id.String())
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.New(string(stderr))
|
||||||
|
}
|
||||||
|
return len(bytes.Split(stdout, []byte("\n"))), nil
|
||||||
|
}
|
||||||
|
|
||||||
stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "rev-list", "--count", id.String())
|
stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "rev-list", "--count", id.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, errors.New(stderr)
|
return 0, errors.New(stderr)
|
||||||
|
|
|
@ -52,6 +52,7 @@ func (repo *Repository) getTag(id sha1) (*Tag, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(stderr)
|
return nil, errors.New(stderr)
|
||||||
}
|
}
|
||||||
|
tp = strings.TrimSpace(tp)
|
||||||
|
|
||||||
// Tag is a commit.
|
// Tag is a commit.
|
||||||
if ObjectType(tp) == COMMIT {
|
if ObjectType(tp) == COMMIT {
|
||||||
|
|
58
modules/git/submodule.go
Normal file
58
modules/git/submodule.go
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SubModule struct {
|
||||||
|
Name string
|
||||||
|
Url string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubModuleFile represents a file with submodule type.
|
||||||
|
type SubModuleFile struct {
|
||||||
|
*Commit
|
||||||
|
|
||||||
|
refUrl string
|
||||||
|
refId string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSubModuleFile(c *Commit, refUrl, refId string) *SubModuleFile {
|
||||||
|
return &SubModuleFile{
|
||||||
|
Commit: c,
|
||||||
|
refUrl: refUrl,
|
||||||
|
refId: refId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefUrl guesses and returns reference URL.
|
||||||
|
func (sf *SubModuleFile) RefUrl() string {
|
||||||
|
url := strings.TrimSuffix(sf.refUrl, ".git")
|
||||||
|
|
||||||
|
// git://xxx/user/repo
|
||||||
|
if strings.HasPrefix(url, "git://") {
|
||||||
|
return "http://" + strings.TrimPrefix(url, "git://")
|
||||||
|
}
|
||||||
|
|
||||||
|
// http[s]://xxx/user/repo
|
||||||
|
if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") {
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
// sysuser@xxx:user/repo
|
||||||
|
i := strings.Index(url, "@")
|
||||||
|
j := strings.LastIndex(url, ":")
|
||||||
|
if i > -1 && j > -1 {
|
||||||
|
return "http://" + url[i+1:j] + "/" + url[j+1:]
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefId returns reference ID.
|
||||||
|
func (sf *SubModuleFile) RefId() string {
|
||||||
|
return sf.refId
|
||||||
|
}
|
|
@ -51,6 +51,8 @@ func parseTreeData(tree *Tree, data []byte) ([]*TreeEntry, error) {
|
||||||
case "160000":
|
case "160000":
|
||||||
entry.mode = ModeCommit
|
entry.mode = ModeCommit
|
||||||
entry.Type = COMMIT
|
entry.Type = COMMIT
|
||||||
|
|
||||||
|
step = 8
|
||||||
case "040000":
|
case "040000":
|
||||||
entry.mode = ModeTree
|
entry.mode = ModeTree
|
||||||
entry.Type = TREE
|
entry.Type = TREE
|
||||||
|
@ -107,9 +109,12 @@ func (t *Tree) ListEntries(relpath string) (Entries, error) {
|
||||||
}
|
}
|
||||||
t.entriesParsed = true
|
t.entriesParsed = true
|
||||||
|
|
||||||
stdout, _, err := com.ExecCmdDirBytes(t.repo.Path,
|
stdout, stderr, err := com.ExecCmdDirBytes(t.repo.Path,
|
||||||
"git", "ls-tree", t.Id.String())
|
"git", "ls-tree", t.Id.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "exit status 128") {
|
||||||
|
return nil, errors.New(strings.TrimSpace(string(stderr)))
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t.entries, err = parseTreeData(t, stdout)
|
t.entries, err = parseTreeData(t, stdout)
|
||||||
|
|
|
@ -61,6 +61,10 @@ func (te *TreeEntry) Size() int64 {
|
||||||
return te.size
|
return te.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (te *TreeEntry) IsSubModule() bool {
|
||||||
|
return te.mode == ModeCommit
|
||||||
|
}
|
||||||
|
|
||||||
func (te *TreeEntry) IsDir() bool {
|
func (te *TreeEntry) IsDir() bool {
|
||||||
return te.mode == ModeTree
|
return te.mode == ModeTree
|
||||||
}
|
}
|
||||||
|
@ -80,7 +84,7 @@ type Entries []*TreeEntry
|
||||||
|
|
||||||
var sorter = []func(t1, t2 *TreeEntry) bool{
|
var sorter = []func(t1, t2 *TreeEntry) bool{
|
||||||
func(t1, t2 *TreeEntry) bool {
|
func(t1, t2 *TreeEntry) bool {
|
||||||
return t1.IsDir() && !t2.IsDir()
|
return (t1.IsDir() || t1.IsSubModule()) && !t2.IsDir() && !t2.IsSubModule()
|
||||||
},
|
},
|
||||||
func(t1, t2 *TreeEntry) bool {
|
func(t1, t2 *TreeEntry) bool {
|
||||||
return t1.name < t2.name
|
return t1.name < t2.name
|
||||||
|
|
|
@ -11,33 +11,85 @@ import (
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Cached Git version.
|
||||||
|
gitVer *Version
|
||||||
|
)
|
||||||
|
|
||||||
// Version represents version of Git.
|
// Version represents version of Git.
|
||||||
type Version struct {
|
type Version struct {
|
||||||
Major, Minor, Patch int
|
Major, Minor, Patch int
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVersion returns current Git version installed.
|
func ParseVersion(verStr string) (*Version, error) {
|
||||||
func GetVersion() (Version, error) {
|
infos := strings.Split(verStr, ".")
|
||||||
stdout, stderr, err := com.ExecCmd("git", "version")
|
|
||||||
if err != nil {
|
|
||||||
return Version{}, errors.New(stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
infos := strings.Split(stdout, " ")
|
|
||||||
if len(infos) < 3 {
|
if len(infos) < 3 {
|
||||||
return Version{}, errors.New("not enough output")
|
return nil, errors.New("incorrect version input")
|
||||||
}
|
}
|
||||||
|
|
||||||
v := Version{}
|
v := &Version{}
|
||||||
for i, s := range strings.Split(strings.TrimSpace(infos[2]), ".") {
|
for i, s := range infos {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
v.Major, _ = com.StrTo(s).Int()
|
v.Major, _ = com.StrTo(s).Int()
|
||||||
case 1:
|
case 1:
|
||||||
v.Minor, _ = com.StrTo(s).Int()
|
v.Minor, _ = com.StrTo(s).Int()
|
||||||
case 2:
|
case 2:
|
||||||
v.Patch, _ = com.StrTo(s).Int()
|
v.Patch, _ = com.StrTo(strings.TrimSpace(s)).Int()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MustParseVersion(verStr string) *Version {
|
||||||
|
v, _ := ParseVersion(verStr)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare compares two versions,
|
||||||
|
// it returns 1 if original is greater, -1 if original is smaller, 0 if equal.
|
||||||
|
func (v *Version) Compare(that *Version) int {
|
||||||
|
if v.Major > that.Major {
|
||||||
|
return 1
|
||||||
|
} else if v.Major < that.Major {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Minor > that.Minor {
|
||||||
|
return 1
|
||||||
|
} else if v.Minor < that.Minor {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Patch > that.Patch {
|
||||||
|
return 1
|
||||||
|
} else if v.Patch < that.Patch {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Version) LessThan(that *Version) bool {
|
||||||
|
return v.Compare(that) < 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVersion returns current Git version installed.
|
||||||
|
func GetVersion() (*Version, error) {
|
||||||
|
if gitVer != nil {
|
||||||
|
return gitVer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
stdout, stderr, err := com.ExecCmd("git", "version")
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New(stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
infos := strings.Split(stdout, " ")
|
||||||
|
if len(infos) < 3 {
|
||||||
|
return nil, errors.New("not enough output")
|
||||||
|
}
|
||||||
|
|
||||||
|
gitVer, err = ParseVersion(infos[2])
|
||||||
|
return gitVer, err
|
||||||
|
}
|
||||||
|
|
27
modules/ldap/LICENSE
Normal file
27
modules/ldap/LICENSE
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
33
modules/ldap/README
Normal file
33
modules/ldap/README
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
Basic LDAP v3 functionality for the GO programming language.
|
||||||
|
|
||||||
|
Required Librarys:
|
||||||
|
github.com/johnweldon/asn1-ber
|
||||||
|
|
||||||
|
Working:
|
||||||
|
Connecting to LDAP server
|
||||||
|
Binding to LDAP server
|
||||||
|
Searching for entries
|
||||||
|
Compiling string filters to LDAP filters
|
||||||
|
Paging Search Results
|
||||||
|
Modify Requests / Responses
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
search
|
||||||
|
modify
|
||||||
|
|
||||||
|
Tests Implemented:
|
||||||
|
Filter Compile / Decompile
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
Add Requests / Responses
|
||||||
|
Delete Requests / Responses
|
||||||
|
Modify DN Requests / Responses
|
||||||
|
Compare Requests / Responses
|
||||||
|
Implement Tests / Benchmarks
|
||||||
|
|
||||||
|
This feature is disabled at the moment, because in some cases the "Search Request Done" packet will be handled before the last "Search Request Entry":
|
||||||
|
Mulitple internal goroutines to handle network traffic
|
||||||
|
Makes library goroutine safe
|
||||||
|
Can perform multiple search requests at the same time and return
|
||||||
|
the results to the proper goroutine. All requests are blocking
|
||||||
|
requests, so the goroutine does not need special handling
|
63
modules/ldap/_examples/enterprise.ldif
Normal file
63
modules/ldap/_examples/enterprise.ldif
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
dn: dc=enterprise,dc=org
|
||||||
|
objectClass: dcObject
|
||||||
|
objectClass: organization
|
||||||
|
o: acme
|
||||||
|
|
||||||
|
dn: cn=admin,dc=enterprise,dc=org
|
||||||
|
objectClass: person
|
||||||
|
cn: admin
|
||||||
|
sn: admin
|
||||||
|
description: "LDAP Admin"
|
||||||
|
|
||||||
|
dn: ou=crew,dc=enterprise,dc=org
|
||||||
|
ou: crew
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
|
||||||
|
|
||||||
|
dn: cn=kirkj,ou=crew,dc=enterprise,dc=org
|
||||||
|
cn: kirkj
|
||||||
|
sn: Kirk
|
||||||
|
gn: James Tiberius
|
||||||
|
mail: james.kirk@enterprise.org
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
|
||||||
|
dn: cn=spock,ou=crew,dc=enterprise,dc=org
|
||||||
|
cn: spock
|
||||||
|
sn: Spock
|
||||||
|
mail: spock@enterprise.org
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
|
||||||
|
dn: cn=mccoyl,ou=crew,dc=enterprise,dc=org
|
||||||
|
cn: mccoyl
|
||||||
|
sn: McCoy
|
||||||
|
gn: Leonard
|
||||||
|
mail: leonard.mccoy@enterprise.org
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
|
||||||
|
dn: cn=scottm,ou=crew,dc=enterprise,dc=org
|
||||||
|
cn: scottm
|
||||||
|
sn: Scott
|
||||||
|
gn: Montgomery
|
||||||
|
mail: Montgomery.scott@enterprise.org
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
|
||||||
|
dn: cn=uhuran,ou=crew,dc=enterprise,dc=org
|
||||||
|
cn: uhuran
|
||||||
|
sn: Uhura
|
||||||
|
gn: Nyota
|
||||||
|
mail: nyota.uhura@enterprise.org
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
|
||||||
|
dn: cn=suluh,ou=crew,dc=enterprise,dc=org
|
||||||
|
cn: suluh
|
||||||
|
sn: Sulu
|
||||||
|
gn: Hikaru
|
||||||
|
mail: hikaru.sulu@enterprise.org
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
|
||||||
|
dn: cn=chekovp,ou=crew,dc=enterprise,dc=org
|
||||||
|
cn: chekovp
|
||||||
|
sn: Chekov
|
||||||
|
gn: pavel
|
||||||
|
mail: pavel.chekov@enterprise.org
|
||||||
|
objectClass: inetOrgPerson
|
89
modules/ldap/_examples/modify.go
Normal file
89
modules/ldap/_examples/modify.go
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/ldap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
LdapServer string = "localhost"
|
||||||
|
LdapPort uint16 = 389
|
||||||
|
BaseDN string = "dc=enterprise,dc=org"
|
||||||
|
BindDN string = "cn=admin,dc=enterprise,dc=org"
|
||||||
|
BindPW string = "enterprise"
|
||||||
|
Filter string = "(cn=kirkj)"
|
||||||
|
)
|
||||||
|
|
||||||
|
func search(l *ldap.Conn, filter string, attributes []string) (*ldap.Entry, *ldap.Error) {
|
||||||
|
search := ldap.NewSearchRequest(
|
||||||
|
BaseDN,
|
||||||
|
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
|
filter,
|
||||||
|
attributes,
|
||||||
|
nil)
|
||||||
|
|
||||||
|
sr, err := l.Search(search)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("ERROR: %s\n", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Search: %s -> num of entries = %d\n", search.Filter, len(sr.Entries))
|
||||||
|
if len(sr.Entries) == 0 {
|
||||||
|
return nil, ldap.NewError(ldap.ErrorDebugging, errors.New(fmt.Sprintf("no entries found for: %s", filter)))
|
||||||
|
}
|
||||||
|
return sr.Entries[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", LdapServer, LdapPort))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("ERROR: %s\n", err.Error())
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
// l.Debug = true
|
||||||
|
|
||||||
|
l.Bind(BindDN, BindPW)
|
||||||
|
|
||||||
|
log.Printf("The Search for Kirk ... %s\n", Filter)
|
||||||
|
entry, err := search(l, Filter, []string{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("could not get entry")
|
||||||
|
}
|
||||||
|
entry.PrettyPrint(0)
|
||||||
|
|
||||||
|
log.Printf("modify the mail address and add a description ... \n")
|
||||||
|
modify := ldap.NewModifyRequest(entry.DN)
|
||||||
|
modify.Add("description", []string{"Captain of the USS Enterprise"})
|
||||||
|
modify.Replace("mail", []string{"captain@enterprise.org"})
|
||||||
|
if err := l.Modify(modify); err != nil {
|
||||||
|
log.Fatalf("ERROR: %s\n", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
entry, err = search(l, Filter, []string{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("could not get entry")
|
||||||
|
}
|
||||||
|
entry.PrettyPrint(0)
|
||||||
|
|
||||||
|
log.Printf("reset the entry ... \n")
|
||||||
|
modify = ldap.NewModifyRequest(entry.DN)
|
||||||
|
modify.Delete("description", []string{})
|
||||||
|
modify.Replace("mail", []string{"james.kirk@enterprise.org"})
|
||||||
|
if err := l.Modify(modify); err != nil {
|
||||||
|
log.Fatalf("ERROR: %s\n", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
entry, err = search(l, Filter, []string{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("could not get entry")
|
||||||
|
}
|
||||||
|
entry.PrettyPrint(0)
|
||||||
|
}
|
52
modules/ldap/_examples/search.go
Normal file
52
modules/ldap/_examples/search.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/ldap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ldapServer string = "adserver"
|
||||||
|
ldapPort uint16 = 3268
|
||||||
|
baseDN string = "dc=*,dc=*"
|
||||||
|
filter string = "(&(objectClass=user)(sAMAccountName=*)(memberOf=CN=*,OU=*,DC=*,DC=*))"
|
||||||
|
Attributes []string = []string{"memberof"}
|
||||||
|
user string = "*"
|
||||||
|
passwd string = "*"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("ERROR: %s\n", err.Error())
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
// l.Debug = true
|
||||||
|
|
||||||
|
err = l.Bind(user, passwd)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: Cannot bind: %s\n", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
search := ldap.NewSearchRequest(
|
||||||
|
baseDN,
|
||||||
|
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
|
filter,
|
||||||
|
Attributes,
|
||||||
|
nil)
|
||||||
|
|
||||||
|
sr, err := l.Search(search)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("ERROR: %s\n", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Search: %s -> num of entries = %d\n", search.Filter, len(sr.Entries))
|
||||||
|
sr.PrettyPrint(0)
|
||||||
|
}
|
45
modules/ldap/_examples/searchSSL.go
Normal file
45
modules/ldap/_examples/searchSSL.go
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/ldap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
LdapServer string = "localhost"
|
||||||
|
LdapPort uint16 = 636
|
||||||
|
BaseDN string = "dc=enterprise,dc=org"
|
||||||
|
Filter string = "(cn=kirkj)"
|
||||||
|
Attributes []string = []string{"mail"}
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
l, err := ldap.DialSSL("tcp", fmt.Sprintf("%s:%d", LdapServer, LdapPort), nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("ERROR: %s\n", err.String())
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
// l.Debug = true
|
||||||
|
|
||||||
|
search := ldap.NewSearchRequest(
|
||||||
|
BaseDN,
|
||||||
|
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
|
Filter,
|
||||||
|
Attributes,
|
||||||
|
nil)
|
||||||
|
|
||||||
|
sr, err := l.Search(search)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("ERROR: %s\n", err.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Search: %s -> num of entries = %d\n", search.Filter, len(sr.Entries))
|
||||||
|
sr.PrettyPrint(0)
|
||||||
|
}
|
45
modules/ldap/_examples/searchTLS.go
Normal file
45
modules/ldap/_examples/searchTLS.go
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/ldap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
LdapServer string = "localhost"
|
||||||
|
LdapPort uint16 = 389
|
||||||
|
BaseDN string = "dc=enterprise,dc=org"
|
||||||
|
Filter string = "(cn=kirkj)"
|
||||||
|
Attributes []string = []string{"mail"}
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
l, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", LdapServer, LdapPort), nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("ERROR: %s\n", err.Error())
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
// l.Debug = true
|
||||||
|
|
||||||
|
search := ldap.NewSearchRequest(
|
||||||
|
BaseDN,
|
||||||
|
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
|
Filter,
|
||||||
|
Attributes,
|
||||||
|
nil)
|
||||||
|
|
||||||
|
sr, err := l.Search(search)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("ERROR: %s\n", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Search: %s -> num of entries = %d\n", search.Filter, len(sr.Entries))
|
||||||
|
sr.PrettyPrint(0)
|
||||||
|
}
|
67
modules/ldap/_examples/slapd.conf
Normal file
67
modules/ldap/_examples/slapd.conf
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#
|
||||||
|
# See slapd.conf(5) for details on configuration options.
|
||||||
|
# This file should NOT be world readable.
|
||||||
|
#
|
||||||
|
include /private/etc/openldap/schema/core.schema
|
||||||
|
include /private/etc/openldap/schema/cosine.schema
|
||||||
|
include /private/etc/openldap/schema/inetorgperson.schema
|
||||||
|
|
||||||
|
# Define global ACLs to disable default read access.
|
||||||
|
|
||||||
|
# Do not enable referrals until AFTER you have a working directory
|
||||||
|
# service AND an understanding of referrals.
|
||||||
|
#referral ldap://root.openldap.org
|
||||||
|
|
||||||
|
pidfile /private/var/db/openldap/run/slapd.pid
|
||||||
|
argsfile /private/var/db/openldap/run/slapd.args
|
||||||
|
|
||||||
|
# Load dynamic backend modules:
|
||||||
|
# modulepath /usr/libexec/openldap
|
||||||
|
# moduleload back_bdb.la
|
||||||
|
# moduleload back_hdb.la
|
||||||
|
# moduleload back_ldap.la
|
||||||
|
|
||||||
|
# Sample security restrictions
|
||||||
|
# Require integrity protection (prevent hijacking)
|
||||||
|
# Require 112-bit (3DES or better) encryption for updates
|
||||||
|
# Require 63-bit encryption for simple bind
|
||||||
|
# security ssf=1 update_ssf=112 simple_bind=64
|
||||||
|
|
||||||
|
# Sample access control policy:
|
||||||
|
# Root DSE: allow anyone to read it
|
||||||
|
# Subschema (sub)entry DSE: allow anyone to read it
|
||||||
|
# Other DSEs:
|
||||||
|
# Allow self write access
|
||||||
|
# Allow authenticated users read access
|
||||||
|
# Allow anonymous users to authenticate
|
||||||
|
# Directives needed to implement policy:
|
||||||
|
# access to dn.base="" by * read
|
||||||
|
# access to dn.base="cn=Subschema" by * read
|
||||||
|
# access to *
|
||||||
|
# by self write
|
||||||
|
# by users read
|
||||||
|
# by anonymous auth
|
||||||
|
#
|
||||||
|
# if no access controls are present, the default policy
|
||||||
|
# allows anyone and everyone to read anything but restricts
|
||||||
|
# updates to rootdn. (e.g., "access to * by * read")
|
||||||
|
#
|
||||||
|
# rootdn can always read and write EVERYTHING!
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# BDB database definitions
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
database bdb
|
||||||
|
suffix "dc=enterprise,dc=org"
|
||||||
|
rootdn "cn=admin,dc=enterprise,dc=org"
|
||||||
|
# Cleartext passwords, especially for the rootdn, should
|
||||||
|
# be avoid. See slappasswd(8) and slapd.conf(5) for details.
|
||||||
|
# Use of strong authentication encouraged.
|
||||||
|
rootpw {SSHA}laO00HsgszhK1O0Z5qR0/i/US69Osfeu
|
||||||
|
# The database directory MUST exist prior to running slapd AND
|
||||||
|
# should only be accessible by the slapd and slap tools.
|
||||||
|
# Mode 700 recommended.
|
||||||
|
directory /private/var/db/openldap/openldap-data
|
||||||
|
# Indices to maintain
|
||||||
|
index objectClass eq
|
55
modules/ldap/bind.go
Normal file
55
modules/ldap/bind.go
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/asn1-ber"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (l *Conn) Bind(username, password string) error {
|
||||||
|
messageID := l.nextMessageID()
|
||||||
|
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
|
||||||
|
bindRequest := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
|
||||||
|
bindRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
|
||||||
|
bindRequest.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, username, "User Name"))
|
||||||
|
bindRequest.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, password, "Password"))
|
||||||
|
packet.AppendChild(bindRequest)
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := l.sendMessage(packet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if channel == nil {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: could not send message"))
|
||||||
|
}
|
||||||
|
defer l.finishMessage(messageID)
|
||||||
|
|
||||||
|
packet = <-channel
|
||||||
|
if packet == nil {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: could not retrieve response"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||||
|
if resultCode != 0 {
|
||||||
|
return NewError(resultCode, errors.New(resultDescription))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
275
modules/ldap/conn.go
Normal file
275
modules/ldap/conn.go
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/asn1-ber"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MessageQuit = 0
|
||||||
|
MessageRequest = 1
|
||||||
|
MessageResponse = 2
|
||||||
|
MessageFinish = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
type messagePacket struct {
|
||||||
|
Op int
|
||||||
|
MessageID uint64
|
||||||
|
Packet *ber.Packet
|
||||||
|
Channel chan *ber.Packet
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conn represents an LDAP Connection
|
||||||
|
type Conn struct {
|
||||||
|
conn net.Conn
|
||||||
|
isTLS bool
|
||||||
|
isClosing bool
|
||||||
|
Debug debugging
|
||||||
|
chanConfirm chan bool
|
||||||
|
chanResults map[uint64]chan *ber.Packet
|
||||||
|
chanMessage chan *messagePacket
|
||||||
|
chanMessageID chan uint64
|
||||||
|
wgSender sync.WaitGroup
|
||||||
|
wgClose sync.WaitGroup
|
||||||
|
once sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dial connects to the given address on the given network using net.Dial
|
||||||
|
// and then returns a new Conn for the connection.
|
||||||
|
func Dial(network, addr string) (*Conn, error) {
|
||||||
|
c, err := net.Dial(network, addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, NewError(ErrorNetwork, err)
|
||||||
|
}
|
||||||
|
conn := NewConn(c)
|
||||||
|
conn.start()
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DialTLS connects to the given address on the given network using tls.Dial
|
||||||
|
// and then returns a new Conn for the connection.
|
||||||
|
func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
|
||||||
|
c, err := tls.Dial(network, addr, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, NewError(ErrorNetwork, err)
|
||||||
|
}
|
||||||
|
conn := NewConn(c)
|
||||||
|
conn.isTLS = true
|
||||||
|
conn.start()
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConn returns a new Conn using conn for network I/O.
|
||||||
|
func NewConn(conn net.Conn) *Conn {
|
||||||
|
return &Conn{
|
||||||
|
conn: conn,
|
||||||
|
chanConfirm: make(chan bool),
|
||||||
|
chanMessageID: make(chan uint64),
|
||||||
|
chanMessage: make(chan *messagePacket, 10),
|
||||||
|
chanResults: map[uint64]chan *ber.Packet{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) start() {
|
||||||
|
go l.reader()
|
||||||
|
go l.processMessages()
|
||||||
|
l.wgClose.Add(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the connection.
|
||||||
|
func (l *Conn) Close() {
|
||||||
|
l.once.Do(func() {
|
||||||
|
l.isClosing = true
|
||||||
|
l.wgSender.Wait()
|
||||||
|
|
||||||
|
l.Debug.Printf("Sending quit message and waiting for confirmation")
|
||||||
|
l.chanMessage <- &messagePacket{Op: MessageQuit}
|
||||||
|
<-l.chanConfirm
|
||||||
|
close(l.chanMessage)
|
||||||
|
|
||||||
|
l.Debug.Printf("Closing network connection")
|
||||||
|
if err := l.conn.Close(); err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.conn = nil
|
||||||
|
l.wgClose.Done()
|
||||||
|
})
|
||||||
|
l.wgClose.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the next available messageID
|
||||||
|
func (l *Conn) nextMessageID() uint64 {
|
||||||
|
if l.chanMessageID != nil {
|
||||||
|
if messageID, ok := <-l.chanMessageID; ok {
|
||||||
|
return messageID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartTLS sends the command to start a TLS session and then creates a new TLS Client
|
||||||
|
func (l *Conn) StartTLS(config *tls.Config) error {
|
||||||
|
messageID := l.nextMessageID()
|
||||||
|
|
||||||
|
if l.isTLS {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: already encrypted"))
|
||||||
|
}
|
||||||
|
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
|
||||||
|
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Start TLS")
|
||||||
|
request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, "1.3.6.1.4.1.1466.20037", "TLS Extended Command"))
|
||||||
|
packet.AppendChild(request)
|
||||||
|
l.Debug.PrintPacket(packet)
|
||||||
|
|
||||||
|
_, err := l.conn.Write(packet.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return NewError(ErrorNetwork, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
packet, err = ber.ReadPacket(l.conn)
|
||||||
|
if err != nil {
|
||||||
|
return NewError(ErrorNetwork, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
if packet.Children[1].Children[0].Value.(uint64) == 0 {
|
||||||
|
conn := tls.Client(l.conn, config)
|
||||||
|
l.isTLS = true
|
||||||
|
l.conn = conn
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) sendMessage(packet *ber.Packet) (chan *ber.Packet, error) {
|
||||||
|
if l.isClosing {
|
||||||
|
return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed"))
|
||||||
|
}
|
||||||
|
out := make(chan *ber.Packet)
|
||||||
|
message := &messagePacket{
|
||||||
|
Op: MessageRequest,
|
||||||
|
MessageID: packet.Children[0].Value.(uint64),
|
||||||
|
Packet: packet,
|
||||||
|
Channel: out,
|
||||||
|
}
|
||||||
|
l.sendProcessMessage(message)
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) finishMessage(messageID uint64) {
|
||||||
|
if l.isClosing {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message := &messagePacket{
|
||||||
|
Op: MessageFinish,
|
||||||
|
MessageID: messageID,
|
||||||
|
}
|
||||||
|
l.sendProcessMessage(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) sendProcessMessage(message *messagePacket) bool {
|
||||||
|
if l.isClosing {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
l.wgSender.Add(1)
|
||||||
|
l.chanMessage <- message
|
||||||
|
l.wgSender.Done()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) processMessages() {
|
||||||
|
defer func() {
|
||||||
|
for messageID, channel := range l.chanResults {
|
||||||
|
l.Debug.Printf("Closing channel for MessageID %d", messageID)
|
||||||
|
close(channel)
|
||||||
|
delete(l.chanResults, messageID)
|
||||||
|
}
|
||||||
|
close(l.chanMessageID)
|
||||||
|
l.chanConfirm <- true
|
||||||
|
close(l.chanConfirm)
|
||||||
|
}()
|
||||||
|
|
||||||
|
var messageID uint64 = 1
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case l.chanMessageID <- messageID:
|
||||||
|
messageID++
|
||||||
|
case messagePacket, ok := <-l.chanMessage:
|
||||||
|
if !ok {
|
||||||
|
l.Debug.Printf("Shutting down - message channel is closed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch messagePacket.Op {
|
||||||
|
case MessageQuit:
|
||||||
|
l.Debug.Printf("Shutting down - quit message received")
|
||||||
|
return
|
||||||
|
case MessageRequest:
|
||||||
|
// Add to message list and write to network
|
||||||
|
l.Debug.Printf("Sending message %d", messagePacket.MessageID)
|
||||||
|
l.chanResults[messagePacket.MessageID] = messagePacket.Channel
|
||||||
|
// go routine
|
||||||
|
buf := messagePacket.Packet.Bytes()
|
||||||
|
|
||||||
|
_, err := l.conn.Write(buf)
|
||||||
|
if err != nil {
|
||||||
|
l.Debug.Printf("Error Sending Message: %s", err.Error())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case MessageResponse:
|
||||||
|
l.Debug.Printf("Receiving message %d", messagePacket.MessageID)
|
||||||
|
if chanResult, ok := l.chanResults[messagePacket.MessageID]; ok {
|
||||||
|
chanResult <- messagePacket.Packet
|
||||||
|
} else {
|
||||||
|
log.Printf("Received unexpected message %d", messagePacket.MessageID)
|
||||||
|
ber.PrintPacket(messagePacket.Packet)
|
||||||
|
}
|
||||||
|
case MessageFinish:
|
||||||
|
// Remove from message list
|
||||||
|
l.Debug.Printf("Finished message %d", messagePacket.MessageID)
|
||||||
|
close(l.chanResults[messagePacket.MessageID])
|
||||||
|
delete(l.chanResults, messagePacket.MessageID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) reader() {
|
||||||
|
defer func() {
|
||||||
|
l.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
packet, err := ber.ReadPacket(l.conn)
|
||||||
|
if err != nil {
|
||||||
|
l.Debug.Printf("reader: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addLDAPDescriptions(packet)
|
||||||
|
message := &messagePacket{
|
||||||
|
Op: MessageResponse,
|
||||||
|
MessageID: packet.Children[0].Value.(uint64),
|
||||||
|
Packet: packet,
|
||||||
|
}
|
||||||
|
if !l.sendProcessMessage(message) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
157
modules/ldap/control.go
Normal file
157
modules/ldap/control.go
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/asn1-ber"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ControlTypePaging = "1.2.840.113556.1.4.319"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ControlTypeMap = map[string]string{
|
||||||
|
ControlTypePaging: "Paging",
|
||||||
|
}
|
||||||
|
|
||||||
|
type Control interface {
|
||||||
|
GetControlType() string
|
||||||
|
Encode() *ber.Packet
|
||||||
|
String() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ControlString struct {
|
||||||
|
ControlType string
|
||||||
|
Criticality bool
|
||||||
|
ControlValue string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlString) GetControlType() string {
|
||||||
|
return c.ControlType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlString) Encode() *ber.Packet {
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.ControlType, "Control Type ("+ControlTypeMap[c.ControlType]+")"))
|
||||||
|
if c.Criticality {
|
||||||
|
packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality"))
|
||||||
|
}
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.ControlValue, "Control Value"))
|
||||||
|
return packet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlString) String() string {
|
||||||
|
return fmt.Sprintf("Control Type: %s (%q) Criticality: %t Control Value: %s", ControlTypeMap[c.ControlType], c.ControlType, c.Criticality, c.ControlValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ControlPaging struct {
|
||||||
|
PagingSize uint32
|
||||||
|
Cookie []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlPaging) GetControlType() string {
|
||||||
|
return ControlTypePaging
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlPaging) Encode() *ber.Packet {
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypePaging, "Control Type ("+ControlTypeMap[ControlTypePaging]+")"))
|
||||||
|
|
||||||
|
p2 := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (Paging)")
|
||||||
|
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Search Control Value")
|
||||||
|
seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(c.PagingSize), "Paging Size"))
|
||||||
|
cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Cookie")
|
||||||
|
cookie.Value = c.Cookie
|
||||||
|
cookie.Data.Write(c.Cookie)
|
||||||
|
seq.AppendChild(cookie)
|
||||||
|
p2.AppendChild(seq)
|
||||||
|
|
||||||
|
packet.AppendChild(p2)
|
||||||
|
return packet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlPaging) String() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"Control Type: %s (%q) Criticality: %t PagingSize: %d Cookie: %q",
|
||||||
|
ControlTypeMap[ControlTypePaging],
|
||||||
|
ControlTypePaging,
|
||||||
|
false,
|
||||||
|
c.PagingSize,
|
||||||
|
c.Cookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlPaging) SetCookie(cookie []byte) {
|
||||||
|
c.Cookie = cookie
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindControl(controls []Control, controlType string) Control {
|
||||||
|
for _, c := range controls {
|
||||||
|
if c.GetControlType() == controlType {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeControl(packet *ber.Packet) Control {
|
||||||
|
ControlType := packet.Children[0].Value.(string)
|
||||||
|
Criticality := false
|
||||||
|
|
||||||
|
packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")"
|
||||||
|
value := packet.Children[1]
|
||||||
|
if len(packet.Children) == 3 {
|
||||||
|
value = packet.Children[2]
|
||||||
|
packet.Children[1].Description = "Criticality"
|
||||||
|
Criticality = packet.Children[1].Value.(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
value.Description = "Control Value"
|
||||||
|
switch ControlType {
|
||||||
|
case ControlTypePaging:
|
||||||
|
value.Description += " (Paging)"
|
||||||
|
c := new(ControlPaging)
|
||||||
|
if value.Value != nil {
|
||||||
|
valueChildren := ber.DecodePacket(value.Data.Bytes())
|
||||||
|
value.Data.Truncate(0)
|
||||||
|
value.Value = nil
|
||||||
|
value.AppendChild(valueChildren)
|
||||||
|
}
|
||||||
|
value = value.Children[0]
|
||||||
|
value.Description = "Search Control Value"
|
||||||
|
value.Children[0].Description = "Paging Size"
|
||||||
|
value.Children[1].Description = "Cookie"
|
||||||
|
c.PagingSize = uint32(value.Children[0].Value.(uint64))
|
||||||
|
c.Cookie = value.Children[1].Data.Bytes()
|
||||||
|
value.Children[1].Value = c.Cookie
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
c := new(ControlString)
|
||||||
|
c.ControlType = ControlType
|
||||||
|
c.Criticality = Criticality
|
||||||
|
c.ControlValue = value.Value.(string)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewControlString(controlType string, criticality bool, controlValue string) *ControlString {
|
||||||
|
return &ControlString{
|
||||||
|
ControlType: controlType,
|
||||||
|
Criticality: criticality,
|
||||||
|
ControlValue: controlValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewControlPaging(pagingSize uint32) *ControlPaging {
|
||||||
|
return &ControlPaging{PagingSize: pagingSize}
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeControls(controls []Control) *ber.Packet {
|
||||||
|
packet := ber.Encode(ber.ClassContext, ber.TypeConstructed, 0, nil, "Controls")
|
||||||
|
for _, control := range controls {
|
||||||
|
packet.AppendChild(control.Encode())
|
||||||
|
}
|
||||||
|
return packet
|
||||||
|
}
|
24
modules/ldap/debug.go
Normal file
24
modules/ldap/debug.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/asn1-ber"
|
||||||
|
)
|
||||||
|
|
||||||
|
// debbuging type
|
||||||
|
// - has a Printf method to write the debug output
|
||||||
|
type debugging bool
|
||||||
|
|
||||||
|
// write debug output
|
||||||
|
func (debug debugging) Printf(format string, args ...interface{}) {
|
||||||
|
if debug {
|
||||||
|
log.Printf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (debug debugging) PrintPacket(packet *ber.Packet) {
|
||||||
|
if debug {
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
}
|
248
modules/ldap/filter.go
Normal file
248
modules/ldap/filter.go
Normal file
|
@ -0,0 +1,248 @@
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/asn1-ber"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
FilterAnd = 0
|
||||||
|
FilterOr = 1
|
||||||
|
FilterNot = 2
|
||||||
|
FilterEqualityMatch = 3
|
||||||
|
FilterSubstrings = 4
|
||||||
|
FilterGreaterOrEqual = 5
|
||||||
|
FilterLessOrEqual = 6
|
||||||
|
FilterPresent = 7
|
||||||
|
FilterApproxMatch = 8
|
||||||
|
FilterExtensibleMatch = 9
|
||||||
|
)
|
||||||
|
|
||||||
|
var FilterMap = map[uint64]string{
|
||||||
|
FilterAnd: "And",
|
||||||
|
FilterOr: "Or",
|
||||||
|
FilterNot: "Not",
|
||||||
|
FilterEqualityMatch: "Equality Match",
|
||||||
|
FilterSubstrings: "Substrings",
|
||||||
|
FilterGreaterOrEqual: "Greater Or Equal",
|
||||||
|
FilterLessOrEqual: "Less Or Equal",
|
||||||
|
FilterPresent: "Present",
|
||||||
|
FilterApproxMatch: "Approx Match",
|
||||||
|
FilterExtensibleMatch: "Extensible Match",
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
FilterSubstringsInitial = 0
|
||||||
|
FilterSubstringsAny = 1
|
||||||
|
FilterSubstringsFinal = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
var FilterSubstringsMap = map[uint64]string{
|
||||||
|
FilterSubstringsInitial: "Substrings Initial",
|
||||||
|
FilterSubstringsAny: "Substrings Any",
|
||||||
|
FilterSubstringsFinal: "Substrings Final",
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompileFilter(filter string) (*ber.Packet, error) {
|
||||||
|
if len(filter) == 0 || filter[0] != '(' {
|
||||||
|
return nil, NewError(ErrorFilterCompile, errors.New("ldap: filter does not start with an '('"))
|
||||||
|
}
|
||||||
|
packet, pos, err := compileFilter(filter, 1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if pos != len(filter) {
|
||||||
|
return nil, NewError(ErrorFilterCompile, errors.New("ldap: finished compiling filter with extra at end: "+fmt.Sprint(filter[pos:])))
|
||||||
|
}
|
||||||
|
return packet, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecompileFilter(packet *ber.Packet) (ret string, err error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = NewError(ErrorFilterDecompile, errors.New("ldap: error decompiling filter"))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
ret = "("
|
||||||
|
err = nil
|
||||||
|
childStr := ""
|
||||||
|
|
||||||
|
switch packet.Tag {
|
||||||
|
case FilterAnd:
|
||||||
|
ret += "&"
|
||||||
|
for _, child := range packet.Children {
|
||||||
|
childStr, err = DecompileFilter(child)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ret += childStr
|
||||||
|
}
|
||||||
|
case FilterOr:
|
||||||
|
ret += "|"
|
||||||
|
for _, child := range packet.Children {
|
||||||
|
childStr, err = DecompileFilter(child)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ret += childStr
|
||||||
|
}
|
||||||
|
case FilterNot:
|
||||||
|
ret += "!"
|
||||||
|
childStr, err = DecompileFilter(packet.Children[0])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ret += childStr
|
||||||
|
|
||||||
|
case FilterSubstrings:
|
||||||
|
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
|
||||||
|
ret += "="
|
||||||
|
switch packet.Children[1].Children[0].Tag {
|
||||||
|
case FilterSubstringsInitial:
|
||||||
|
ret += ber.DecodeString(packet.Children[1].Children[0].Data.Bytes()) + "*"
|
||||||
|
case FilterSubstringsAny:
|
||||||
|
ret += "*" + ber.DecodeString(packet.Children[1].Children[0].Data.Bytes()) + "*"
|
||||||
|
case FilterSubstringsFinal:
|
||||||
|
ret += "*" + ber.DecodeString(packet.Children[1].Children[0].Data.Bytes())
|
||||||
|
}
|
||||||
|
case FilterEqualityMatch:
|
||||||
|
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
|
||||||
|
ret += "="
|
||||||
|
ret += ber.DecodeString(packet.Children[1].Data.Bytes())
|
||||||
|
case FilterGreaterOrEqual:
|
||||||
|
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
|
||||||
|
ret += ">="
|
||||||
|
ret += ber.DecodeString(packet.Children[1].Data.Bytes())
|
||||||
|
case FilterLessOrEqual:
|
||||||
|
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
|
||||||
|
ret += "<="
|
||||||
|
ret += ber.DecodeString(packet.Children[1].Data.Bytes())
|
||||||
|
case FilterPresent:
|
||||||
|
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
|
||||||
|
ret += "=*"
|
||||||
|
case FilterApproxMatch:
|
||||||
|
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
|
||||||
|
ret += "~="
|
||||||
|
ret += ber.DecodeString(packet.Children[1].Data.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += ")"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileFilterSet(filter string, pos int, parent *ber.Packet) (int, error) {
|
||||||
|
for pos < len(filter) && filter[pos] == '(' {
|
||||||
|
child, newPos, err := compileFilter(filter, pos+1)
|
||||||
|
if err != nil {
|
||||||
|
return pos, err
|
||||||
|
}
|
||||||
|
pos = newPos
|
||||||
|
parent.AppendChild(child)
|
||||||
|
}
|
||||||
|
if pos == len(filter) {
|
||||||
|
return pos, NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos + 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileFilter(filter string, pos int) (*ber.Packet, int, error) {
|
||||||
|
var packet *ber.Packet
|
||||||
|
var err error
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = NewError(ErrorFilterCompile, errors.New("ldap: error compiling filter"))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
newPos := pos
|
||||||
|
switch filter[pos] {
|
||||||
|
case '(':
|
||||||
|
packet, newPos, err = compileFilter(filter, pos+1)
|
||||||
|
newPos++
|
||||||
|
return packet, newPos, err
|
||||||
|
case '&':
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterAnd, nil, FilterMap[FilterAnd])
|
||||||
|
newPos, err = compileFilterSet(filter, pos+1, packet)
|
||||||
|
return packet, newPos, err
|
||||||
|
case '|':
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterOr, nil, FilterMap[FilterOr])
|
||||||
|
newPos, err = compileFilterSet(filter, pos+1, packet)
|
||||||
|
return packet, newPos, err
|
||||||
|
case '!':
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterNot, nil, FilterMap[FilterNot])
|
||||||
|
var child *ber.Packet
|
||||||
|
child, newPos, err = compileFilter(filter, pos+1)
|
||||||
|
packet.AppendChild(child)
|
||||||
|
return packet, newPos, err
|
||||||
|
default:
|
||||||
|
attribute := ""
|
||||||
|
condition := ""
|
||||||
|
for newPos < len(filter) && filter[newPos] != ')' {
|
||||||
|
switch {
|
||||||
|
case packet != nil:
|
||||||
|
condition += fmt.Sprintf("%c", filter[newPos])
|
||||||
|
case filter[newPos] == '=':
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterEqualityMatch, nil, FilterMap[FilterEqualityMatch])
|
||||||
|
case filter[newPos] == '>' && filter[newPos+1] == '=':
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterGreaterOrEqual, nil, FilterMap[FilterGreaterOrEqual])
|
||||||
|
newPos++
|
||||||
|
case filter[newPos] == '<' && filter[newPos+1] == '=':
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterLessOrEqual, nil, FilterMap[FilterLessOrEqual])
|
||||||
|
newPos++
|
||||||
|
case filter[newPos] == '~' && filter[newPos+1] == '=':
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterApproxMatch, nil, FilterMap[FilterLessOrEqual])
|
||||||
|
newPos++
|
||||||
|
case packet == nil:
|
||||||
|
attribute += fmt.Sprintf("%c", filter[newPos])
|
||||||
|
}
|
||||||
|
newPos++
|
||||||
|
}
|
||||||
|
if newPos == len(filter) {
|
||||||
|
err = NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter"))
|
||||||
|
return packet, newPos, err
|
||||||
|
}
|
||||||
|
if packet == nil {
|
||||||
|
err = NewError(ErrorFilterCompile, errors.New("ldap: error parsing filter"))
|
||||||
|
return packet, newPos, err
|
||||||
|
}
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute"))
|
||||||
|
switch {
|
||||||
|
case packet.Tag == FilterEqualityMatch && condition == "*":
|
||||||
|
packet.Tag = FilterPresent
|
||||||
|
packet.Description = FilterMap[uint64(packet.Tag)]
|
||||||
|
case packet.Tag == FilterEqualityMatch && condition[0] == '*' && condition[len(condition)-1] == '*':
|
||||||
|
// Any
|
||||||
|
packet.Tag = FilterSubstrings
|
||||||
|
packet.Description = FilterMap[uint64(packet.Tag)]
|
||||||
|
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings")
|
||||||
|
seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterSubstringsAny, condition[1:len(condition)-1], "Any Substring"))
|
||||||
|
packet.AppendChild(seq)
|
||||||
|
case packet.Tag == FilterEqualityMatch && condition[0] == '*':
|
||||||
|
// Final
|
||||||
|
packet.Tag = FilterSubstrings
|
||||||
|
packet.Description = FilterMap[uint64(packet.Tag)]
|
||||||
|
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings")
|
||||||
|
seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterSubstringsFinal, condition[1:], "Final Substring"))
|
||||||
|
packet.AppendChild(seq)
|
||||||
|
case packet.Tag == FilterEqualityMatch && condition[len(condition)-1] == '*':
|
||||||
|
// Initial
|
||||||
|
packet.Tag = FilterSubstrings
|
||||||
|
packet.Description = FilterMap[uint64(packet.Tag)]
|
||||||
|
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings")
|
||||||
|
seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterSubstringsInitial, condition[:len(condition)-1], "Initial Substring"))
|
||||||
|
packet.AppendChild(seq)
|
||||||
|
default:
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, condition, "Condition"))
|
||||||
|
}
|
||||||
|
newPos++
|
||||||
|
return packet, newPos, err
|
||||||
|
}
|
||||||
|
}
|
78
modules/ldap/filter_test.go
Normal file
78
modules/ldap/filter_test.go
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/asn1-ber"
|
||||||
|
)
|
||||||
|
|
||||||
|
type compileTest struct {
|
||||||
|
filterStr string
|
||||||
|
filterType int
|
||||||
|
}
|
||||||
|
|
||||||
|
var testFilters = []compileTest{
|
||||||
|
compileTest{filterStr: "(&(sn=Miller)(givenName=Bob))", filterType: FilterAnd},
|
||||||
|
compileTest{filterStr: "(|(sn=Miller)(givenName=Bob))", filterType: FilterOr},
|
||||||
|
compileTest{filterStr: "(!(sn=Miller))", filterType: FilterNot},
|
||||||
|
compileTest{filterStr: "(sn=Miller)", filterType: FilterEqualityMatch},
|
||||||
|
compileTest{filterStr: "(sn=Mill*)", filterType: FilterSubstrings},
|
||||||
|
compileTest{filterStr: "(sn=*Mill)", filterType: FilterSubstrings},
|
||||||
|
compileTest{filterStr: "(sn=*Mill*)", filterType: FilterSubstrings},
|
||||||
|
compileTest{filterStr: "(sn>=Miller)", filterType: FilterGreaterOrEqual},
|
||||||
|
compileTest{filterStr: "(sn<=Miller)", filterType: FilterLessOrEqual},
|
||||||
|
compileTest{filterStr: "(sn=*)", filterType: FilterPresent},
|
||||||
|
compileTest{filterStr: "(sn~=Miller)", filterType: FilterApproxMatch},
|
||||||
|
// compileTest{ filterStr: "()", filterType: FilterExtensibleMatch },
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilter(t *testing.T) {
|
||||||
|
// Test Compiler and Decompiler
|
||||||
|
for _, i := range testFilters {
|
||||||
|
filter, err := CompileFilter(i.filterStr)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Problem compiling %s - %s", i.filterStr, err.Error())
|
||||||
|
} else if filter.Tag != uint8(i.filterType) {
|
||||||
|
t.Errorf("%q Expected %q got %q", i.filterStr, FilterMap[uint64(i.filterType)], FilterMap[uint64(filter.Tag)])
|
||||||
|
} else {
|
||||||
|
o, err := DecompileFilter(filter)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Problem compiling %s - %s", i.filterStr, err.Error())
|
||||||
|
} else if i.filterStr != o {
|
||||||
|
t.Errorf("%q expected, got %q", i.filterStr, o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkFilterCompile(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
filters := make([]string, len(testFilters))
|
||||||
|
|
||||||
|
// Test Compiler and Decompiler
|
||||||
|
for idx, i := range testFilters {
|
||||||
|
filters[idx] = i.filterStr
|
||||||
|
}
|
||||||
|
|
||||||
|
maxIdx := len(filters)
|
||||||
|
b.StartTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
CompileFilter(filters[i%maxIdx])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkFilterDecompile(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
filters := make([]*ber.Packet, len(testFilters))
|
||||||
|
|
||||||
|
// Test Compiler and Decompiler
|
||||||
|
for idx, i := range testFilters {
|
||||||
|
filters[idx], _ = CompileFilter(i.filterStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
maxIdx := len(filters)
|
||||||
|
b.StartTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
DecompileFilter(filters[i%maxIdx])
|
||||||
|
}
|
||||||
|
}
|
302
modules/ldap/ldap.go
Normal file
302
modules/ldap/ldap.go
Normal file
|
@ -0,0 +1,302 @@
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/asn1-ber"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LDAP Application Codes
|
||||||
|
const (
|
||||||
|
ApplicationBindRequest = 0
|
||||||
|
ApplicationBindResponse = 1
|
||||||
|
ApplicationUnbindRequest = 2
|
||||||
|
ApplicationSearchRequest = 3
|
||||||
|
ApplicationSearchResultEntry = 4
|
||||||
|
ApplicationSearchResultDone = 5
|
||||||
|
ApplicationModifyRequest = 6
|
||||||
|
ApplicationModifyResponse = 7
|
||||||
|
ApplicationAddRequest = 8
|
||||||
|
ApplicationAddResponse = 9
|
||||||
|
ApplicationDelRequest = 10
|
||||||
|
ApplicationDelResponse = 11
|
||||||
|
ApplicationModifyDNRequest = 12
|
||||||
|
ApplicationModifyDNResponse = 13
|
||||||
|
ApplicationCompareRequest = 14
|
||||||
|
ApplicationCompareResponse = 15
|
||||||
|
ApplicationAbandonRequest = 16
|
||||||
|
ApplicationSearchResultReference = 19
|
||||||
|
ApplicationExtendedRequest = 23
|
||||||
|
ApplicationExtendedResponse = 24
|
||||||
|
)
|
||||||
|
|
||||||
|
var ApplicationMap = map[uint8]string{
|
||||||
|
ApplicationBindRequest: "Bind Request",
|
||||||
|
ApplicationBindResponse: "Bind Response",
|
||||||
|
ApplicationUnbindRequest: "Unbind Request",
|
||||||
|
ApplicationSearchRequest: "Search Request",
|
||||||
|
ApplicationSearchResultEntry: "Search Result Entry",
|
||||||
|
ApplicationSearchResultDone: "Search Result Done",
|
||||||
|
ApplicationModifyRequest: "Modify Request",
|
||||||
|
ApplicationModifyResponse: "Modify Response",
|
||||||
|
ApplicationAddRequest: "Add Request",
|
||||||
|
ApplicationAddResponse: "Add Response",
|
||||||
|
ApplicationDelRequest: "Del Request",
|
||||||
|
ApplicationDelResponse: "Del Response",
|
||||||
|
ApplicationModifyDNRequest: "Modify DN Request",
|
||||||
|
ApplicationModifyDNResponse: "Modify DN Response",
|
||||||
|
ApplicationCompareRequest: "Compare Request",
|
||||||
|
ApplicationCompareResponse: "Compare Response",
|
||||||
|
ApplicationAbandonRequest: "Abandon Request",
|
||||||
|
ApplicationSearchResultReference: "Search Result Reference",
|
||||||
|
ApplicationExtendedRequest: "Extended Request",
|
||||||
|
ApplicationExtendedResponse: "Extended Response",
|
||||||
|
}
|
||||||
|
|
||||||
|
// LDAP Result Codes
|
||||||
|
const (
|
||||||
|
LDAPResultSuccess = 0
|
||||||
|
LDAPResultOperationsError = 1
|
||||||
|
LDAPResultProtocolError = 2
|
||||||
|
LDAPResultTimeLimitExceeded = 3
|
||||||
|
LDAPResultSizeLimitExceeded = 4
|
||||||
|
LDAPResultCompareFalse = 5
|
||||||
|
LDAPResultCompareTrue = 6
|
||||||
|
LDAPResultAuthMethodNotSupported = 7
|
||||||
|
LDAPResultStrongAuthRequired = 8
|
||||||
|
LDAPResultReferral = 10
|
||||||
|
LDAPResultAdminLimitExceeded = 11
|
||||||
|
LDAPResultUnavailableCriticalExtension = 12
|
||||||
|
LDAPResultConfidentialityRequired = 13
|
||||||
|
LDAPResultSaslBindInProgress = 14
|
||||||
|
LDAPResultNoSuchAttribute = 16
|
||||||
|
LDAPResultUndefinedAttributeType = 17
|
||||||
|
LDAPResultInappropriateMatching = 18
|
||||||
|
LDAPResultConstraintViolation = 19
|
||||||
|
LDAPResultAttributeOrValueExists = 20
|
||||||
|
LDAPResultInvalidAttributeSyntax = 21
|
||||||
|
LDAPResultNoSuchObject = 32
|
||||||
|
LDAPResultAliasProblem = 33
|
||||||
|
LDAPResultInvalidDNSyntax = 34
|
||||||
|
LDAPResultAliasDereferencingProblem = 36
|
||||||
|
LDAPResultInappropriateAuthentication = 48
|
||||||
|
LDAPResultInvalidCredentials = 49
|
||||||
|
LDAPResultInsufficientAccessRights = 50
|
||||||
|
LDAPResultBusy = 51
|
||||||
|
LDAPResultUnavailable = 52
|
||||||
|
LDAPResultUnwillingToPerform = 53
|
||||||
|
LDAPResultLoopDetect = 54
|
||||||
|
LDAPResultNamingViolation = 64
|
||||||
|
LDAPResultObjectClassViolation = 65
|
||||||
|
LDAPResultNotAllowedOnNonLeaf = 66
|
||||||
|
LDAPResultNotAllowedOnRDN = 67
|
||||||
|
LDAPResultEntryAlreadyExists = 68
|
||||||
|
LDAPResultObjectClassModsProhibited = 69
|
||||||
|
LDAPResultAffectsMultipleDSAs = 71
|
||||||
|
LDAPResultOther = 80
|
||||||
|
|
||||||
|
ErrorNetwork = 200
|
||||||
|
ErrorFilterCompile = 201
|
||||||
|
ErrorFilterDecompile = 202
|
||||||
|
ErrorDebugging = 203
|
||||||
|
)
|
||||||
|
|
||||||
|
var LDAPResultCodeMap = map[uint8]string{
|
||||||
|
LDAPResultSuccess: "Success",
|
||||||
|
LDAPResultOperationsError: "Operations Error",
|
||||||
|
LDAPResultProtocolError: "Protocol Error",
|
||||||
|
LDAPResultTimeLimitExceeded: "Time Limit Exceeded",
|
||||||
|
LDAPResultSizeLimitExceeded: "Size Limit Exceeded",
|
||||||
|
LDAPResultCompareFalse: "Compare False",
|
||||||
|
LDAPResultCompareTrue: "Compare True",
|
||||||
|
LDAPResultAuthMethodNotSupported: "Auth Method Not Supported",
|
||||||
|
LDAPResultStrongAuthRequired: "Strong Auth Required",
|
||||||
|
LDAPResultReferral: "Referral",
|
||||||
|
LDAPResultAdminLimitExceeded: "Admin Limit Exceeded",
|
||||||
|
LDAPResultUnavailableCriticalExtension: "Unavailable Critical Extension",
|
||||||
|
LDAPResultConfidentialityRequired: "Confidentiality Required",
|
||||||
|
LDAPResultSaslBindInProgress: "Sasl Bind In Progress",
|
||||||
|
LDAPResultNoSuchAttribute: "No Such Attribute",
|
||||||
|
LDAPResultUndefinedAttributeType: "Undefined Attribute Type",
|
||||||
|
LDAPResultInappropriateMatching: "Inappropriate Matching",
|
||||||
|
LDAPResultConstraintViolation: "Constraint Violation",
|
||||||
|
LDAPResultAttributeOrValueExists: "Attribute Or Value Exists",
|
||||||
|
LDAPResultInvalidAttributeSyntax: "Invalid Attribute Syntax",
|
||||||
|
LDAPResultNoSuchObject: "No Such Object",
|
||||||
|
LDAPResultAliasProblem: "Alias Problem",
|
||||||
|
LDAPResultInvalidDNSyntax: "Invalid DN Syntax",
|
||||||
|
LDAPResultAliasDereferencingProblem: "Alias Dereferencing Problem",
|
||||||
|
LDAPResultInappropriateAuthentication: "Inappropriate Authentication",
|
||||||
|
LDAPResultInvalidCredentials: "Invalid Credentials",
|
||||||
|
LDAPResultInsufficientAccessRights: "Insufficient Access Rights",
|
||||||
|
LDAPResultBusy: "Busy",
|
||||||
|
LDAPResultUnavailable: "Unavailable",
|
||||||
|
LDAPResultUnwillingToPerform: "Unwilling To Perform",
|
||||||
|
LDAPResultLoopDetect: "Loop Detect",
|
||||||
|
LDAPResultNamingViolation: "Naming Violation",
|
||||||
|
LDAPResultObjectClassViolation: "Object Class Violation",
|
||||||
|
LDAPResultNotAllowedOnNonLeaf: "Not Allowed On Non Leaf",
|
||||||
|
LDAPResultNotAllowedOnRDN: "Not Allowed On RDN",
|
||||||
|
LDAPResultEntryAlreadyExists: "Entry Already Exists",
|
||||||
|
LDAPResultObjectClassModsProhibited: "Object Class Mods Prohibited",
|
||||||
|
LDAPResultAffectsMultipleDSAs: "Affects Multiple DSAs",
|
||||||
|
LDAPResultOther: "Other",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds descriptions to an LDAP Response packet for debugging
|
||||||
|
func addLDAPDescriptions(packet *ber.Packet) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = NewError(ErrorDebugging, errors.New("ldap: cannot process packet to add descriptions"))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
packet.Description = "LDAP Response"
|
||||||
|
packet.Children[0].Description = "Message ID"
|
||||||
|
|
||||||
|
application := packet.Children[1].Tag
|
||||||
|
packet.Children[1].Description = ApplicationMap[application]
|
||||||
|
|
||||||
|
switch application {
|
||||||
|
case ApplicationBindRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationBindResponse:
|
||||||
|
addDefaultLDAPResponseDescriptions(packet)
|
||||||
|
case ApplicationUnbindRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationSearchRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationSearchResultEntry:
|
||||||
|
packet.Children[1].Children[0].Description = "Object Name"
|
||||||
|
packet.Children[1].Children[1].Description = "Attributes"
|
||||||
|
for _, child := range packet.Children[1].Children[1].Children {
|
||||||
|
child.Description = "Attribute"
|
||||||
|
child.Children[0].Description = "Attribute Name"
|
||||||
|
child.Children[1].Description = "Attribute Values"
|
||||||
|
for _, grandchild := range child.Children[1].Children {
|
||||||
|
grandchild.Description = "Attribute Value"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(packet.Children) == 3 {
|
||||||
|
addControlDescriptions(packet.Children[2])
|
||||||
|
}
|
||||||
|
case ApplicationSearchResultDone:
|
||||||
|
addDefaultLDAPResponseDescriptions(packet)
|
||||||
|
case ApplicationModifyRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationModifyResponse:
|
||||||
|
case ApplicationAddRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationAddResponse:
|
||||||
|
case ApplicationDelRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationDelResponse:
|
||||||
|
case ApplicationModifyDNRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationModifyDNResponse:
|
||||||
|
case ApplicationCompareRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationCompareResponse:
|
||||||
|
case ApplicationAbandonRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationSearchResultReference:
|
||||||
|
case ApplicationExtendedRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationExtendedResponse:
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addControlDescriptions(packet *ber.Packet) {
|
||||||
|
packet.Description = "Controls"
|
||||||
|
for _, child := range packet.Children {
|
||||||
|
child.Description = "Control"
|
||||||
|
child.Children[0].Description = "Control Type (" + ControlTypeMap[child.Children[0].Value.(string)] + ")"
|
||||||
|
value := child.Children[1]
|
||||||
|
if len(child.Children) == 3 {
|
||||||
|
child.Children[1].Description = "Criticality"
|
||||||
|
value = child.Children[2]
|
||||||
|
}
|
||||||
|
value.Description = "Control Value"
|
||||||
|
|
||||||
|
switch child.Children[0].Value.(string) {
|
||||||
|
case ControlTypePaging:
|
||||||
|
value.Description += " (Paging)"
|
||||||
|
if value.Value != nil {
|
||||||
|
valueChildren := ber.DecodePacket(value.Data.Bytes())
|
||||||
|
value.Data.Truncate(0)
|
||||||
|
value.Value = nil
|
||||||
|
valueChildren.Children[1].Value = valueChildren.Children[1].Data.Bytes()
|
||||||
|
value.AppendChild(valueChildren)
|
||||||
|
}
|
||||||
|
value.Children[0].Description = "Real Search Control Value"
|
||||||
|
value.Children[0].Children[0].Description = "Paging Size"
|
||||||
|
value.Children[0].Children[1].Description = "Cookie"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRequestDescriptions(packet *ber.Packet) {
|
||||||
|
packet.Description = "LDAP Request"
|
||||||
|
packet.Children[0].Description = "Message ID"
|
||||||
|
packet.Children[1].Description = ApplicationMap[packet.Children[1].Tag]
|
||||||
|
if len(packet.Children) == 3 {
|
||||||
|
addControlDescriptions(packet.Children[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addDefaultLDAPResponseDescriptions(packet *ber.Packet) {
|
||||||
|
resultCode := packet.Children[1].Children[0].Value.(uint64)
|
||||||
|
packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[uint8(resultCode)] + ")"
|
||||||
|
packet.Children[1].Children[1].Description = "Matched DN"
|
||||||
|
packet.Children[1].Children[2].Description = "Error Message"
|
||||||
|
if len(packet.Children[1].Children) > 3 {
|
||||||
|
packet.Children[1].Children[3].Description = "Referral"
|
||||||
|
}
|
||||||
|
if len(packet.Children) == 3 {
|
||||||
|
addControlDescriptions(packet.Children[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DebugBinaryFile(fileName string) error {
|
||||||
|
file, err := ioutil.ReadFile(fileName)
|
||||||
|
if err != nil {
|
||||||
|
return NewError(ErrorDebugging, err)
|
||||||
|
}
|
||||||
|
ber.PrintBytes(file, "")
|
||||||
|
packet := ber.DecodePacket(file)
|
||||||
|
addLDAPDescriptions(packet)
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
Err error
|
||||||
|
ResultCode uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewError(resultCode uint8, err error) error {
|
||||||
|
return &Error{ResultCode: resultCode, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLDAPResultCode(packet *ber.Packet) (code uint8, description string) {
|
||||||
|
if len(packet.Children) >= 2 {
|
||||||
|
response := packet.Children[1]
|
||||||
|
if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) == 3 {
|
||||||
|
return uint8(response.Children[0].Value.(uint64)), response.Children[2].Value.(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrorNetwork, "Invalid packet format"
|
||||||
|
}
|
123
modules/ldap/ldap_test.go
Normal file
123
modules/ldap/ldap_test.go
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ldapServer = "ldap.itd.umich.edu"
|
||||||
|
var ldapPort = uint16(389)
|
||||||
|
var baseDN = "dc=umich,dc=edu"
|
||||||
|
var filter = []string{
|
||||||
|
"(cn=cis-fac)",
|
||||||
|
"(&(objectclass=rfc822mailgroup)(cn=*Computer*))",
|
||||||
|
"(&(objectclass=rfc822mailgroup)(cn=*Mathematics*))"}
|
||||||
|
var attributes = []string{
|
||||||
|
"cn",
|
||||||
|
"description"}
|
||||||
|
|
||||||
|
func TestConnect(t *testing.T) {
|
||||||
|
fmt.Printf("TestConnect: starting...\n")
|
||||||
|
l, err := Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
fmt.Printf("TestConnect: finished...\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearch(t *testing.T) {
|
||||||
|
fmt.Printf("TestSearch: starting...\n")
|
||||||
|
l, err := Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
searchRequest := NewSearchRequest(
|
||||||
|
baseDN,
|
||||||
|
ScopeWholeSubtree, DerefAlways, 0, 0, false,
|
||||||
|
filter[0],
|
||||||
|
attributes,
|
||||||
|
nil)
|
||||||
|
|
||||||
|
sr, err := l.Search(searchRequest)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("TestSearch: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearchWithPaging(t *testing.T) {
|
||||||
|
fmt.Printf("TestSearchWithPaging: starting...\n")
|
||||||
|
l, err := Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
err = l.Bind("", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
searchRequest := NewSearchRequest(
|
||||||
|
baseDN,
|
||||||
|
ScopeWholeSubtree, DerefAlways, 0, 0, false,
|
||||||
|
filter[1],
|
||||||
|
attributes,
|
||||||
|
nil)
|
||||||
|
sr, err := l.SearchWithPaging(searchRequest, 5)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("TestSearchWithPaging: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testMultiGoroutineSearch(t *testing.T, l *Conn, results chan *SearchResult, i int) {
|
||||||
|
searchRequest := NewSearchRequest(
|
||||||
|
baseDN,
|
||||||
|
ScopeWholeSubtree, DerefAlways, 0, 0, false,
|
||||||
|
filter[i],
|
||||||
|
attributes,
|
||||||
|
nil)
|
||||||
|
sr, err := l.Search(searchRequest)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
results <- nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
results <- sr
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMultiGoroutineSearch(t *testing.T) {
|
||||||
|
fmt.Printf("TestMultiGoroutineSearch: starting...\n")
|
||||||
|
l, err := Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
results := make([]chan *SearchResult, len(filter))
|
||||||
|
for i := range filter {
|
||||||
|
results[i] = make(chan *SearchResult)
|
||||||
|
go testMultiGoroutineSearch(t, l, results[i], i)
|
||||||
|
}
|
||||||
|
for i := range filter {
|
||||||
|
sr := <-results[i]
|
||||||
|
if sr == nil {
|
||||||
|
t.Errorf("Did not receive results from goroutine for %q", filter[i])
|
||||||
|
} else {
|
||||||
|
fmt.Printf("TestMultiGoroutineSearch(%d): %s -> num of entries = %d\n", i, filter[i], len(sr.Entries))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
156
modules/ldap/modify.go
Normal file
156
modules/ldap/modify.go
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
//
|
||||||
|
// File contains Modify functionality
|
||||||
|
//
|
||||||
|
// https://tools.ietf.org/html/rfc4511
|
||||||
|
//
|
||||||
|
// ModifyRequest ::= [APPLICATION 6] SEQUENCE {
|
||||||
|
// object LDAPDN,
|
||||||
|
// changes SEQUENCE OF change SEQUENCE {
|
||||||
|
// operation ENUMERATED {
|
||||||
|
// add (0),
|
||||||
|
// delete (1),
|
||||||
|
// replace (2),
|
||||||
|
// ... },
|
||||||
|
// modification PartialAttribute } }
|
||||||
|
//
|
||||||
|
// PartialAttribute ::= SEQUENCE {
|
||||||
|
// type AttributeDescription,
|
||||||
|
// vals SET OF value AttributeValue }
|
||||||
|
//
|
||||||
|
// AttributeDescription ::= LDAPString
|
||||||
|
// -- Constrained to <attributedescription>
|
||||||
|
// -- [RFC4512]
|
||||||
|
//
|
||||||
|
// AttributeValue ::= OCTET STRING
|
||||||
|
//
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/asn1-ber"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AddAttribute = 0
|
||||||
|
DeleteAttribute = 1
|
||||||
|
ReplaceAttribute = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
type PartialAttribute struct {
|
||||||
|
attrType string
|
||||||
|
attrVals []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PartialAttribute) encode() *ber.Packet {
|
||||||
|
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "PartialAttribute")
|
||||||
|
seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, p.attrType, "Type"))
|
||||||
|
set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue")
|
||||||
|
for _, value := range p.attrVals {
|
||||||
|
set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals"))
|
||||||
|
}
|
||||||
|
seq.AppendChild(set)
|
||||||
|
return seq
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModifyRequest struct {
|
||||||
|
dn string
|
||||||
|
addAttributes []PartialAttribute
|
||||||
|
deleteAttributes []PartialAttribute
|
||||||
|
replaceAttributes []PartialAttribute
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ModifyRequest) Add(attrType string, attrVals []string) {
|
||||||
|
m.addAttributes = append(m.addAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ModifyRequest) Delete(attrType string, attrVals []string) {
|
||||||
|
m.deleteAttributes = append(m.deleteAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ModifyRequest) Replace(attrType string, attrVals []string) {
|
||||||
|
m.replaceAttributes = append(m.replaceAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m ModifyRequest) encode() *ber.Packet {
|
||||||
|
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request")
|
||||||
|
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.dn, "DN"))
|
||||||
|
changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes")
|
||||||
|
for _, attribute := range m.addAttributes {
|
||||||
|
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
|
||||||
|
change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(AddAttribute), "Operation"))
|
||||||
|
change.AppendChild(attribute.encode())
|
||||||
|
changes.AppendChild(change)
|
||||||
|
}
|
||||||
|
for _, attribute := range m.deleteAttributes {
|
||||||
|
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
|
||||||
|
change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(DeleteAttribute), "Operation"))
|
||||||
|
change.AppendChild(attribute.encode())
|
||||||
|
changes.AppendChild(change)
|
||||||
|
}
|
||||||
|
for _, attribute := range m.replaceAttributes {
|
||||||
|
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
|
||||||
|
change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(ReplaceAttribute), "Operation"))
|
||||||
|
change.AppendChild(attribute.encode())
|
||||||
|
changes.AppendChild(change)
|
||||||
|
}
|
||||||
|
request.AppendChild(changes)
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewModifyRequest(
|
||||||
|
dn string,
|
||||||
|
) *ModifyRequest {
|
||||||
|
return &ModifyRequest{
|
||||||
|
dn: dn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
|
||||||
|
messageID := l.nextMessageID()
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
|
||||||
|
packet.AppendChild(modifyRequest.encode())
|
||||||
|
|
||||||
|
l.Debug.PrintPacket(packet)
|
||||||
|
|
||||||
|
channel, err := l.sendMessage(packet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if channel == nil {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: could not send message"))
|
||||||
|
}
|
||||||
|
defer l.finishMessage(messageID)
|
||||||
|
|
||||||
|
l.Debug.Printf("%d: waiting for response", messageID)
|
||||||
|
packet = <-channel
|
||||||
|
l.Debug.Printf("%d: got response %p", messageID, packet)
|
||||||
|
if packet == nil {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
if packet.Children[1].Tag == ApplicationModifyResponse {
|
||||||
|
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||||
|
if resultCode != 0 {
|
||||||
|
return NewError(resultCode, errors.New(resultDescription))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Debug.Printf("%d: returning", messageID)
|
||||||
|
return nil
|
||||||
|
}
|
350
modules/ldap/search.go
Normal file
350
modules/ldap/search.go
Normal file
|
@ -0,0 +1,350 @@
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
//
|
||||||
|
// File contains Search functionality
|
||||||
|
//
|
||||||
|
// https://tools.ietf.org/html/rfc4511
|
||||||
|
//
|
||||||
|
// SearchRequest ::= [APPLICATION 3] SEQUENCE {
|
||||||
|
// baseObject LDAPDN,
|
||||||
|
// scope ENUMERATED {
|
||||||
|
// baseObject (0),
|
||||||
|
// singleLevel (1),
|
||||||
|
// wholeSubtree (2),
|
||||||
|
// ... },
|
||||||
|
// derefAliases ENUMERATED {
|
||||||
|
// neverDerefAliases (0),
|
||||||
|
// derefInSearching (1),
|
||||||
|
// derefFindingBaseObj (2),
|
||||||
|
// derefAlways (3) },
|
||||||
|
// sizeLimit INTEGER (0 .. maxInt),
|
||||||
|
// timeLimit INTEGER (0 .. maxInt),
|
||||||
|
// typesOnly BOOLEAN,
|
||||||
|
// filter Filter,
|
||||||
|
// attributes AttributeSelection }
|
||||||
|
//
|
||||||
|
// AttributeSelection ::= SEQUENCE OF selector LDAPString
|
||||||
|
// -- The LDAPString is constrained to
|
||||||
|
// -- <attributeSelector> in Section 4.5.1.8
|
||||||
|
//
|
||||||
|
// Filter ::= CHOICE {
|
||||||
|
// and [0] SET SIZE (1..MAX) OF filter Filter,
|
||||||
|
// or [1] SET SIZE (1..MAX) OF filter Filter,
|
||||||
|
// not [2] Filter,
|
||||||
|
// equalityMatch [3] AttributeValueAssertion,
|
||||||
|
// substrings [4] SubstringFilter,
|
||||||
|
// greaterOrEqual [5] AttributeValueAssertion,
|
||||||
|
// lessOrEqual [6] AttributeValueAssertion,
|
||||||
|
// present [7] AttributeDescription,
|
||||||
|
// approxMatch [8] AttributeValueAssertion,
|
||||||
|
// extensibleMatch [9] MatchingRuleAssertion,
|
||||||
|
// ... }
|
||||||
|
//
|
||||||
|
// SubstringFilter ::= SEQUENCE {
|
||||||
|
// type AttributeDescription,
|
||||||
|
// substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
|
||||||
|
// initial [0] AssertionValue, -- can occur at most once
|
||||||
|
// any [1] AssertionValue,
|
||||||
|
// final [2] AssertionValue } -- can occur at most once
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// MatchingRuleAssertion ::= SEQUENCE {
|
||||||
|
// matchingRule [1] MatchingRuleId OPTIONAL,
|
||||||
|
// type [2] AttributeDescription OPTIONAL,
|
||||||
|
// matchValue [3] AssertionValue,
|
||||||
|
// dnAttributes [4] BOOLEAN DEFAULT FALSE }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/asn1-ber"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ScopeBaseObject = 0
|
||||||
|
ScopeSingleLevel = 1
|
||||||
|
ScopeWholeSubtree = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
var ScopeMap = map[int]string{
|
||||||
|
ScopeBaseObject: "Base Object",
|
||||||
|
ScopeSingleLevel: "Single Level",
|
||||||
|
ScopeWholeSubtree: "Whole Subtree",
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
NeverDerefAliases = 0
|
||||||
|
DerefInSearching = 1
|
||||||
|
DerefFindingBaseObj = 2
|
||||||
|
DerefAlways = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
var DerefMap = map[int]string{
|
||||||
|
NeverDerefAliases: "NeverDerefAliases",
|
||||||
|
DerefInSearching: "DerefInSearching",
|
||||||
|
DerefFindingBaseObj: "DerefFindingBaseObj",
|
||||||
|
DerefAlways: "DerefAlways",
|
||||||
|
}
|
||||||
|
|
||||||
|
type Entry struct {
|
||||||
|
DN string
|
||||||
|
Attributes []*EntryAttribute
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entry) GetAttributeValues(attribute string) []string {
|
||||||
|
for _, attr := range e.Attributes {
|
||||||
|
if attr.Name == attribute {
|
||||||
|
return attr.Values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entry) GetAttributeValue(attribute string) string {
|
||||||
|
values := e.GetAttributeValues(attribute)
|
||||||
|
if len(values) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return values[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entry) Print() {
|
||||||
|
fmt.Printf("DN: %s\n", e.DN)
|
||||||
|
for _, attr := range e.Attributes {
|
||||||
|
attr.Print()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entry) PrettyPrint(indent int) {
|
||||||
|
fmt.Printf("%sDN: %s\n", strings.Repeat(" ", indent), e.DN)
|
||||||
|
for _, attr := range e.Attributes {
|
||||||
|
attr.PrettyPrint(indent + 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type EntryAttribute struct {
|
||||||
|
Name string
|
||||||
|
Values []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EntryAttribute) Print() {
|
||||||
|
fmt.Printf("%s: %s\n", e.Name, e.Values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EntryAttribute) PrettyPrint(indent int) {
|
||||||
|
fmt.Printf("%s%s: %s\n", strings.Repeat(" ", indent), e.Name, e.Values)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SearchResult struct {
|
||||||
|
Entries []*Entry
|
||||||
|
Referrals []string
|
||||||
|
Controls []Control
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SearchResult) Print() {
|
||||||
|
for _, entry := range s.Entries {
|
||||||
|
entry.Print()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SearchResult) PrettyPrint(indent int) {
|
||||||
|
for _, entry := range s.Entries {
|
||||||
|
entry.PrettyPrint(indent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SearchRequest struct {
|
||||||
|
BaseDN string
|
||||||
|
Scope int
|
||||||
|
DerefAliases int
|
||||||
|
SizeLimit int
|
||||||
|
TimeLimit int
|
||||||
|
TypesOnly bool
|
||||||
|
Filter string
|
||||||
|
Attributes []string
|
||||||
|
Controls []Control
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SearchRequest) encode() (*ber.Packet, error) {
|
||||||
|
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationSearchRequest, nil, "Search Request")
|
||||||
|
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, s.BaseDN, "Base DN"))
|
||||||
|
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(s.Scope), "Scope"))
|
||||||
|
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(s.DerefAliases), "Deref Aliases"))
|
||||||
|
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(s.SizeLimit), "Size Limit"))
|
||||||
|
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(s.TimeLimit), "Time Limit"))
|
||||||
|
request.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, s.TypesOnly, "Types Only"))
|
||||||
|
// compile and encode filter
|
||||||
|
filterPacket, err := CompileFilter(s.Filter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
request.AppendChild(filterPacket)
|
||||||
|
// encode attributes
|
||||||
|
attributesPacket := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes")
|
||||||
|
for _, attribute := range s.Attributes {
|
||||||
|
attributesPacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute"))
|
||||||
|
}
|
||||||
|
request.AppendChild(attributesPacket)
|
||||||
|
return request, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSearchRequest(
|
||||||
|
BaseDN string,
|
||||||
|
Scope, DerefAliases, SizeLimit, TimeLimit int,
|
||||||
|
TypesOnly bool,
|
||||||
|
Filter string,
|
||||||
|
Attributes []string,
|
||||||
|
Controls []Control,
|
||||||
|
) *SearchRequest {
|
||||||
|
return &SearchRequest{
|
||||||
|
BaseDN: BaseDN,
|
||||||
|
Scope: Scope,
|
||||||
|
DerefAliases: DerefAliases,
|
||||||
|
SizeLimit: SizeLimit,
|
||||||
|
TimeLimit: TimeLimit,
|
||||||
|
TypesOnly: TypesOnly,
|
||||||
|
Filter: Filter,
|
||||||
|
Attributes: Attributes,
|
||||||
|
Controls: Controls,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) {
|
||||||
|
if searchRequest.Controls == nil {
|
||||||
|
searchRequest.Controls = make([]Control, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pagingControl := NewControlPaging(pagingSize)
|
||||||
|
searchRequest.Controls = append(searchRequest.Controls, pagingControl)
|
||||||
|
searchResult := new(SearchResult)
|
||||||
|
for {
|
||||||
|
result, err := l.Search(searchRequest)
|
||||||
|
l.Debug.Printf("Looking for Paging Control...")
|
||||||
|
if err != nil {
|
||||||
|
return searchResult, err
|
||||||
|
}
|
||||||
|
if result == nil {
|
||||||
|
return searchResult, NewError(ErrorNetwork, errors.New("ldap: packet not received"))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range result.Entries {
|
||||||
|
searchResult.Entries = append(searchResult.Entries, entry)
|
||||||
|
}
|
||||||
|
for _, referral := range result.Referrals {
|
||||||
|
searchResult.Referrals = append(searchResult.Referrals, referral)
|
||||||
|
}
|
||||||
|
for _, control := range result.Controls {
|
||||||
|
searchResult.Controls = append(searchResult.Controls, control)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Debug.Printf("Looking for Paging Control...")
|
||||||
|
pagingResult := FindControl(result.Controls, ControlTypePaging)
|
||||||
|
if pagingResult == nil {
|
||||||
|
pagingControl = nil
|
||||||
|
l.Debug.Printf("Could not find paging control. Breaking...")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
cookie := pagingResult.(*ControlPaging).Cookie
|
||||||
|
if len(cookie) == 0 {
|
||||||
|
pagingControl = nil
|
||||||
|
l.Debug.Printf("Could not find cookie. Breaking...")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pagingControl.SetCookie(cookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pagingControl != nil {
|
||||||
|
l.Debug.Printf("Abandoning Paging...")
|
||||||
|
pagingControl.PagingSize = 0
|
||||||
|
l.Search(searchRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
return searchResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
|
||||||
|
messageID := l.nextMessageID()
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
|
||||||
|
// encode search request
|
||||||
|
encodedSearchRequest, err := searchRequest.encode()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
packet.AppendChild(encodedSearchRequest)
|
||||||
|
// encode search controls
|
||||||
|
if searchRequest.Controls != nil {
|
||||||
|
packet.AppendChild(encodeControls(searchRequest.Controls))
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Debug.PrintPacket(packet)
|
||||||
|
|
||||||
|
channel, err := l.sendMessage(packet)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if channel == nil {
|
||||||
|
return nil, NewError(ErrorNetwork, errors.New("ldap: could not send message"))
|
||||||
|
}
|
||||||
|
defer l.finishMessage(messageID)
|
||||||
|
|
||||||
|
result := &SearchResult{
|
||||||
|
Entries: make([]*Entry, 0),
|
||||||
|
Referrals: make([]string, 0),
|
||||||
|
Controls: make([]Control, 0)}
|
||||||
|
|
||||||
|
foundSearchResultDone := false
|
||||||
|
for !foundSearchResultDone {
|
||||||
|
l.Debug.Printf("%d: waiting for response", messageID)
|
||||||
|
packet = <-channel
|
||||||
|
l.Debug.Printf("%d: got response %p", messageID, packet)
|
||||||
|
if packet == nil {
|
||||||
|
return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch packet.Children[1].Tag {
|
||||||
|
case 4:
|
||||||
|
entry := new(Entry)
|
||||||
|
entry.DN = packet.Children[1].Children[0].Value.(string)
|
||||||
|
for _, child := range packet.Children[1].Children[1].Children {
|
||||||
|
attr := new(EntryAttribute)
|
||||||
|
attr.Name = child.Children[0].Value.(string)
|
||||||
|
for _, value := range child.Children[1].Children {
|
||||||
|
attr.Values = append(attr.Values, value.Value.(string))
|
||||||
|
}
|
||||||
|
entry.Attributes = append(entry.Attributes, attr)
|
||||||
|
}
|
||||||
|
result.Entries = append(result.Entries, entry)
|
||||||
|
case 5:
|
||||||
|
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||||
|
if resultCode != 0 {
|
||||||
|
return result, NewError(resultCode, errors.New(resultDescription))
|
||||||
|
}
|
||||||
|
if len(packet.Children) == 3 {
|
||||||
|
for _, child := range packet.Children[2].Children {
|
||||||
|
result.Controls = append(result.Controls, DecodeControl(child))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foundSearchResultDone = true
|
||||||
|
case 19:
|
||||||
|
result.Referrals = append(result.Referrals, packet.Children[1].Children[0].Value.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l.Debug.Printf("%d: returning", messageID)
|
||||||
|
return result, nil
|
||||||
|
}
|
|
@ -87,6 +87,12 @@ func Fatal(skip int, format string, v ...interface{}) {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Close() {
|
||||||
|
for _, l := range loggers {
|
||||||
|
l.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// .___ __ _____
|
// .___ __ _____
|
||||||
// | | _____/ |_ ____________/ ____\____ ____ ____
|
// | | _____/ |_ ____________/ ____\____ ____ ____
|
||||||
// | |/ \ __\/ __ \_ __ \ __\\__ \ _/ ___\/ __ \
|
// | |/ \ __\/ __ \_ __ \ __\\__ \ _/ ___\/ __ \
|
||||||
|
|
844
modules/mahonia/8bit.go
Normal file
844
modules/mahonia/8bit.go
Normal file
|
@ -0,0 +1,844 @@
|
||||||
|
package mahonia
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Converters for simple 8-bit character sets.
|
||||||
|
|
||||||
|
type eightBitInfo struct {
|
||||||
|
Name string
|
||||||
|
Aliases []string
|
||||||
|
|
||||||
|
// the character used for characters that can't be converted
|
||||||
|
SubstitutionChar byte
|
||||||
|
|
||||||
|
// a string containing all 256 characters, in order.
|
||||||
|
Repertoire string
|
||||||
|
|
||||||
|
// used to synchronize unpacking Repertoire into the conversion tables
|
||||||
|
once *sync.Once
|
||||||
|
|
||||||
|
// true if the first 128 characters are the same as US-ASCII
|
||||||
|
asciiCompatible bool
|
||||||
|
|
||||||
|
byte2char [256]rune
|
||||||
|
char2byte map[rune]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
const asciiRepertoire = "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f"
|
||||||
|
|
||||||
|
func (info *eightBitInfo) register() {
|
||||||
|
var cs Charset
|
||||||
|
cs.Name = info.Name
|
||||||
|
cs.Aliases = info.Aliases
|
||||||
|
|
||||||
|
info.once = new(sync.Once)
|
||||||
|
|
||||||
|
cs.NewDecoder = func() Decoder {
|
||||||
|
info.once.Do(func() { info.unpack() })
|
||||||
|
|
||||||
|
return func(p []byte) (c rune, size int, status Status) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
status = NO_ROOM
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c = info.byte2char[p[0]]
|
||||||
|
|
||||||
|
if c == 0xfffd {
|
||||||
|
status = INVALID_CHAR
|
||||||
|
} else {
|
||||||
|
status = SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
size = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cs.NewEncoder = func() Encoder {
|
||||||
|
info.once.Do(func() { info.unpack() })
|
||||||
|
|
||||||
|
return func(p []byte, c rune) (size int, status Status) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
status = NO_ROOM
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if c < 128 && info.asciiCompatible {
|
||||||
|
p[0] = byte(c)
|
||||||
|
return 1, SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
b, ok := info.char2byte[c]
|
||||||
|
if !ok {
|
||||||
|
b = info.SubstitutionChar
|
||||||
|
status = INVALID_CHAR
|
||||||
|
} else {
|
||||||
|
status = SUCCESS
|
||||||
|
}
|
||||||
|
p[0] = b
|
||||||
|
size = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterCharset(&cs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (info *eightBitInfo) unpack() {
|
||||||
|
info.asciiCompatible = info.Repertoire[:128] == asciiRepertoire
|
||||||
|
|
||||||
|
info.char2byte = make(map[rune]byte, 256)
|
||||||
|
i := 0
|
||||||
|
for _, c := range info.Repertoire {
|
||||||
|
info.byte2char[i] = c
|
||||||
|
if c != 0xfffd {
|
||||||
|
info.char2byte[c] = byte(i)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i != 256 {
|
||||||
|
panic(fmt.Errorf("%s has only %d characters", info.Name, i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for i := 0; i < len(eightBitCharsets); i++ {
|
||||||
|
eightBitCharsets[i].register()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var eightBitCharsets = []eightBitInfo{
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-2",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u0104\u02d8\u0141\u00a4\u013d\u015a\u00a7\u00a8\u0160\u015e\u0164\u0179\u00ad\u017d\u017b\u00b0\u0105\u02db\u0142\u00b4\u013e\u015b\u02c7\u00b8\u0161\u015f\u0165\u017a\u02dd\u017e\u017c\u0154\u00c1\u00c2\u0102\u00c4\u0139\u0106\u00c7\u010c\u00c9\u0118\u00cb\u011a\u00cd\u00ce\u010e\u0110\u0143\u0147\u00d3\u00d4\u0150\u00d6\u00d7\u0158\u016e\u00da\u0170\u00dc\u00dd\u0162\u00df\u0155\u00e1\u00e2\u0103\u00e4\u013a\u0107\u00e7\u010d\u00e9\u0119\u00eb\u011b\u00ed\u00ee\u010f\u0111\u0144\u0148\u00f3\u00f4\u0151\u00f6\u00f7\u0159\u016f\u00fa\u0171\u00fc\u00fd\u0163\u02d9",
|
||||||
|
Aliases: []string{"ISO_8859-2:1987", "iso-ir-101", "latin2", "l2", "csISOLatin2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-3",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u0126\u02d8\u00a3\u00a4\ufffd\u0124\u00a7\u00a8\u0130\u015e\u011e\u0134\u00ad\ufffd\u017b\u00b0\u0127\u00b2\u00b3\u00b4\u00b5\u0125\u00b7\u00b8\u0131\u015f\u011f\u0135\u00bd\ufffd\u017c\u00c0\u00c1\u00c2\ufffd\u00c4\u010a\u0108\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\ufffd\u00d1\u00d2\u00d3\u00d4\u0120\u00d6\u00d7\u011c\u00d9\u00da\u00db\u00dc\u016c\u015c\u00df\u00e0\u00e1\u00e2\ufffd\u00e4\u010b\u0109\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\ufffd\u00f1\u00f2\u00f3\u00f4\u0121\u00f6\u00f7\u011d\u00f9\u00fa\u00fb\u00fc\u016d\u015d\u02d9",
|
||||||
|
Aliases: []string{"ISO_8859-3:1988", "iso-ir-109", "latin3", "l3", "csISOLatin3"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-4",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u0104\u0138\u0156\u00a4\u0128\u013b\u00a7\u00a8\u0160\u0112\u0122\u0166\u00ad\u017d\u00af\u00b0\u0105\u02db\u0157\u00b4\u0129\u013c\u02c7\u00b8\u0161\u0113\u0123\u0167\u014a\u017e\u014b\u0100\u00c1\u00c2\u00c3\u00c4\u00c5\u00c6\u012e\u010c\u00c9\u0118\u00cb\u0116\u00cd\u00ce\u012a\u0110\u0145\u014c\u0136\u00d4\u00d5\u00d6\u00d7\u00d8\u0172\u00da\u00db\u00dc\u0168\u016a\u00df\u0101\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u012f\u010d\u00e9\u0119\u00eb\u0117\u00ed\u00ee\u012b\u0111\u0146\u014d\u0137\u00f4\u00f5\u00f6\u00f7\u00f8\u0173\u00fa\u00fb\u00fc\u0169\u016b\u02d9",
|
||||||
|
Aliases: []string{"ISO_8859-4:1988", "iso-ir-110", "latin4", "l4", "csISOLatin4"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-5",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u0401\u0402\u0403\u0404\u0405\u0406\u0407\u0408\u0409\u040a\u040b\u040c\u00ad\u040e\u040f\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f\u2116\u0451\u0452\u0453\u0454\u0455\u0456\u0457\u0458\u0459\u045a\u045b\u045c\u00a7\u045e\u045f",
|
||||||
|
Aliases: []string{"ISO_8859-5:1988", "iso-ir-144", "cyrillic", "csISOLatinCyrillic"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-6",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\ufffd\ufffd\ufffd\u00a4\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u060c\u00ad\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u061b\ufffd\ufffd\ufffd\u061f\ufffd\u0621\u0622\u0623\u0624\u0625\u0626\u0627\u0628\u0629\u062a\u062b\u062c\u062d\u062e\u062f\u0630\u0631\u0632\u0633\u0634\u0635\u0636\u0637\u0638\u0639\u063a\ufffd\ufffd\ufffd\ufffd\ufffd\u0640\u0641\u0642\u0643\u0644\u0645\u0646\u0647\u0648\u0649\u064a\u064b\u064c\u064d\u064e\u064f\u0650\u0651\u0652\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd",
|
||||||
|
Aliases: []string{"ISO_8859-6:1987", "iso-ir-127", "ECMA-114", "ASMO-708", "arabic", "csISOLatinArabic"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-7",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u2018\u2019\u00a3\u20ac\u20af\u00a6\u00a7\u00a8\u00a9\u037a\u00ab\u00ac\u00ad\ufffd\u2015\u00b0\u00b1\u00b2\u00b3\u0384\u0385\u0386\u00b7\u0388\u0389\u038a\u00bb\u038c\u00bd\u038e\u038f\u0390\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\ufffd\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab\u03ac\u03ad\u03ae\u03af\u03b0\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c2\u03c3\u03c4\u03c5\u03c6\u03c7\u03c8\u03c9\u03ca\u03cb\u03cc\u03cd\u03ce\ufffd",
|
||||||
|
Aliases: []string{"ISO_8859-7:2003", "iso-ir-126", "ELOT_928", "ECMA-118", "greek", "greek8", "csISOLatinGreek"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-8",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\ufffd\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7\u00a8\u00a9\u00d7\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00f7\u00bb\u00bc\u00bd\u00be\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u2017\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\ufffd\ufffd\u200e\u200f\ufffd",
|
||||||
|
Aliases: []string{"ISO_8859-8:1999", "iso-ir-138", "hebrew", "csISOLatinHebrew"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-9",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u00a1\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7\u00a8\u00a9\u00aa\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00ba\u00bb\u00bc\u00bd\u00be\u00bf\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u011e\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d7\u00d8\u00d9\u00da\u00db\u00dc\u0130\u015e\u00df\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u011f\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f7\u00f8\u00f9\u00fa\u00fb\u00fc\u0131\u015f\u00ff",
|
||||||
|
Aliases: []string{"ISO_8859-9:1999", "iso-ir-148", "latin5", "l5", "csISOLatin5"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-10",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u0104\u0112\u0122\u012a\u0128\u0136\u00a7\u013b\u0110\u0160\u0166\u017d\u00ad\u016a\u014a\u00b0\u0105\u0113\u0123\u012b\u0129\u0137\u00b7\u013c\u0111\u0161\u0167\u017e\u2015\u016b\u014b\u0100\u00c1\u00c2\u00c3\u00c4\u00c5\u00c6\u012e\u010c\u00c9\u0118\u00cb\u0116\u00cd\u00ce\u00cf\u00d0\u0145\u014c\u00d3\u00d4\u00d5\u00d6\u0168\u00d8\u0172\u00da\u00db\u00dc\u00dd\u00de\u00df\u0101\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u012f\u010d\u00e9\u0119\u00eb\u0117\u00ed\u00ee\u00ef\u00f0\u0146\u014d\u00f3\u00f4\u00f5\u00f6\u0169\u00f8\u0173\u00fa\u00fb\u00fc\u00fd\u00fe\u0138",
|
||||||
|
Aliases: []string{"iso_8859-10:1992", "l6", "iso-ir-157", "latin6", "csISOLatin6"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-11",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u0e01\u0e02\u0e03\u0e04\u0e05\u0e06\u0e07\u0e08\u0e09\u0e0a\u0e0b\u0e0c\u0e0d\u0e0e\u0e0f\u0e10\u0e11\u0e12\u0e13\u0e14\u0e15\u0e16\u0e17\u0e18\u0e19\u0e1a\u0e1b\u0e1c\u0e1d\u0e1e\u0e1f\u0e20\u0e21\u0e22\u0e23\u0e24\u0e25\u0e26\u0e27\u0e28\u0e29\u0e2a\u0e2b\u0e2c\u0e2d\u0e2e\u0e2f\u0e30\u0e31\u0e32\u0e33\u0e34\u0e35\u0e36\u0e37\u0e38\u0e39\u0e3a\ufffd\ufffd\ufffd\ufffd\u0e3f\u0e40\u0e41\u0e42\u0e43\u0e44\u0e45\u0e46\u0e47\u0e48\u0e49\u0e4a\u0e4b\u0e4c\u0e4d\u0e4e\u0e4f\u0e50\u0e51\u0e52\u0e53\u0e54\u0e55\u0e56\u0e57\u0e58\u0e59\u0e5a\u0e5b\ufffd\ufffd\ufffd\ufffd",
|
||||||
|
Aliases: []string{"iso_8859-11:2001", "Latin/Thai", "TIS-620"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-13",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u201d\u00a2\u00a3\u00a4\u201e\u00a6\u00a7\u00d8\u00a9\u0156\u00ab\u00ac\u00ad\u00ae\u00c6\u00b0\u00b1\u00b2\u00b3\u201c\u00b5\u00b6\u00b7\u00f8\u00b9\u0157\u00bb\u00bc\u00bd\u00be\u00e6\u0104\u012e\u0100\u0106\u00c4\u00c5\u0118\u0112\u010c\u00c9\u0179\u0116\u0122\u0136\u012a\u013b\u0160\u0143\u0145\u00d3\u014c\u00d5\u00d6\u00d7\u0172\u0141\u015a\u016a\u00dc\u017b\u017d\u00df\u0105\u012f\u0101\u0107\u00e4\u00e5\u0119\u0113\u010d\u00e9\u017a\u0117\u0123\u0137\u012b\u013c\u0161\u0144\u0146\u00f3\u014d\u00f5\u00f6\u00f7\u0173\u0142\u015b\u016b\u00fc\u017c\u017e\u2019",
|
||||||
|
Aliases: []string{"latin7", "Baltic Rim"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-14",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u1e02\u1e03\u00a3\u010a\u010b\u1e0a\u00a7\u1e80\u00a9\u1e82\u1e0b\u1ef2\u00ad\u00ae\u0178\u1e1e\u1e1f\u0120\u0121\u1e40\u1e41\u00b6\u1e56\u1e81\u1e57\u1e83\u1e60\u1ef3\u1e84\u1e85\u1e61\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u0174\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u1e6a\u00d8\u00d9\u00da\u00db\u00dc\u00dd\u0176\u00df\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u0175\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u1e6b\u00f8\u00f9\u00fa\u00fb\u00fc\u00fd\u0177\u00ff",
|
||||||
|
Aliases: []string{"iso-ir-199", "ISO_8859-14:1998", "latin8", "iso-celtic", "l8"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-15",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u00a1\u00a2\u00a3\u20ac\u00a5\u0160\u00a7\u0161\u00a9\u00aa\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u017d\u00b5\u00b6\u00b7\u017e\u00b9\u00ba\u00bb\u0152\u0153\u0178\u00bf\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u00d0\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d7\u00d8\u00d9\u00da\u00db\u00dc\u00dd\u00de\u00df\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u00f0\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f7\u00f8\u00f9\u00fa\u00fb\u00fc\u00fd\u00fe\u00ff",
|
||||||
|
Aliases: []string{"Latin-9"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-16",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u0104\u0105\u0141\u20ac\u201e\u0160\u00a7\u0161\u00a9\u0218\u00ab\u0179\u00ad\u017a\u017b\u00b0\u00b1\u010c\u0142\u017d\u201d\u00b6\u00b7\u017e\u010d\u0219\u00bb\u0152\u0153\u0178\u017c\u00c0\u00c1\u00c2\u0102\u00c4\u0106\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u0110\u0143\u00d2\u00d3\u00d4\u0150\u00d6\u015a\u0170\u00d9\u00da\u00db\u00dc\u0118\u021a\u00df\u00e0\u00e1\u00e2\u0103\u00e4\u0107\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u0111\u0144\u00f2\u00f3\u00f4\u0151\u00f6\u015b\u0171\u00f9\u00fa\u00fb\u00fc\u0119\u021b\u00ff",
|
||||||
|
Aliases: []string{"iso-ir-226", "ISO_8859-16:2001", "latin10", "l10"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "macos-0_2-10.2",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u00c4\u00c5\u00c7\u00c9\u00d1\u00d6\u00dc\u00e1\u00e0\u00e2\u00e4\u00e3\u00e5\u00e7\u00e9\u00e8\u00ea\u00eb\u00ed\u00ec\u00ee\u00ef\u00f1\u00f3\u00f2\u00f4\u00f6\u00f5\u00fa\u00f9\u00fb\u00fc\u2020\u00b0\u00a2\u00a3\u00a7\u2022\u00b6\u00df\u00ae\u00a9\u2122\u00b4\u00a8\u2260\u00c6\u00d8\u221e\u00b1\u2264\u2265\u00a5\u00b5\u2202\u2211\u220f\u03c0\u222b\u00aa\u00ba\u03a9\u00e6\u00f8\u00bf\u00a1\u00ac\u221a\u0192\u2248\u2206\u00ab\u00bb\u2026\u00a0\u00c0\u00c3\u00d5\u0152\u0153\u2013\u2014\u201c\u201d\u2018\u2019\u00f7\u25ca\u00ff\u0178\u2044\u20ac\u2039\u203a\ufb01\ufb02\u2021\u00b7\u201a\u201e\u2030\u00c2\u00ca\u00c1\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u00d3\u00d4\uf8ff\u00d2\u00da\u00db\u00d9\u0131\u02c6\u02dc\u00af\u02d8\u02d9\u02da\u00b8\u02dd\u02db\u02c7",
|
||||||
|
Aliases: []string{"macos-0_2-10.2", "macintosh", "mac", "csMacintosh", "windows-10000", "macroman"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "macos-6_2-10.4",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u00c4\u00b9\u00b2\u00c9\u00b3\u00d6\u00dc\u0385\u00e0\u00e2\u00e4\u0384\u00a8\u00e7\u00e9\u00e8\u00ea\u00eb\u00a3\u2122\u00ee\u00ef\u2022\u00bd\u2030\u00f4\u00f6\u00a6\u20ac\u00f9\u00fb\u00fc\u2020\u0393\u0394\u0398\u039b\u039e\u03a0\u00df\u00ae\u00a9\u03a3\u03aa\u00a7\u2260\u00b0\u00b7\u0391\u00b1\u2264\u2265\u00a5\u0392\u0395\u0396\u0397\u0399\u039a\u039c\u03a6\u03ab\u03a8\u03a9\u03ac\u039d\u00ac\u039f\u03a1\u2248\u03a4\u00ab\u00bb\u2026\u00a0\u03a5\u03a7\u0386\u0388\u0153\u2013\u2015\u201c\u201d\u2018\u2019\u00f7\u0389\u038a\u038c\u038e\u03ad\u03ae\u03af\u03cc\u038f\u03cd\u03b1\u03b2\u03c8\u03b4\u03b5\u03c6\u03b3\u03b7\u03b9\u03be\u03ba\u03bb\u03bc\u03bd\u03bf\u03c0\u03ce\u03c1\u03c3\u03c4\u03b8\u03c9\u03c2\u03c7\u03c5\u03b6\u03ca\u03cb\u0390\u03b0\u00ad",
|
||||||
|
Aliases: []string{"macos-6_2-10.4", "x-mac-greek", "windows-10006", "macgr"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "macos-7_3-10.2",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u2020\u00b0\u0490\u00a3\u00a7\u2022\u00b6\u0406\u00ae\u00a9\u2122\u0402\u0452\u2260\u0403\u0453\u221e\u00b1\u2264\u2265\u0456\u00b5\u0491\u0408\u0404\u0454\u0407\u0457\u0409\u0459\u040a\u045a\u0458\u0405\u00ac\u221a\u0192\u2248\u2206\u00ab\u00bb\u2026\u00a0\u040b\u045b\u040c\u045c\u0455\u2013\u2014\u201c\u201d\u2018\u2019\u00f7\u201e\u040e\u045e\u040f\u045f\u2116\u0401\u0451\u044f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u20ac",
|
||||||
|
Aliases: []string{"macos-7_3-10.2", "x-mac-cyrillic", "windows-10007", "mac-cyrillic", "maccy"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "macos-29-10.2",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u00c4\u0100\u0101\u00c9\u0104\u00d6\u00dc\u00e1\u0105\u010c\u00e4\u010d\u0106\u0107\u00e9\u0179\u017a\u010e\u00ed\u010f\u0112\u0113\u0116\u00f3\u0117\u00f4\u00f6\u00f5\u00fa\u011a\u011b\u00fc\u2020\u00b0\u0118\u00a3\u00a7\u2022\u00b6\u00df\u00ae\u00a9\u2122\u0119\u00a8\u2260\u0123\u012e\u012f\u012a\u2264\u2265\u012b\u0136\u2202\u2211\u0142\u013b\u013c\u013d\u013e\u0139\u013a\u0145\u0146\u0143\u00ac\u221a\u0144\u0147\u2206\u00ab\u00bb\u2026\u00a0\u0148\u0150\u00d5\u0151\u014c\u2013\u2014\u201c\u201d\u2018\u2019\u00f7\u25ca\u014d\u0154\u0155\u0158\u2039\u203a\u0159\u0156\u0157\u0160\u201a\u201e\u0161\u015a\u015b\u00c1\u0164\u0165\u00cd\u017d\u017e\u016a\u00d3\u00d4\u016b\u016e\u00da\u016f\u0170\u0171\u0172\u0173\u00dd\u00fd\u0137\u017b\u0141\u017c\u0122\u02c7",
|
||||||
|
Aliases: []string{"macos-29-10.2", "x-mac-centraleurroman", "windows-10029", "x-mac-ce", "macce", "maccentraleurope"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "macos-35-10.2",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u00c4\u00c5\u00c7\u00c9\u00d1\u00d6\u00dc\u00e1\u00e0\u00e2\u00e4\u00e3\u00e5\u00e7\u00e9\u00e8\u00ea\u00eb\u00ed\u00ec\u00ee\u00ef\u00f1\u00f3\u00f2\u00f4\u00f6\u00f5\u00fa\u00f9\u00fb\u00fc\u2020\u00b0\u00a2\u00a3\u00a7\u2022\u00b6\u00df\u00ae\u00a9\u2122\u00b4\u00a8\u2260\u00c6\u00d8\u221e\u00b1\u2264\u2265\u00a5\u00b5\u2202\u2211\u220f\u03c0\u222b\u00aa\u00ba\u03a9\u00e6\u00f8\u00bf\u00a1\u00ac\u221a\u0192\u2248\u2206\u00ab\u00bb\u2026\u00a0\u00c0\u00c3\u00d5\u0152\u0153\u2013\u2014\u201c\u201d\u2018\u2019\u00f7\u25ca\u00ff\u0178\u011e\u011f\u0130\u0131\u015e\u015f\u2021\u00b7\u201a\u201e\u2030\u00c2\u00ca\u00c1\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u00d3\u00d4\uf8ff\u00d2\u00da\u00db\u00d9\uf8a0\u02c6\u02dc\u00af\u02d8\u02d9\u02da\u00b8\u02dd\u02db\u02c7",
|
||||||
|
Aliases: []string{"macos-35-10.2", "x-mac-turkish", "windows-10081", "mactr"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "windows-1250",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u20ac\ufffd\u201a\ufffd\u201e\u2026\u2020\u2021\ufffd\u2030\u0160\u2039\u015a\u0164\u017d\u0179\ufffd\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffd\u2122\u0161\u203a\u015b\u0165\u017e\u017a\u00a0\u02c7\u02d8\u0141\u00a4\u0104\u00a6\u00a7\u00a8\u00a9\u015e\u00ab\u00ac\u00ad\u00ae\u017b\u00b0\u00b1\u02db\u0142\u00b4\u00b5\u00b6\u00b7\u00b8\u0105\u015f\u00bb\u013d\u02dd\u013e\u017c\u0154\u00c1\u00c2\u0102\u00c4\u0139\u0106\u00c7\u010c\u00c9\u0118\u00cb\u011a\u00cd\u00ce\u010e\u0110\u0143\u0147\u00d3\u00d4\u0150\u00d6\u00d7\u0158\u016e\u00da\u0170\u00dc\u00dd\u0162\u00df\u0155\u00e1\u00e2\u0103\u00e4\u013a\u0107\u00e7\u010d\u00e9\u0119\u00eb\u011b\u00ed\u00ee\u010f\u0111\u0144\u0148\u00f3\u00f4\u0151\u00f6\u00f7\u0159\u016f\u00fa\u0171\u00fc\u00fd\u0163\u02d9",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "windows-1251",
|
||||||
|
Aliases: []string{"CP1251"},
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0402\u0403\u201a\u0453\u201e\u2026\u2020\u2021\u20ac\u2030\u0409\u2039\u040a\u040c\u040b\u040f\u0452\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffd\u2122\u0459\u203a\u045a\u045c\u045b\u045f\u00a0\u040e\u045e\u0408\u00a4\u0490\u00a6\u00a7\u0401\u00a9\u0404\u00ab\u00ac\u00ad\u00ae\u0407\u00b0\u00b1\u0406\u0456\u0491\u00b5\u00b6\u00b7\u0451\u2116\u0454\u00bb\u0458\u0405\u0455\u0457\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "windows-1252",
|
||||||
|
Aliases: []string{"cp1252"},
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u20ac\ufffd\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160\u2039\u0152\ufffd\u017d\ufffd\ufffd\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u0161\u203a\u0153\ufffd\u017e\u0178\u00a0\u00a1\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7\u00a8\u00a9\u00aa\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00ba\u00bb\u00bc\u00bd\u00be\u00bf\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u00d0\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d7\u00d8\u00d9\u00da\u00db\u00dc\u00dd\u00de\u00df\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u00f0\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f7\u00f8\u00f9\u00fa\u00fb\u00fc\u00fd\u00fe\u00ff",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "windows-1253",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u20ac\ufffd\u201a\u0192\u201e\u2026\u2020\u2021\ufffd\u2030\ufffd\u2039\ufffd\ufffd\ufffd\ufffd\ufffd\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffd\u2122\ufffd\u203a\ufffd\ufffd\ufffd\ufffd\u00a0\u0385\u0386\u00a3\u00a4\u00a5\u00a6\u00a7\u00a8\u00a9\ufffd\u00ab\u00ac\u00ad\u00ae\u2015\u00b0\u00b1\u00b2\u00b3\u0384\u00b5\u00b6\u00b7\u0388\u0389\u038a\u00bb\u038c\u00bd\u038e\u038f\u0390\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\ufffd\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab\u03ac\u03ad\u03ae\u03af\u03b0\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c2\u03c3\u03c4\u03c5\u03c6\u03c7\u03c8\u03c9\u03ca\u03cb\u03cc\u03cd\u03ce\ufffd",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "windows-1254",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u20ac\ufffd\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160\u2039\u0152\ufffd\ufffd\ufffd\ufffd\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u0161\u203a\u0153\ufffd\ufffd\u0178\u00a0\u00a1\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7\u00a8\u00a9\u00aa\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00ba\u00bb\u00bc\u00bd\u00be\u00bf\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u011e\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d7\u00d8\u00d9\u00da\u00db\u00dc\u0130\u015e\u00df\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u011f\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f7\u00f8\u00f9\u00fa\u00fb\u00fc\u0131\u015f\u00ff",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "windows-1255",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u20ac\ufffd\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\ufffd\u2039\ufffd\ufffd\ufffd\ufffd\ufffd\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\ufffd\u203a\ufffd\ufffd\ufffd\ufffd\u00a0\u00a1\u00a2\u00a3\u20aa\u00a5\u00a6\u00a7\u00a8\u00a9\u00d7\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00f7\u00bb\u00bc\u00bd\u00be\u00bf\u05b0\u05b1\u05b2\u05b3\u05b4\u05b5\u05b6\u05b7\u05b8\u05b9\ufffd\u05bb\u05bc\u05bd\u05be\u05bf\u05c0\u05c1\u05c2\u05c3\u05f0\u05f1\u05f2\u05f3\u05f4\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\ufffd\ufffd\u200e\u200f\ufffd",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "windows-1256",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u20ac\u067e\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0679\u2039\u0152\u0686\u0698\u0688\u06af\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u06a9\u2122\u0691\u203a\u0153\u200c\u200d\u06ba\u00a0\u060c\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7\u00a8\u00a9\u06be\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u061b\u00bb\u00bc\u00bd\u00be\u061f\u06c1\u0621\u0622\u0623\u0624\u0625\u0626\u0627\u0628\u0629\u062a\u062b\u062c\u062d\u062e\u062f\u0630\u0631\u0632\u0633\u0634\u0635\u0636\u00d7\u0637\u0638\u0639\u063a\u0640\u0641\u0642\u0643\u00e0\u0644\u00e2\u0645\u0646\u0647\u0648\u00e7\u00e8\u00e9\u00ea\u00eb\u0649\u064a\u00ee\u00ef\u064b\u064c\u064d\u064e\u00f4\u064f\u0650\u00f7\u0651\u00f9\u0652\u00fb\u00fc\u200e\u200f\u06d2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "windows-1257",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u20ac\ufffd\u201a\ufffd\u201e\u2026\u2020\u2021\ufffd\u2030\ufffd\u2039\ufffd\u00a8\u02c7\u00b8\ufffd\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffd\u2122\ufffd\u203a\ufffd\u00af\u02db\ufffd\u00a0\ufffd\u00a2\u00a3\u00a4\ufffd\u00a6\u00a7\u00d8\u00a9\u0156\u00ab\u00ac\u00ad\u00ae\u00c6\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00f8\u00b9\u0157\u00bb\u00bc\u00bd\u00be\u00e6\u0104\u012e\u0100\u0106\u00c4\u00c5\u0118\u0112\u010c\u00c9\u0179\u0116\u0122\u0136\u012a\u013b\u0160\u0143\u0145\u00d3\u014c\u00d5\u00d6\u00d7\u0172\u0141\u015a\u016a\u00dc\u017b\u017d\u00df\u0105\u012f\u0101\u0107\u00e4\u00e5\u0119\u0113\u010d\u00e9\u017a\u0117\u0123\u0137\u012b\u013c\u0161\u0144\u0146\u00f3\u014d\u00f5\u00f6\u00f7\u0173\u0142\u015b\u016b\u00fc\u017c\u017e\u02d9",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "windows-1258",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u20ac\ufffd\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\ufffd\u2039\u0152\ufffd\ufffd\ufffd\ufffd\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\ufffd\u203a\u0153\ufffd\ufffd\u0178\u00a0\u00a1\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7\u00a8\u00a9\u00aa\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00ba\u00bb\u00bc\u00bd\u00be\u00bf\u00c0\u00c1\u00c2\u0102\u00c4\u00c5\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u0300\u00cd\u00ce\u00cf\u0110\u00d1\u0309\u00d3\u00d4\u01a0\u00d6\u00d7\u00d8\u00d9\u00da\u00db\u00dc\u01af\u0303\u00df\u00e0\u00e1\u00e2\u0103\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u0301\u00ed\u00ee\u00ef\u0111\u00f1\u0323\u00f3\u00f4\u01a1\u00f6\u00f7\u00f8\u00f9\u00fa\u00fb\u00fc\u01b0\u20ab\u00ff",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "windows-874",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u20ac\ufffd\ufffd\ufffd\ufffd\u2026\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u00a0\u0e01\u0e02\u0e03\u0e04\u0e05\u0e06\u0e07\u0e08\u0e09\u0e0a\u0e0b\u0e0c\u0e0d\u0e0e\u0e0f\u0e10\u0e11\u0e12\u0e13\u0e14\u0e15\u0e16\u0e17\u0e18\u0e19\u0e1a\u0e1b\u0e1c\u0e1d\u0e1e\u0e1f\u0e20\u0e21\u0e22\u0e23\u0e24\u0e25\u0e26\u0e27\u0e28\u0e29\u0e2a\u0e2b\u0e2c\u0e2d\u0e2e\u0e2f\u0e30\u0e31\u0e32\u0e33\u0e34\u0e35\u0e36\u0e37\u0e38\u0e39\u0e3a\ufffd\ufffd\ufffd\ufffd\u0e3f\u0e40\u0e41\u0e42\u0e43\u0e44\u0e45\u0e46\u0e47\u0e48\u0e49\u0e4a\u0e4b\u0e4c\u0e4d\u0e4e\u0e4f\u0e50\u0e51\u0e52\u0e53\u0e54\u0e55\u0e56\u0e57\u0e58\u0e59\u0e5a\u0e5b\ufffd\ufffd\ufffd\ufffd",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "IBM037",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3\u00e5\u00e7\u00f1\u00a2.<(+|&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df!$*);\u00ac-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00a6,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc`:#@'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u00a4\u00b5~stuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae^\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be[]\u00af\u00a8\u00b4\u00d7{ABCDEFGHI\u00ad\u00f4\u00f6\u00f2\u00f3\u00f5}JKLMNOPQR\u00b9\u00fb\u00fc\u00f9\u00fa\u00ff\\\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"cp037", "ebcdic-cp-us", "ebcdic-cp-ca", "ebcdic-cp-wt", "ebcdic-cp-nl", "csIBM037"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-273_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2{\u00e0\u00e1\u00e3\u00e5\u00e7\u00f1\u00c4.<(+!&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec~\u00dc$*);^-/\u00c2[\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00f6,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc`:#\u00a7'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u00a4\u00b5\u00dfstuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9@\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\u00b4\u00d7\u00e4ABCDEFGHI\u00ad\u00f4\u00a6\u00f2\u00f3\u00f5\u00fcJKLMNOPQR\u00b9\u00fb}\u00f9\u00fa\u00ff\u00d6\u00f7STUVWXYZ\u00b2\u00d4\\\u00d2\u00d3\u00d50123456789\u00b3\u00db]\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-273_P100-1995", "ibm-273", "IBM273", "CP273", "csIBM273", "ebcdic-de", "273"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-277_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3}\u00e7\u00f1#.<(+!&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df\u00a4\u00c5*);^-/\u00c2\u00c4\u00c0\u00c1\u00c3$\u00c7\u00d1\u00f8,%_>?\u00a6\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc`:\u00c6\u00d8'=\"@abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba{\u00b8[]\u00b5\u00fcstuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\u00b4\u00d7\u00e6ABCDEFGHI\u00ad\u00f4\u00f6\u00f2\u00f3\u00f5\u00e5JKLMNOPQR\u00b9\u00fb~\u00f9\u00fa\u00ff\\\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-277_P100-1995", "ibm-277", "IBM277", "cp277", "EBCDIC-CP-DK", "EBCDIC-CP-NO", "csIBM277", "ebcdic-dk", "277"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-278_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2{\u00e0\u00e1\u00e3}\u00e7\u00f1\u00a7.<(+!&`\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df\u00a4\u00c5*);^-/\u00c2#\u00c0\u00c1\u00c3$\u00c7\u00d1\u00f6,%_>?\u00f8\\\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u00e9:\u00c4\u00d6'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6]\u00b5\u00fcstuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9[\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\u00b4\u00d7\u00e4ABCDEFGHI\u00ad\u00f4\u00a6\u00f2\u00f3\u00f5\u00e5JKLMNOPQR\u00b9\u00fb~\u00f9\u00fa\u00ff\u00c9\u00f7STUVWXYZ\u00b2\u00d4@\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-278_P100-1995", "ibm-278", "IBM278", "cp278", "ebcdic-cp-fi", "ebcdic-cp-se", "csIBM278", "ebcdic-sv", "278"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-280_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4{\u00e1\u00e3\u00e5\\\u00f1\u00b0.<(+!&]\u00ea\u00eb}\u00ed\u00ee\u00ef~\u00df\u00e9$*);^-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00f2,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u00f9:\u00a3\u00a7'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1[jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u00a4\u00b5\u00ecstuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2#\u00a5\u00b7\u00a9@\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\u00b4\u00d7\u00e0ABCDEFGHI\u00ad\u00f4\u00f6\u00a6\u00f3\u00f5\u00e8JKLMNOPQR\u00b9\u00fb\u00fc`\u00fa\u00ff\u00e7\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-280_P100-1995", "ibm-280", "IBM280", "CP280", "ebcdic-cp-it", "csIBM280", "280"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-284_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3\u00e5\u00e7\u00a6[.<(+|&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df]$*);\u00ac-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7#\u00f1,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc`:\u00d1@'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u00a4\u00b5\u00a8stuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be^!\u00af~\u00b4\u00d7{ABCDEFGHI\u00ad\u00f4\u00f6\u00f2\u00f3\u00f5}JKLMNOPQR\u00b9\u00fb\u00fc\u00f9\u00fa\u00ff\\\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-284_P100-1995", "ibm-284", "IBM284", "CP284", "ebcdic-cp-es", "csIBM284", "cpibm284", "284"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-285_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3\u00e5\u00e7\u00f1$.<(+|&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df!\u00a3*);\u00ac-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00a6,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc`:#@'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u00a4\u00b5\u00afstuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2[\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be^]~\u00a8\u00b4\u00d7{ABCDEFGHI\u00ad\u00f4\u00f6\u00f2\u00f3\u00f5}JKLMNOPQR\u00b9\u00fb\u00fc\u00f9\u00fa\u00ff\\\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-285_P100-1995", "ibm-285", "IBM285", "CP285", "ebcdic-cp-gb", "csIBM285", "cpibm285", "ebcdic-gb", "285"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-290_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \uff61\uff62\uff63\uff64\uff65\uff66\uff67\uff68\uff69\u00a3.<(+|&\uff6a\uff6b\uff6c\uff6d\uff6e\uff6f\ufffd\uff70\ufffd!\u00a5*);\u00ac-/abcdefgh\ufffd,%_>?[ijklmnop`:#@'=\"]\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\uff7aq\uff7b\uff7c\uff7d\uff7e\uff7f\uff80\uff81\uff82\uff83\uff84\uff85\uff86\uff87\uff88\uff89r\ufffd\uff8a\uff8b\uff8c~\u203e\uff8d\uff8e\uff8f\uff90\uff91\uff92\uff93\uff94\uff95s\uff96\uff97\uff98\uff99^\u00a2\\tuvwxyz\uff9a\uff9b\uff9c\uff9d\uff9e\uff9f{ABCDEFGHI\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd}JKLMNOPQR\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd$\ufffdSTUVWXYZ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd0123456789\ufffd\ufffd\ufffd\ufffd\ufffd\u009f",
|
||||||
|
Aliases: []string{"ibm-290_P100-1995", "ibm-290", "IBM290", "cp290", "EBCDIC-JP-kana", "csIBM290"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-297_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4@\u00e1\u00e3\u00e5\\\u00f1\u00b0.<(+!&{\u00ea\u00eb}\u00ed\u00ee\u00ef\u00ec\u00df\u00a7$*);^-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00f9,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u00b5:\u00a3\u00e0'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1[jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u00a4`\u00a8stuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2#\u00a5\u00b7\u00a9]\u00b6\u00bc\u00bd\u00be\u00ac|\u00af~\u00b4\u00d7\u00e9ABCDEFGHI\u00ad\u00f4\u00f6\u00f2\u00f3\u00f5\u00e8JKLMNOPQR\u00b9\u00fb\u00fc\u00a6\u00fa\u00ff\u00e7\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-297_P100-1995", "ibm-297", "IBM297", "cp297", "ebcdic-cp-fr", "csIBM297", "cpibm297", "297"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-420_X120-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u0651\ufe7d\u0640\u200b\u0621\u0622\ufe82\u0623\u00a2.<(+|&\ufe84\u0624\ufffd\ufffd\u0626\u0627\ufe8e\u0628\ufe91!$*);\u00ac-/\u0629\u062a\ufe97\u062b\ufe9b\u062c\ufe9f\u062d\u00a6,%_>?\ufea3\u062e\ufea7\u062f\u0630\u0631\u0632\u0633\ufeb3\u060c:#@'=\"\u0634abcdefghi\ufeb7\u0635\ufebb\u0636\ufebf\u0637\u0638jklmnopqr\u0639\ufeca\ufecb\ufecc\u063a\ufece\ufecf\u00f7stuvwxyz\ufed0\u0641\ufed3\u0642\ufed7\u0643\ufedb\u0644\ufef5\ufef6\ufef7\ufef8\ufffd\ufffd\ufefb\ufefc\ufedf\u0645\ufee3\u0646\ufee7\u0647\u061bABCDEFGHI\u00ad\ufeeb\ufffd\ufeec\ufffd\u0648\u061fJKLMNOPQR\u0649\ufef0\u064a\ufef2\ufef3\u0660\u00d7\ufffdSTUVWXYZ\u0661\u0662\ufffd\u0663\u0664\u06650123456789\ufffd\u0666\u0667\u0668\u0669\u009f",
|
||||||
|
Aliases: []string{"ibm-420_X120-1999", "ibm-420", "IBM420", "cp420", "ebcdic-cp-ar1", "csIBM420", "420"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "IBM424",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u00a2.<(+|&\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1!$*);\u00ac-/\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u00a6,%_>?\ufffd\u05ea\ufffd\ufffd\u00a0\ufffd\ufffd\ufffd\u2017`:#@'=\"\ufffdabcdefghi\u00ab\u00bb\ufffd\ufffd\ufffd\u00b1\u00b0jklmnopqr\ufffd\ufffd\ufffd\u00b8\ufffd\u00a4\u00b5~stuvwxyz\ufffd\ufffd\ufffd\ufffd\ufffd\u00ae^\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be[]\u00af\u00a8\u00b4\u00d7{ABCDEFGHI\u00ad\ufffd\ufffd\ufffd\ufffd\ufffd}JKLMNOPQR\u00b9\ufffd\ufffd\ufffd\ufffd\ufffd\\\u00f7STUVWXYZ\u00b2\ufffd\ufffd\ufffd\ufffd\ufffd0123456789\u00b3\ufffd\ufffd\ufffd\ufffd\u009f",
|
||||||
|
Aliases: []string{"cp424", "ebcdic-cp-he", "csIBM424"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "IBM437",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00a2\u00a3\u00a5\u20a7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u2310\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u00df\u0393\u03c0\u03a3\u03c3\u00b5\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u03c6\u03b5\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u00a0",
|
||||||
|
Aliases: []string{"cp437", "437", "csPC8CodePage437"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "IBM500",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3\u00e5\u00e7\u00f1[.<(+!&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df]$*);^-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00a6,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc`:#@'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u00a4\u00b5~stuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\u00b4\u00d7{ABCDEFGHI\u00ad\u00f4\u00f6\u00f2\u00f3\u00f5}JKLMNOPQR\u00b9\u00fb\u00fc\u00f9\u00fa\u00ff\\\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"CP500", "ebcdic-cp-be", "ebcdic-cp-ch", "csIBM500"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-720_P100-1997",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\ufffd\ufffd\u00e9\u00e2\ufffd\u00e0\ufffd\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\ufffd\ufffd\ufffd\ufffd\u0651\u0652\u00f4\u00a4\u0640\u00fb\u00f9\u0621\u0622\u0623\u0624\u00a3\u0625\u0626\u0627\u0628\u0629\u062a\u062b\u062c\u062d\u062e\u062f\u0630\u0631\u0632\u0633\u0634\u0635\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u0636\u0637\u0638\u0639\u063a\u0641\u00b5\u0642\u0643\u0644\u0645\u0646\u0647\u0648\u0649\u064a\u2261\u064b\u064c\u064d\u064e\u064f\u0650\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u00a0",
|
||||||
|
Aliases: []string{"ibm-720_P100-1997", "ibm-720", "windows-720", "DOS-720"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "IBM737",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c3\u03c2\u03c4\u03c5\u03c6\u03c7\u03c8\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03c9\u03ac\u03ad\u03ae\u03ca\u03af\u03cc\u03cd\u03cb\u03ce\u0386\u0388\u0389\u038a\u038c\u038e\u038f\u00b1\u2265\u2264\u03aa\u03ab\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u00a0",
|
||||||
|
Aliases: []string{"cp737", "cp737_DOSGreek"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "IBM775",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0106\u00fc\u00e9\u0101\u00e4\u0123\u00e5\u0107\u0142\u0113\u0156\u0157\u012b\u0179\u00c4\u00c5\u00c9\u00e6\u00c6\u014d\u00f6\u0122\u00a2\u015a\u015b\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u00a4\u0100\u012a\u00f3\u017b\u017c\u017a\u201d\u00a6\u00a9\u00ae\u00ac\u00bd\u00bc\u0141\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u0104\u010c\u0118\u0116\u2563\u2551\u2557\u255d\u012e\u0160\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u0172\u016a\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u017d\u0105\u010d\u0119\u0117\u012f\u0161\u0173\u016b\u017e\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u00d3\u00df\u014c\u0143\u00f5\u00d5\u00b5\u0144\u0136\u0137\u013b\u013c\u0146\u0112\u0145\u2019\u00ad\u00b1\u201c\u00be\u00b6\u00a7\u00f7\u201e\u00b0\u2219\u00b7\u00b9\u00b3\u00b2\u25a0\u00a0",
|
||||||
|
Aliases: []string{"cp775", "csPC775Baltic"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-803_P100-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd$.<(+|\u05d0\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd!\u00a2*);\u00ac-/\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd,%_>?\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd:#@'=\"\ufffd\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdABCDEFGHI\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdJKLMNOPQR\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdSTUVWXYZ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd0123456789\ufffd\ufffd\ufffd\ufffd\ufffd\u009f",
|
||||||
|
Aliases: []string{"ibm-803_P100-1999", "ibm-803", "cp803"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-838_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u0e01\u0e02\u0e03\u0e04\u0e05\u0e06\u0e07[\u00a2.<(+|&\u0e48\u0e08\u0e09\u0e0a\u0e0b\u0e0c\u0e0d\u0e0e]!$*);\u00ac-/\u0e0f\u0e10\u0e11\u0e12\u0e13\u0e14\u0e15^\u00a6,%_>?\u0e3f\u0e4e\u0e16\u0e17\u0e18\u0e19\u0e1a\u0e1b\u0e1c`:#@'=\"\u0e4fabcdefghi\u0e1d\u0e1e\u0e1f\u0e20\u0e21\u0e22\u0e5ajklmnopqr\u0e23\u0e24\u0e25\u0e26\u0e27\u0e28\u0e5b~stuvwxyz\u0e29\u0e2a\u0e2b\u0e2c\u0e2d\u0e2e\u0e50\u0e51\u0e52\u0e53\u0e54\u0e55\u0e56\u0e57\u0e58\u0e59\u0e2f\u0e30\u0e31\u0e32\u0e33\u0e34{ABCDEFGHI\u0e49\u0e35\u0e36\u0e37\u0e38\u0e39}JKLMNOPQR\u0e3a\u0e40\u0e41\u0e42\u0e43\u0e44\\\u0e4aSTUVWXYZ\u0e45\u0e46\u0e47\u0e48\u0e49\u0e4a0123456789\u0e4b\u0e4c\u0e4d\u0e4b\u0e4c\u009f",
|
||||||
|
Aliases: []string{"ibm-838_P100-1995", "ibm-838", "IBM838", "IBM-Thai", "csIBMThai", "cp838", "838", "ibm-9030"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "IBM850",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u00c1\u00c2\u00c0\u00a9\u2563\u2551\u2557\u255d\u00a2\u00a5\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u00e3\u00c3\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u00a4\u00f0\u00d0\u00ca\u00cb\u00c8\u0131\u00cd\u00ce\u00cf\u2518\u250c\u2588\u2584\u00a6\u00cc\u2580\u00d3\u00df\u00d4\u00d2\u00f5\u00d5\u00b5\u00fe\u00de\u00da\u00db\u00d9\u00fd\u00dd\u00af\u00b4\u00ad\u00b1\u2017\u00be\u00b6\u00a7\u00f7\u00b8\u00b0\u00a8\u00b7\u00b9\u00b3\u00b2\u25a0\u00a0",
|
||||||
|
Aliases: []string{"cp850", "850", "csPC850Multilingual"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-851_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u0386\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u0388\u00c4\u0389\u038a\ufffd\u038c\u00f4\u00f6\u038e\u00fb\u00f9\u038f\u00d6\u00dc\u03ac\u00a3\u03ad\u03ae\u03af\u03ca\u0390\u03cc\u03cd\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u00bd\u0398\u0399\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u039a\u039b\u039c\u039d\u2563\u2551\u2557\u255d\u039e\u039f\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u03a0\u03a1\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03b1\u03b2\u03b3\u2518\u250c\u2588\u2584\u03b4\u03b5\u2580\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c3\u03c2\u03c4\u00b4\u00ad\u00b1\u03c5\u03c6\u03c7\u00a7\u03c8\u00b8\u00b0\u00a8\u03c9\u03cb\u03b0\u03ce\u25a0\u00a0",
|
||||||
|
Aliases: []string{"ibm-851_P100-1995", "ibm-851", "IBM851", "cp851", "851", "csPC851"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "IBM852",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u00c7\u00fc\u00e9\u00e2\u00e4\u016f\u0107\u00e7\u0142\u00eb\u0150\u0151\u00ee\u0179\u00c4\u0106\u00c9\u0139\u013a\u00f4\u00f6\u013d\u013e\u015a\u015b\u00d6\u00dc\u0164\u0165\u0141\u00d7\u010d\u00e1\u00ed\u00f3\u00fa\u0104\u0105\u017d\u017e\u0118\u0119\u00ac\u017a\u010c\u015f\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u00c1\u00c2\u011a\u015e\u2563\u2551\u2557\u255d\u017b\u017c\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u0102\u0103\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u00a4\u0111\u0110\u010e\u00cb\u010f\u0147\u00cd\u00ce\u011b\u2518\u250c\u2588\u2584\u0162\u016e\u2580\u00d3\u00df\u00d4\u0143\u0144\u0148\u0160\u0161\u0154\u00da\u0155\u0170\u00fd\u00dd\u0163\u00b4\u00ad\u02dd\u02db\u02c7\u02d8\u00a7\u00f7\u00b8\u00b0\u00a8\u02d9\u0171\u0158\u0159\u25a0\u00a0",
|
||||||
|
Aliases: []string{"cp852", "852", "csPCp852"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "IBM855",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0452\u0402\u0453\u0403\u0451\u0401\u0454\u0404\u0455\u0405\u0456\u0406\u0457\u0407\u0458\u0408\u0459\u0409\u045a\u040a\u045b\u040b\u045c\u040c\u045e\u040e\u045f\u040f\u044e\u042e\u044a\u042a\u0430\u0410\u0431\u0411\u0446\u0426\u0434\u0414\u0435\u0415\u0444\u0424\u0433\u0413\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u0445\u0425\u0438\u0418\u2563\u2551\u2557\u255d\u0439\u0419\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u043a\u041a\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u00a4\u043b\u041b\u043c\u041c\u043d\u041d\u043e\u041e\u043f\u2518\u250c\u2588\u2584\u041f\u044f\u2580\u042f\u0440\u0420\u0441\u0421\u0442\u0422\u0443\u0423\u0436\u0416\u0432\u0412\u044c\u042c\u2116\u00ad\u044b\u042b\u0437\u0417\u0448\u0428\u044d\u042d\u0449\u0429\u0447\u0427\u00a7\u25a0\u00a0",
|
||||||
|
Aliases: []string{"cp855", "855", "csIBM855"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "IBM856",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\ufffd\u00a3\ufffd\u00d7\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u00ae\u00ac\u00bd\u00bc\ufffd\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\ufffd\ufffd\ufffd\u00a9\u2563\u2551\u2557\u255d\u00a2\u00a5\u2510\u2514\u2534\u252c\u251c\u2500\u253c\ufffd\ufffd\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u00a4\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u2518\u250c\u2588\u2584\u00a6\ufffd\u2580\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u00b5\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u00af\u00b4\u00ad\u00b1\u2017\u00be\u00b6\u00a7\u00f7\u00b8\u00b0\u00a8\u00b7\u00b9\u00b3\u00b2\u25a0\u00a0",
|
||||||
|
Aliases: []string{"cp856", "cp856_Hebrew_PC"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-857_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u0131\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u0130\u00d6\u00dc\u00f8\u00a3\u00d8\u015e\u015f\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u011e\u011f\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u00c1\u00c2\u00c0\u00a9\u2563\u2551\u2557\u255d\u00a2\u00a5\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u00e3\u00c3\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u00a4\u00ba\u00aa\u00ca\u00cb\u00c8\ufffd\u00cd\u00ce\u00cf\u2518\u250c\u2588\u2584\u00a6\u00cc\u2580\u00d3\u00df\u00d4\u00d2\u00f5\u00d5\u00b5\ufffd\u00d7\u00da\u00db\u00d9\u00ec\u00ff\u00af\u00b4\u00ad\u00b1\ufffd\u00be\u00b6\u00a7\u00f7\u00b8\u00b0\u00a8\u00b7\u00b9\u00b3\u00b2\u25a0\u00a0",
|
||||||
|
Aliases: []string{"ibm-857_P100-1995", "ibm-857", "IBM857", "cp857", "857", "csIBM857", "windows-857"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-858_P100-1997",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u00c1\u00c2\u00c0\u00a9\u2563\u2551\u2557\u255d\u00a2\u00a5\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u00e3\u00c3\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u00a4\u00f0\u00d0\u00ca\u00cb\u00c8\u20ac\u00cd\u00ce\u00cf\u2518\u250c\u2588\u2584\u00a6\u00cc\u2580\u00d3\u00df\u00d4\u00d2\u00f5\u00d5\u00b5\u00fe\u00de\u00da\u00db\u00d9\u00fd\u00dd\u00af\u00b4\u00ad\u00b1\u2017\u00be\u00b6\u00a7\u00f7\u00b8\u00b0\u00a8\u00b7\u00b9\u00b3\u00b2\u25a0\u00a0",
|
||||||
|
Aliases: []string{"ibm-858_P100-1997", "ibm-858", "IBM00858", "CCSID00858", "CP00858", "PC-Multilingual-850+euro", "cp858", "windows-858"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-860_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\u00c7\u00fc\u00e9\u00e2\u00e3\u00e0\u00c1\u00e7\u00ea\u00ca\u00e8\u00cd\u00d4\u00ec\u00c3\u00c2\u00c9\u00c0\u00c8\u00f4\u00f5\u00f2\u00da\u00f9\u00cc\u00d5\u00dc\u00a2\u00a3\u00d9\u20a7\u00d3\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00d2\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u00df\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u03c6\u03b5\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u00a0",
|
||||||
|
Aliases: []string{"ibm-860_P100-1995", "ibm-860", "IBM860", "cp860", "860", "csIBM860"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-861_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00d0\u00f0\u00de\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00fe\u00fb\u00dd\u00fd\u00d6\u00dc\u00f8\u00a3\u00d8\u20a7\u0192\u00e1\u00ed\u00f3\u00fa\u00c1\u00cd\u00d3\u00da\u00bf\u2310\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u00df\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u03c6\u03b5\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u00a0",
|
||||||
|
Aliases: []string{"ibm-861_P100-1995", "ibm-861", "IBM861", "cp861", "861", "cp-is", "csIBM861", "windows-861"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-862_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\u00a2\u00a3\u00a5\u20a7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u2310\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u00df\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u03c6\u03b5\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u00a0",
|
||||||
|
Aliases: []string{"ibm-862_P100-1995", "ibm-862", "IBM862", "cp862", "862", "csPC862LatinHebrew", "DOS-862", "windows-862"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-863_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\u00c7\u00fc\u00e9\u00e2\u00c2\u00e0\u00b6\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u2017\u00c0\u00a7\u00c9\u00c8\u00ca\u00f4\u00cb\u00cf\u00fb\u00f9\u00a4\u00d4\u00dc\u00a2\u00a3\u00d9\u00db\u0192\u00a6\u00b4\u00f3\u00fa\u00a8\u00b8\u00b3\u00af\u00ce\u2310\u00ac\u00bd\u00bc\u00be\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u00df\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u03c6\u03b5\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u00a0",
|
||||||
|
Aliases: []string{"ibm-863_P100-1995", "ibm-863", "IBM863", "cp863", "863", "csIBM863"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-864_X110-1999",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\u00b0\u00b7\u2219\u221a\u2592\u2500\u2502\u253c\u2524\u252c\u251c\u2534\u2510\u250c\u2514\u2518\u03b2\u221e\u03c6\u00b1\u00bd\u00bc\u2248\u00ab\u00bb\ufef7\ufef8\ufffd\ufffd\ufefb\ufefc\u200b\u00a0\u00ad\ufe82\u00a3\u00a4\ufe84\ufffd\ufffd\ufe8e\ufe8f\ufe95\ufe99\u060c\ufe9d\ufea1\ufea5\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669\ufed1\u061b\ufeb1\ufeb5\ufeb9\u061f\u00a2\ufe80\ufe81\ufe83\ufe85\ufeca\ufe8b\ufe8d\ufe91\ufe93\ufe97\ufe9b\ufe9f\ufea3\ufea7\ufea9\ufeab\ufead\ufeaf\ufeb3\ufeb7\ufebb\ufebf\ufec3\ufec7\ufecb\ufecf\u00a6\u00ac\u00f7\u00d7\ufec9\u0640\ufed3\ufed7\ufedb\ufedf\ufee3\ufee7\ufeeb\ufeed\ufeef\ufef3\ufebd\ufecc\ufece\ufecd\ufee1\ufe7d\ufe7c\ufee5\ufee9\ufeec\ufef0\ufef2\ufed0\ufed5\ufef5\ufef6\ufedd\ufed9\ufef1\u25a0\ufffd",
|
||||||
|
Aliases: []string{"ibm-864_X110-1999", "ibm-864", "IBM864", "cp864", "csIBM864"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-865_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u20a7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u2310\u00ac\u00bd\u00bc\u00a1\u00ab\u00a4\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u00df\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u03c6\u03b5\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u00a0",
|
||||||
|
Aliases: []string{"ibm-865_P100-1995", "ibm-865", "IBM865", "cp865", "865", "csIBM865"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "IBM866",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f\u0401\u0451\u0404\u0454\u0407\u0457\u040e\u045e\u00b0\u2219\u00b7\u221a\u2116\u00a4\u25a0\u00a0",
|
||||||
|
Aliases: []string{"cp866", "866", "csIBM866"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-867_P100-1998",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\u00a2\u00a3\u00a5\ufffd\u20aa\u200e\u200f\u202a\u202b\u202d\u202e\u202c\ufffd\ufffd\u2310\u00ac\u00bd\u00bc\u20ac\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u00df\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u03c6\u03b5\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u00a0",
|
||||||
|
Aliases: []string{"ibm-867_P100-1998", "ibm-867"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-868_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u060c\u061b\u061f\ufe81\ufe8d\ufe8e\uf8fb\ufe8f\ufe91\ufb56\ufb58\ufe93\ufe95\ufe97\ufb66\ufb68\ufe99\ufe9b\ufe9d\ufe9f\ufb7a\ufb7c\ufea1\ufea3\ufea5\ufea7\ufea9\ufb88\ufeab\ufead\ufb8c\ufeaf\ufb8a\ufeb1\ufeb3\ufeb5\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\ufeb7\ufeb9\ufebb\ufebd\u2563\u2551\u2557\u255d\ufebf\ufec3\u2510\u2514\u2534\u252c\u251c\u2500\u253c\ufec7\ufec9\u255a\u2554\u2569\u2566\u2560\u2550\u256c\ufeca\ufecb\ufecc\ufecd\ufece\ufecf\ufed0\ufed1\ufed3\ufed5\u2518\u250c\u2588\u2584\ufed7\ufb8e\u2580\ufedb\ufb92\ufb94\ufedd\ufedf\ufee0\ufee1\ufee3\ufb9e\ufee5\ufee7\ufe85\ufeed\ufba6\ufba8\ufba9\u00ad\ufbaa\ufe80\ufe89\ufe8a\ufe8b\ufbfc\ufbfd\ufbfe\ufbb0\ufbae\ufe7c\ufe7d\ufffd\u25a0\u00a0",
|
||||||
|
Aliases: []string{"ibm-868_P100-1995", "ibm-868", "IBM868", "CP868", "868", "csIBM868", "cp-ar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-869_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0386\ufffd\u0387\u00ac\u00a6\u2018\u2019\u0388\u2015\u0389\u038a\u03aa\u038c\ufffd\ufffd\u038e\u03ab\u00a9\u038f\u00b2\u00b3\u03ac\u00a3\u03ad\u03ae\u03af\u03ca\u0390\u03cc\u03cd\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u00bd\u0398\u0399\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u039a\u039b\u039c\u039d\u2563\u2551\u2557\u255d\u039e\u039f\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u03a0\u03a1\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03b1\u03b2\u03b3\u2518\u250c\u2588\u2584\u03b4\u03b5\u2580\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c3\u03c2\u03c4\u00b4\u00ad\u00b1\u03c5\u03c6\u03c7\u00a7\u03c8\u0385\u00b0\u00a8\u03c9\u03cb\u03b0\u03ce\u25a0\u00a0",
|
||||||
|
Aliases: []string{"ibm-869_P100-1995", "ibm-869", "IBM869", "cp869", "869", "cp-gr", "csIBM869", "windows-869"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-870_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u0163\u00e1\u0103\u010d\u00e7\u0107[.<(+!&\u00e9\u0119\u00eb\u016f\u00ed\u00ee\u013e\u013a\u00df]$*);^-/\u00c2\u00c4\u02dd\u00c1\u0102\u010c\u00c7\u0106|,%_>?\u02c7\u00c9\u0118\u00cb\u016e\u00cd\u00ce\u013d\u0139`:#@'=\"\u02d8abcdefghi\u015b\u0148\u0111\u00fd\u0159\u015f\u00b0jklmnopqr\u0142\u0144\u0161\u00b8\u02db\u00a4\u0105~stuvwxyz\u015a\u0147\u0110\u00dd\u0158\u015e\u02d9\u0104\u017c\u0162\u017b\u00a7\u017e\u017a\u017d\u0179\u0141\u0143\u0160\u00a8\u00b4\u00d7{ABCDEFGHI\u00ad\u00f4\u00f6\u0155\u00f3\u0151}JKLMNOPQR\u011a\u0171\u00fc\u0165\u00fa\u011b\\\u00f7STUVWXYZ\u010f\u00d4\u00d6\u0154\u00d3\u01500123456789\u010e\u0170\u00dc\u0164\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-870_P100-1995", "ibm-870", "IBM870", "CP870", "ebcdic-cp-roece", "ebcdic-cp-yu", "csIBM870"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-871_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3\u00e5\u00e7\u00f1\u00de.<(+!&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df\u00c6$*);\u00d6-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00a6,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u00f0:#\u00d0'=\"\u00d8abcdefghi\u00ab\u00bb`\u00fd{\u00b1\u00b0jklmnopqr\u00aa\u00ba}\u00b8]\u00a4\u00b5\u00f6stuvwxyz\u00a1\u00bf@\u00dd[\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\\\u00d7\u00feABCDEFGHI\u00ad\u00f4~\u00f2\u00f3\u00f5\u00e6JKLMNOPQR\u00b9\u00fb\u00fc\u00f9\u00fa\u00ff\u00b4\u00f7STUVWXYZ\u00b2\u00d4^\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-871_P100-1995", "ibm-871", "IBM871", "ebcdic-cp-is", "csIBM871", "CP871", "ebcdic-is", "871"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-874_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0e48\u0e01\u0e02\u0e03\u0e04\u0e05\u0e06\u0e07\u0e08\u0e09\u0e0a\u0e0b\u0e0c\u0e0d\u0e0e\u0e0f\u0e10\u0e11\u0e12\u0e13\u0e14\u0e15\u0e16\u0e17\u0e18\u0e19\u0e1a\u0e1b\u0e1c\u0e1d\u0e1e\u0e1f\u0e20\u0e21\u0e22\u0e23\u0e24\u0e25\u0e26\u0e27\u0e28\u0e29\u0e2a\u0e2b\u0e2c\u0e2d\u0e2e\u0e2f\u0e30\u0e31\u0e32\u0e33\u0e34\u0e35\u0e36\u0e37\u0e38\u0e39\u0e3a\u0e49\u0e4a\u0e4b\u0e4c\u0e3f\u0e40\u0e41\u0e42\u0e43\u0e44\u0e45\u0e46\u0e47\u0e48\u0e49\u0e4a\u0e4b\u0e4c\u0e4d\u0e4e\u0e4f\u0e50\u0e51\u0e52\u0e53\u0e54\u0e55\u0e56\u0e57\u0e58\u0e59\u0e5a\u0e5b\u00a2\u00ac\u00a6\u00a0",
|
||||||
|
Aliases: []string{"ibm-874_P100-1995", "ibm-874", "ibm-9066", "cp874", "tis620.2533", "eucTH"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-875_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399[.<(+!&\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\u03a3]$*);^-/\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab|,%_>?\u00a8\u0386\u0388\u0389\u00a0\u038a\u038c\u038e\u038f`:#@'=\"\u0385abcdefghi\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u00b0jklmnopqr\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u00b4~stuvwxyz\u03bd\u03be\u03bf\u03c0\u03c1\u03c3\u00a3\u03ac\u03ad\u03ae\u03ca\u03af\u03cc\u03cd\u03cb\u03ce\u03c2\u03c4\u03c5\u03c6\u03c7\u03c8{ABCDEFGHI\u00ad\u03c9\u0390\u03b0\u2018\u2015}JKLMNOPQR\u00b1\u00bd\ufffd\u0387\u2019\u00a6\\\ufffdSTUVWXYZ\u00b2\u00a7\ufffd\ufffd\u00ab\u00ac0123456789\u00b3\u00a9\ufffd\ufffd\u00bb\u009f",
|
||||||
|
Aliases: []string{"ibm-875_P100-1995", "ibm-875", "IBM875", "cp875", "875"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-901_P100-1999",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u201d\u00a2\u00a3\u20ac\u201e\u00a6\u00a7\u00d8\u00a9\u0156\u00ab\u00ac\u00ad\u00ae\u00c6\u00b0\u00b1\u00b2\u00b3\u201c\u00b5\u00b6\u00b7\u00f8\u00b9\u0157\u00bb\u00bc\u00bd\u00be\u00e6\u0104\u012e\u0100\u0106\u00c4\u00c5\u0118\u0112\u010c\u00c9\u0179\u0116\u0122\u0136\u012a\u013b\u0160\u0143\u0145\u00d3\u014c\u00d5\u00d6\u00d7\u0172\u0141\u015a\u016a\u00dc\u017b\u017d\u00df\u0105\u012f\u0101\u0107\u00e4\u00e5\u0119\u0113\u010d\u00e9\u017a\u0117\u0123\u0137\u012b\u013c\u0161\u0144\u0146\u00f3\u014d\u00f5\u00f6\u00f7\u0173\u0142\u015b\u016b\u00fc\u017c\u017e\u2019",
|
||||||
|
Aliases: []string{"ibm-901_P100-1999", "ibm-901"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-902_P100-1999",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u00a1\u00a2\u00a3\u20ac\u00a5\u00a6\u00a7\u00a8\u00a9\u00aa\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00ba\u00bb\u00bc\u00bd\u00be\u00bf\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u0160\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d7\u00d8\u00d9\u00da\u00db\u00dc\u00dd\u017d\u00df\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u0161\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f7\u00f8\u00f9\u00fa\u00fb\u00fc\u00fd\u017e\u00ff",
|
||||||
|
Aliases: []string{"ibm-902_P100-1999", "ibm-902"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-916_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\ufffd\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7\u00a8\u00a9\u00d7\u00ab\u00ac\u00ad\u00ae\u203e\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u2022\u00b8\u00b9\u00f7\u00bb\u00bc\u00bd\u00be\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u2017\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\ufffd\ufffd\ufffd\ufffd\ufffd",
|
||||||
|
Aliases: []string{"ibm-916_P100-1995", "ibm-916", "cp916", "916"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-918_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u060c\u061b\u061f\ufe81\ufe8d\ufe8e\uf8fb\ufe8f[.<(+!&\ufe91\ufb56\ufb58\ufe93\ufe95\ufe97\ufb66\ufb68\ufe99]$*);^-/\ufe9b\ufe9d\ufe9f\ufb7a\ufb7c\ufea1\ufea3\ufea5`,%_>?\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9:#@'=\"\ufea7abcdefghi\ufea9\ufb88\ufeab\ufead\ufb8c\ufeaf\ufb8ajklmnopqr\ufeb1\ufeb3\ufeb5\ufeb7\ufeb9\ufebb\ufebd~stuvwxyz\ufebf\ufec3\ufec7\ufec9\ufeca\ufecb\ufecc\ufecd\ufece\ufecf\ufed0\ufed1\ufed3\ufed5\ufed7\ufb8e\ufedb|\ufb92\ufb94\ufedd\ufedf{ABCDEFGHI\u00ad\ufee0\ufee1\ufee3\ufb9e\ufee5}JKLMNOPQR\ufee7\ufe85\ufeed\ufba6\ufba8\ufba9\\\ufbaaSTUVWXYZ\ufe80\ufe89\ufe8a\ufe8b\ufbfc\ufbfd0123456789\ufbfe\ufbb0\ufbae\ufe7c\ufe7d\u009f",
|
||||||
|
Aliases: []string{"ibm-918_P100-1995", "ibm-918", "IBM918", "CP918", "ebcdic-cp-ar2", "csIBM918"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-922_P100-1999",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u00a1\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7\u00a8\u00a9\u00aa\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00ba\u00bb\u00bc\u00bd\u00be\u00bf\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u0160\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d7\u00d8\u00d9\u00da\u00db\u00dc\u00dd\u017d\u00df\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u0161\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f7\u00f8\u00f9\u00fa\u00fb\u00fc\u00fd\u017e\u00ff",
|
||||||
|
Aliases: []string{"ibm-922_P100-1999", "ibm-922", "IBM922", "cp922", "922"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1006_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u060c\u061b\u00ad\u061f\ufe81\ufe8d\ufe8e\uf8fb\ufe8f\ufe91\ufb56\ufb58\ufe93\ufe95\ufe97\ufb66\ufb68\ufe99\ufe9b\ufe9d\ufe9f\ufb7a\ufb7c\ufea1\ufea3\ufea5\ufea7\ufea9\ufb88\ufeab\ufead\ufb8c\ufeaf\ufb8a\ufeb1\ufeb3\ufeb5\ufeb7\ufeb9\ufebb\ufebd\ufebf\ufec3\ufec7\ufec9\ufeca\ufecb\ufecc\ufecd\ufece\ufecf\ufed0\ufed1\ufed3\ufed5\ufed7\ufb8e\ufedb\ufb92\ufb94\ufedd\ufedf\ufee0\ufee1\ufee3\ufb9e\ufee5\ufee7\ufe85\ufeed\ufba6\ufba8\ufba9\ufbaa\ufe80\ufe89\ufe8a\ufe8b\ufbfc\ufbfd\ufbfe\ufbb0\ufbae\ufe7c\ufe7d",
|
||||||
|
Aliases: []string{"ibm-1006_P100-1995", "ibm-1006", "IBM1006", "cp1006", "1006"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1025_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u0452\u0453\u0451\u0454\u0455\u0456\u0457\u0458[.<(+!&\u0459\u045a\u045b\u045c\u045e\u045f\u042a\u2116\u0402]$*);^-/\u0403\u0401\u0404\u0405\u0406\u0407\u0408\u0409|,%_>?\u040a\u040b\u040c\u00ad\u040e\u040f\u044e\u0430\u0431`:#@'=\"\u0446abcdefghi\u0434\u0435\u0444\u0433\u0445\u0438\u0439jklmnopqr\u043a\u043b\u043c\u043d\u043e\u043f\u044f~stuvwxyz\u0440\u0441\u0442\u0443\u0436\u0432\u044c\u044b\u0437\u0448\u044d\u0449\u0447\u044a\u042e\u0410\u0411\u0426\u0414\u0415\u0424\u0413{ABCDEFGHI\u0425\u0418\u0419\u041a\u041b\u041c}JKLMNOPQR\u041d\u041e\u041f\u042f\u0420\u0421\\\u00a7STUVWXYZ\u0422\u0423\u0416\u0412\u042c\u042b0123456789\u0417\u0428\u042d\u0429\u0427\u009f",
|
||||||
|
Aliases: []string{"ibm-1025_P100-1995", "ibm-1025", "cp1025", "1025"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1026_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3\u00e5{\u00f1\u00c7.<(+!&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df\u011e\u0130*);^-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5[\u00d1\u015f,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u0131:\u00d6\u015e'=\u00dc\u00d8abcdefghi\u00ab\u00bb}`\u00a6\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u00a4\u00b5\u00f6stuvwxyz\u00a1\u00bf]$@\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\u00b4\u00d7\u00e7ABCDEFGHI\u00ad\u00f4~\u00f2\u00f3\u00f5\u011fJKLMNOPQR\u00b9\u00fb\\\u00f9\u00fa\u00ff\u00fc\u00f7STUVWXYZ\u00b2\u00d4#\u00d2\u00d3\u00d50123456789\u00b3\u00db\"\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1026_P100-1995", "ibm-1026", "IBM1026", "CP1026", "csIBM1026", "1026"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1047_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3\u00e5\u00e7\u00f1\u00a2.<(+|&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df!$*);^-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00a6,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc`:#@'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u00a4\u00b5~stuvwxyz\u00a1\u00bf\u00d0[\u00de\u00ae\u00ac\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be\u00dd\u00a8\u00af]\u00b4\u00d7{ABCDEFGHI\u00ad\u00f4\u00f6\u00f2\u00f3\u00f5}JKLMNOPQR\u00b9\u00fb\u00fc\u00f9\u00fa\u00ff\\\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1047_P100-1995", "ibm-1047", "IBM1047", "cp1047", "1047"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1097_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u060c\u064b\ufe81\ufe82\uf8fa\ufe8d\ufe8e\uf8fb\u00a4.<(+|&\ufe80\ufe83\ufe84\uf8f9\ufe85\ufe8b\ufe8f\ufe91\ufb56!$*);\u00ac-/\ufb58\ufe95\ufe97\ufe99\ufe9b\ufe9d\ufe9f\ufb7a\u061b,%_>?\ufb7c\ufea1\ufea3\ufea5\ufea7\ufea9\ufeab\ufead\ufeaf`:#@'=\"\ufb8aabcdefghi\u00ab\u00bb\ufeb1\ufeb3\ufeb5\ufeb7\ufeb9jklmnopqr\ufebb\ufebd\ufebf\ufec1\ufec3\ufec5\ufec7~stuvwxyz\ufec9\ufeca\ufecb\ufecc\ufecd\ufece\ufecf\ufed0\ufed1\ufed3\ufed5\ufed7\ufb8e\ufedb\ufb92\ufb94[]\ufedd\ufedf\ufee1\u00d7{ABCDEFGHI\u00ad\ufee3\ufee5\ufee7\ufeed\ufee9}JKLMNOPQR\ufeeb\ufeec\ufba4\ufbfc\ufbfd\ufbfe\\\u061fSTUVWXYZ\u0640\u06f0\u06f1\u06f2\u06f3\u06f40123456789\u06f5\u06f6\u06f7\u06f8\u06f9\u009f",
|
||||||
|
Aliases: []string{"ibm-1097_P100-1995", "ibm-1097", "cp1097", "1097"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1098_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\ufffd\ufffd\u060c\u061b\u061f\u064b\ufe81\ufe82\uf8fa\ufe8d\ufe8e\uf8fb\ufe80\ufe83\ufe84\uf8f9\ufe85\ufe8b\ufe8f\ufe91\ufb56\ufb58\ufe95\ufe97\ufe99\ufe9b\ufe9d\ufe9f\ufb7a\ufb7c\u00d7\ufea1\ufea3\ufea5\ufea7\ufea9\ufeab\ufead\ufeaf\ufb8a\ufeb1\ufeb3\ufeb5\ufeb7\ufeb9\ufebb\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\ufebd\ufebf\ufec1\ufec3\u2563\u2551\u2557\u255d\u00a4\ufec5\u2510\u2514\u2534\u252c\u251c\u2500\u253c\ufec7\ufec9\u255a\u2554\u2569\u2566\u2560\u2550\u256c\ufffd\ufeca\ufecb\ufecc\ufecd\ufece\ufecf\ufed0\ufed1\ufed3\u2518\u250c\u2588\u2584\ufed5\ufed7\u2580\ufb8e\ufedb\ufb92\ufb94\ufedd\ufedf\ufee1\ufee3\ufee5\ufee7\ufeed\ufee9\ufeeb\ufeec\ufba4\ufbfc\u00ad\ufbfd\ufbfe\u0640\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u25a0\u00a0",
|
||||||
|
Aliases: []string{"ibm-1098_P100-1995", "ibm-1098", "IBM1098", "cp1098", "1098"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1112_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u0161\u00e4\u0105\u012f\u016b\u00e5\u0113\u017e\u00a2.<(+|&\u00e9\u0119\u0117\u010d\u0173\u201e\u201c\u0123\u00df!$*);\u00ac-/\u0160\u00c4\u0104\u012e\u016a\u00c5\u0112\u017d\u00a6,%_>?\u00f8\u00c9\u0118\u0116\u010c\u0172\u012a\u013b\u0122`:#@'=\"\u00d8abcdefghi\u00ab\u00bb\u0101\u017c\u0144\u00b1\u00b0jklmnopqr\u0156\u0157\u00e6\u0137\u00c6\u00a4\u00b5~stuvwxyz\u201d\u017a\u0100\u017b\u0143\u00ae^\u00a3\u012b\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be[]\u0179\u0136\u013c\u00d7{ABCDEFGHI\u00ad\u014d\u00f6\u0146\u00f3\u00f5}JKLMNOPQR\u00b9\u0107\u00fc\u0142\u015b\u2019\\\u00f7STUVWXYZ\u00b2\u014c\u00d6\u0145\u00d3\u00d50123456789\u00b3\u0106\u00dc\u0141\u015a\u009f",
|
||||||
|
Aliases: []string{"ibm-1112_P100-1995", "ibm-1112", "cp1112", "1112"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1122_P100-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2{\u00e0\u00e1\u00e3}\u00e7\u00f1\u00a7.<(+!&`\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df\u00a4\u00c5*);^-/\u00c2#\u00c0\u00c1\u00c3$\u00c7\u00d1\u00f6,%_>?\u00f8\\\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u00e9:\u00c4\u00d6'=\"\u00d8abcdefghi\u00ab\u00bb\u0161\u00fd\u017e\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6]\u00b5\u00fcstuvwxyz\u00a1\u00bf\u0160\u00dd\u017d\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9[\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\u00b4\u00d7\u00e4ABCDEFGHI\u00ad\u00f4\u00a6\u00f2\u00f3\u00f5\u00e5JKLMNOPQR\u00b9\u00fb~\u00f9\u00fa\u00ff\u00c9\u00f7STUVWXYZ\u00b2\u00d4@\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1122_P100-1999", "ibm-1122", "cp1122", "1122"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1123_P100-1995",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u0452\u0491\u0451\u0454\u0455\u0456\u0457\u0458[.<(+!&\u0459\u045a\u045b\u045c\u045e\u045f\u042a\u2116\u0402]$*);^-/\u0490\u0401\u0404\u0405\u0406\u0407\u0408\u0409|,%_>?\u040a\u040b\u040c\u00ad\u040e\u040f\u044e\u0430\u0431`:#@'=\"\u0446abcdefghi\u0434\u0435\u0444\u0433\u0445\u0438\u0439jklmnopqr\u043a\u043b\u043c\u043d\u043e\u043f\u044f~stuvwxyz\u0440\u0441\u0442\u0443\u0436\u0432\u044c\u044b\u0437\u0448\u044d\u0449\u0447\u044a\u042e\u0410\u0411\u0426\u0414\u0415\u0424\u0413{ABCDEFGHI\u0425\u0418\u0419\u041a\u041b\u041c}JKLMNOPQR\u041d\u041e\u041f\u042f\u0420\u0421\\\u00a7STUVWXYZ\u0422\u0423\u0416\u0412\u042c\u042b0123456789\u0417\u0428\u042d\u0429\u0427\u009f",
|
||||||
|
Aliases: []string{"ibm-1123_P100-1995", "ibm-1123", "cp1123", "1123"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1124_P100-1996",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u0401\u0402\u0490\u0404\u0405\u0406\u0407\u0408\u0409\u040a\u040b\u040c\u00ad\u040e\u040f\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f\u2116\u0451\u0452\u0491\u0454\u0455\u0456\u0457\u0458\u0459\u045a\u045b\u045c\u00a7\u045e\u045f",
|
||||||
|
Aliases: []string{"ibm-1124_P100-1996", "ibm-1124", "cp1124", "1124"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1125_P100-1997",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f\u0401\u0451\u0490\u0491\u0404\u0454\u0406\u0456\u0407\u0457\u00f7\u00b1\u2116\u00a4\u25a0\u00a0",
|
||||||
|
Aliases: []string{"ibm-1125_P100-1997", "ibm-1125", "cp1125"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1129_P100-1997",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u00a1\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7\u0153\u00a9\u00aa\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u0178\u00b5\u00b6\u00b7\u0152\u00b9\u00ba\u00bb\u00bc\u00bd\u00be\u00bf\u00c0\u00c1\u00c2\u0102\u00c4\u00c5\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u0300\u00cd\u00ce\u00cf\u0110\u00d1\u0309\u00d3\u00d4\u01a0\u00d6\u00d7\u00d8\u00d9\u00da\u00db\u00dc\u01af\u0303\u00df\u00e0\u00e1\u00e2\u0103\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u0301\u00ed\u00ee\u00ef\u0111\u00f1\u0323\u00f3\u00f4\u01a1\u00f6\u00f7\u00f8\u00f9\u00fa\u00fb\u00fc\u01b0\u20ab\u00ff",
|
||||||
|
Aliases: []string{"ibm-1129_P100-1997", "ibm-1129"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1130_P100-1997",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u0103\u00e5\u00e7\u00f1[.<(+!&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u0303\u00df]$*);^-/\u00c2\u00c4\u00c0\u00c1\u0102\u00c5\u00c7\u00d1\u00a6,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u20ab`:#@'=\"\u00d8abcdefghi\u00ab\u00bb\u0111\u0309\u0300\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u0152\u00c6\u00a4\u00b5~stuvwxyz\u00a1\u00bf\u0110\u0323\u0301\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u0153\u0178\u00d7{ABCDEFGHI\u00ad\u00f4\u00f6\u01b0\u00f3\u01a1}JKLMNOPQR\u00b9\u00fb\u00fc\u00f9\u00fa\u00ff\\\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u01af\u00d3\u01a00123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1130_P100-1997", "ibm-1130"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1131_P100-1997",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1c\x1b\x7f\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x1a\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f\u0401\u0451\u0404\u0454\u0407\u0457\u040e\u045e\u0406\u0456\u00b7\u00a4\u0490\u0491\u2219\u00a0",
|
||||||
|
Aliases: []string{"ibm-1131_P100-1997", "ibm-1131", "cp1131"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1132_P100-1998",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u0e81\u0e82\u0e84\u0e87\u0e88\u0eaa\u0e8a[\u00a2.<(+|&\ufffd\u0e8d\u0e94\u0e95\u0e96\u0e97\u0e99\u0e9a]!$*);\u00ac-/\u0e9b\u0e9c\u0e9d\u0e9e\u0e9f\u0ea1\u0ea2^\u00a6,%_>?\u20ad\ufffd\u0ea3\u0ea5\u0ea7\u0eab\u0ead\u0eae\ufffd`:#@'=\"\ufffdabcdefghi\ufffd\ufffd\u0eaf\u0eb0\u0eb2\u0eb3\ufffdjklmnopqr\u0eb4\u0eb5\u0eb6\u0eb7\u0eb8\u0eb9\ufffd~stuvwxyz\u0ebc\u0eb1\u0ebb\u0ebd\ufffd\ufffd\u0ed0\u0ed1\u0ed2\u0ed3\u0ed4\u0ed5\u0ed6\u0ed7\u0ed8\u0ed9\ufffd\u0ec0\u0ec1\u0ec2\u0ec3\u0ec4{ABCDEFGHI\ufffd\u0ec8\u0ec9\u0eca\u0ecb\u0ecc}JKLMNOPQR\u0ecd\u0ec6\ufffd\u0edc\u0edd\ufffd\\\ufffdSTUVWXYZ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd0123456789\ufffd\ufffd\ufffd\ufffd\ufffd\u009f",
|
||||||
|
Aliases: []string{"ibm-1132_P100-1998", "ibm-1132"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1133_P100-1997",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\ufffd\u0e81\u0e82\u0e84\u0e87\u0e88\u0eaa\u0e8a\u0e8d\u0e94\u0e95\u0e96\u0e97\u0e99\u0e9a\u0e9b\u0e9c\u0e9d\u0e9e\u0e9f\u0ea1\u0ea2\u0ea3\u0ea5\u0ea7\u0eab\u0ead\u0eae\ufffd\ufffd\ufffd\u0eaf\u0eb0\u0eb2\u0eb3\u0eb4\u0eb5\u0eb6\u0eb7\u0eb8\u0eb9\u0ebc\u0eb1\u0ebb\u0ebd\ufffd\ufffd\ufffd\u0ec0\u0ec1\u0ec2\u0ec3\u0ec4\u0ec8\u0ec9\u0eca\u0ecb\u0ecc\u0ecd\u0ec6\ufffd\u0edc\u0eddk\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0ed0\u0ed1\u0ed2\u0ed3\u0ed4\u0ed5\u0ed6\u0ed7\u0ed8\u0ed9\ufffd\ufffd\u00a2\u00ac\u00a6\u00a0",
|
||||||
|
Aliases: []string{"ibm-1133_P100-1997", "ibm-1133"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1137_P100-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u0901\u0902\u0903\u0905\u0906\u0907\u0908\u0909\u090a.<(+|&\u090b\u090c\u090d\u090e\u090f\u0910\u0911\u0912\u0913!$*);^-/\u0914\u0915\u0916\u0917\u0918\u0919\u091a\u091b\u091c,%_>?\u091d\u091e\u091f\u0920\u0921\u0922\u0923\u0924\u0925`:#@'=\"\u0926abcdefghi\u0927\u0928\u092a\u092b\u092c\u092d\u092ejklmnopqr\u092f\u0930\u0932\u0933\u0935\u0936\u200c~stuvwxyz\u0937\u0938\u0939[\u093c\u093d\u093e\u093f\u0940\u0941\u0942\u0943\u0944\u0945\u0946\u0947\u0948\u0949\u094a]\u094b\u094c{ABCDEFGHI\u094d\u0950\u0951\u0952\ufffd\ufffd}JKLMNOPQR\u0960\u0961\u0962\u0963\u0964\u0965\\\u200dSTUVWXYZ\u0966\u0967\u0968\u0969\u096a\u096b0123456789\u096c\u096d\u096e\u096f\u0970\u009f",
|
||||||
|
Aliases: []string{"ibm-1137_P100-1999", "ibm-1137"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1140_P100-1997",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3\u00e5\u00e7\u00f1\u00a2.<(+|&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df!$*);\u00ac-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00a6,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc`:#@'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u20ac\u00b5~stuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae^\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be[]\u00af\u00a8\u00b4\u00d7{ABCDEFGHI\u00ad\u00f4\u00f6\u00f2\u00f3\u00f5}JKLMNOPQR\u00b9\u00fb\u00fc\u00f9\u00fa\u00ff\\\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1140_P100-1997", "ibm-1140", "IBM01140", "CCSID01140", "CP01140", "cp1140", "ebcdic-us-37+euro"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1141_P100-1997",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2{\u00e0\u00e1\u00e3\u00e5\u00e7\u00f1\u00c4.<(+!&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec~\u00dc$*);^-/\u00c2[\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00f6,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc`:#\u00a7'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u20ac\u00b5\u00dfstuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9@\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\u00b4\u00d7\u00e4ABCDEFGHI\u00ad\u00f4\u00a6\u00f2\u00f3\u00f5\u00fcJKLMNOPQR\u00b9\u00fb}\u00f9\u00fa\u00ff\u00d6\u00f7STUVWXYZ\u00b2\u00d4\\\u00d2\u00d3\u00d50123456789\u00b3\u00db]\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1141_P100-1997", "ibm-1141", "IBM01141", "CCSID01141", "CP01141", "cp1141", "ebcdic-de-273+euro"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1142_P100-1997",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3}\u00e7\u00f1#.<(+!&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df\u20ac\u00c5*);^-/\u00c2\u00c4\u00c0\u00c1\u00c3$\u00c7\u00d1\u00f8,%_>?\u00a6\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc`:\u00c6\u00d8'=\"@abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba{\u00b8[]\u00b5\u00fcstuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\u00b4\u00d7\u00e6ABCDEFGHI\u00ad\u00f4\u00f6\u00f2\u00f3\u00f5\u00e5JKLMNOPQR\u00b9\u00fb~\u00f9\u00fa\u00ff\\\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1142_P100-1997", "ibm-1142", "IBM01142", "CCSID01142", "CP01142", "cp1142", "ebcdic-dk-277+euro", "ebcdic-no-277+euro"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1143_P100-1997",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2{\u00e0\u00e1\u00e3}\u00e7\u00f1\u00a7.<(+!&`\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df\u20ac\u00c5*);^-/\u00c2#\u00c0\u00c1\u00c3$\u00c7\u00d1\u00f6,%_>?\u00f8\\\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u00e9:\u00c4\u00d6'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6]\u00b5\u00fcstuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9[\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\u00b4\u00d7\u00e4ABCDEFGHI\u00ad\u00f4\u00a6\u00f2\u00f3\u00f5\u00e5JKLMNOPQR\u00b9\u00fb~\u00f9\u00fa\u00ff\u00c9\u00f7STUVWXYZ\u00b2\u00d4@\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1143_P100-1997", "ibm-1143", "IBM01143", "CCSID01143", "CP01143", "cp1143", "ebcdic-fi-278+euro", "ebcdic-se-278+euro"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1144_P100-1997",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4{\u00e1\u00e3\u00e5\\\u00f1\u00b0.<(+!&]\u00ea\u00eb}\u00ed\u00ee\u00ef~\u00df\u00e9$*);^-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00f2,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u00f9:\u00a3\u00a7'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1[jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u20ac\u00b5\u00ecstuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2#\u00a5\u00b7\u00a9@\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\u00b4\u00d7\u00e0ABCDEFGHI\u00ad\u00f4\u00f6\u00a6\u00f3\u00f5\u00e8JKLMNOPQR\u00b9\u00fb\u00fc`\u00fa\u00ff\u00e7\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1144_P100-1997", "ibm-1144", "IBM01144", "CCSID01144", "CP01144", "cp1144", "ebcdic-it-280+euro"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1145_P100-1997",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3\u00e5\u00e7\u00a6[.<(+|&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df]$*);\u00ac-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7#\u00f1,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc`:\u00d1@'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u20ac\u00b5\u00a8stuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be^!\u00af~\u00b4\u00d7{ABCDEFGHI\u00ad\u00f4\u00f6\u00f2\u00f3\u00f5}JKLMNOPQR\u00b9\u00fb\u00fc\u00f9\u00fa\u00ff\\\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1145_P100-1997", "ibm-1145", "IBM01145", "CCSID01145", "CP01145", "cp1145", "ebcdic-es-284+euro"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1146_P100-1997",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3\u00e5\u00e7\u00f1$.<(+|&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df!\u00a3*);\u00ac-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00a6,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc`:#@'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u20ac\u00b5\u00afstuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2[\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be^]~\u00a8\u00b4\u00d7{ABCDEFGHI\u00ad\u00f4\u00f6\u00f2\u00f3\u00f5}JKLMNOPQR\u00b9\u00fb\u00fc\u00f9\u00fa\u00ff\\\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1146_P100-1997", "ibm-1146", "IBM01146", "CCSID01146", "CP01146", "cp1146", "ebcdic-gb-285+euro"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1147_P100-1997",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4@\u00e1\u00e3\u00e5\\\u00f1\u00b0.<(+!&{\u00ea\u00eb}\u00ed\u00ee\u00ef\u00ec\u00df\u00a7$*);^-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00f9,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u00b5:\u00a3\u00e0'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1[jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u20ac`\u00a8stuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2#\u00a5\u00b7\u00a9]\u00b6\u00bc\u00bd\u00be\u00ac|\u00af~\u00b4\u00d7\u00e9ABCDEFGHI\u00ad\u00f4\u00f6\u00f2\u00f3\u00f5\u00e8JKLMNOPQR\u00b9\u00fb\u00fc\u00a6\u00fa\u00ff\u00e7\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1147_P100-1997", "ibm-1147", "IBM01147", "CCSID01147", "CP01147", "cp1147", "ebcdic-fr-297+euro"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1148_P100-1997",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3\u00e5\u00e7\u00f1[.<(+!&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df]$*);^-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00a6,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc`:#@'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u20ac\u00b5~stuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\u00b4\u00d7{ABCDEFGHI\u00ad\u00f4\u00f6\u00f2\u00f3\u00f5}JKLMNOPQR\u00b9\u00fb\u00fc\u00f9\u00fa\u00ff\\\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1148_P100-1997", "ibm-1148", "IBM01148", "CCSID01148", "CP01148", "cp1148", "ebcdic-international-500+euro"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1149_P100-1997",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3\u00e5\u00e7\u00f1\u00de.<(+!&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df\u00c6$*);\u00d6-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00a6,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u00f0:#\u00d0'=\"\u00d8abcdefghi\u00ab\u00bb`\u00fd{\u00b1\u00b0jklmnopqr\u00aa\u00ba}\u00b8]\u20ac\u00b5\u00f6stuvwxyz\u00a1\u00bf@\u00dd[\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\\\u00d7\u00feABCDEFGHI\u00ad\u00f4~\u00f2\u00f3\u00f5\u00e6JKLMNOPQR\u00b9\u00fb\u00fc\u00f9\u00fa\u00ff\u00b4\u00f7STUVWXYZ\u00b2\u00d4^\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1149_P100-1997", "ibm-1149", "IBM01149", "CCSID01149", "CP01149", "cp1149", "ebcdic-is-871+euro"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1153_P100-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u0163\u00e1\u0103\u010d\u00e7\u0107[.<(+!&\u00e9\u0119\u00eb\u016f\u00ed\u00ee\u013e\u013a\u00df]$*);^-/\u00c2\u00c4\u02dd\u00c1\u0102\u010c\u00c7\u0106|,%_>?\u02c7\u00c9\u0118\u00cb\u016e\u00cd\u00ce\u013d\u0139`:#@'=\"\u02d8abcdefghi\u015b\u0148\u0111\u00fd\u0159\u015f\u00b0jklmnopqr\u0142\u0144\u0161\u00b8\u02db\u20ac\u0105~stuvwxyz\u015a\u0147\u0110\u00dd\u0158\u015e\u02d9\u0104\u017c\u0162\u017b\u00a7\u017e\u017a\u017d\u0179\u0141\u0143\u0160\u00a8\u00b4\u00d7{ABCDEFGHI\u00ad\u00f4\u00f6\u0155\u00f3\u0151}JKLMNOPQR\u011a\u0171\u00fc\u0165\u00fa\u011b\\\u00f7STUVWXYZ\u010f\u00d4\u00d6\u0154\u00d3\u01500123456789\u010e\u0170\u00dc\u0164\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1153_P100-1999", "ibm-1153"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1154_P100-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u0452\u0453\u0451\u0454\u0455\u0456\u0457\u0458[.<(+!&\u0459\u045a\u045b\u045c\u045e\u045f\u042a\u2116\u0402]$*);^-/\u0403\u0401\u0404\u0405\u0406\u0407\u0408\u0409|,%_>?\u040a\u040b\u040c\u00ad\u040e\u040f\u044e\u0430\u0431`:#@'=\"\u0446abcdefghi\u0434\u0435\u0444\u0433\u0445\u0438\u0439jklmnopqr\u043a\u043b\u043c\u043d\u043e\u043f\u044f~stuvwxyz\u0440\u0441\u0442\u0443\u0436\u0432\u044c\u044b\u0437\u0448\u044d\u0449\u0447\u044a\u042e\u0410\u0411\u0426\u0414\u0415\u0424\u0413{ABCDEFGHI\u0425\u0418\u0419\u041a\u041b\u041c}JKLMNOPQR\u041d\u041e\u041f\u042f\u0420\u0421\\\u20acSTUVWXYZ\u0422\u0423\u0416\u0412\u042c\u042b0123456789\u0417\u0428\u042d\u0429\u0427\u009f",
|
||||||
|
Aliases: []string{"ibm-1154_P100-1999", "ibm-1154"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1155_P100-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3\u00e5{\u00f1\u00c7.<(+!&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df\u011e\u0130*);^-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5[\u00d1\u015f,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u0131:\u00d6\u015e'=\u00dc\u00d8abcdefghi\u00ab\u00bb}`\u00a6\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u20ac\u00b5\u00f6stuvwxyz\u00a1\u00bf]$@\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\u00b4\u00d7\u00e7ABCDEFGHI\u00ad\u00f4~\u00f2\u00f3\u00f5\u011fJKLMNOPQR\u00b9\u00fb\\\u00f9\u00fa\u00ff\u00fc\u00f7STUVWXYZ\u00b2\u00d4#\u00d2\u00d3\u00d50123456789\u00b3\u00db\"\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1155_P100-1999", "ibm-1155"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1156_P100-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u0161\u00e4\u0105\u012f\u016b\u00e5\u0113\u017e\u00a2.<(+|&\u00e9\u0119\u0117\u010d\u0173\u201e\u201c\u0123\u00df!$*);\u00ac-/\u0160\u00c4\u0104\u012e\u016a\u00c5\u0112\u017d\u00a6,%_>?\u00f8\u00c9\u0118\u0116\u010c\u0172\u012a\u013b\u0122`:#@'=\"\u00d8abcdefghi\u00ab\u00bb\u0101\u017c\u0144\u00b1\u00b0jklmnopqr\u0156\u0157\u00e6\u0137\u00c6\u20ac\u00b5~stuvwxyz\u201d\u017a\u0100\u017b\u0143\u00ae^\u00a3\u012b\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be[]\u0179\u0136\u013c\u00d7{ABCDEFGHI\u00ad\u014d\u00f6\u0146\u00f3\u00f5}JKLMNOPQR\u00b9\u0107\u00fc\u0142\u015b\u2019\\\u00f7STUVWXYZ\u00b2\u014c\u00d6\u0145\u00d3\u00d50123456789\u00b3\u0106\u00dc\u0141\u015a\u009f",
|
||||||
|
Aliases: []string{"ibm-1156_P100-1999", "ibm-1156"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1157_P100-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2{\u00e0\u00e1\u00e3}\u00e7\u00f1\u00a7.<(+!&`\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df\u20ac\u00c5*);^-/\u00c2#\u00c0\u00c1\u00c3$\u00c7\u00d1\u00f6,%_>?\u00f8\\\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u00e9:\u00c4\u00d6'=\"\u00d8abcdefghi\u00ab\u00bb\u0161\u00fd\u017e\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6]\u00b5\u00fcstuvwxyz\u00a1\u00bf\u0160\u00dd\u017d\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9[\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u00a8\u00b4\u00d7\u00e4ABCDEFGHI\u00ad\u00f4\u00a6\u00f2\u00f3\u00f5\u00e5JKLMNOPQR\u00b9\u00fb~\u00f9\u00fa\u00ff\u00c9\u00f7STUVWXYZ\u00b2\u00d4@\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1157_P100-1999", "ibm-1157"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1158_P100-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u0452\u0491\u0451\u0454\u0455\u0456\u0457\u0458[.<(+!&\u0459\u045a\u045b\u045c\u045e\u045f\u042a\u2116\u0402]$*);^-/\u0490\u0401\u0404\u0405\u0406\u0407\u0408\u0409|,%_>?\u040a\u040b\u040c\u00ad\u040e\u040f\u044e\u0430\u0431`:#@'=\"\u0446abcdefghi\u0434\u0435\u0444\u0433\u0445\u0438\u0439jklmnopqr\u043a\u043b\u043c\u043d\u043e\u043f\u044f~stuvwxyz\u0440\u0441\u0442\u0443\u0436\u0432\u044c\u044b\u0437\u0448\u044d\u0449\u0447\u044a\u042e\u0410\u0411\u0426\u0414\u0415\u0424\u0413{ABCDEFGHI\u0425\u0418\u0419\u041a\u041b\u041c}JKLMNOPQR\u041d\u041e\u041f\u042f\u0420\u0421\\\u20acSTUVWXYZ\u0422\u0423\u0416\u0412\u042c\u042b0123456789\u0417\u0428\u042d\u0429\u0427\u009f",
|
||||||
|
Aliases: []string{"ibm-1158_P100-1999", "ibm-1158"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1160_P100-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u0e01\u0e02\u0e03\u0e04\u0e05\u0e06\u0e07[\u00a2.<(+|&\u0e48\u0e08\u0e09\u0e0a\u0e0b\u0e0c\u0e0d\u0e0e]!$*);\u00ac-/\u0e0f\u0e10\u0e11\u0e12\u0e13\u0e14\u0e15^\u00a6,%_>?\u0e3f\u0e4e\u0e16\u0e17\u0e18\u0e19\u0e1a\u0e1b\u0e1c`:#@'=\"\u0e4fabcdefghi\u0e1d\u0e1e\u0e1f\u0e20\u0e21\u0e22\u0e5ajklmnopqr\u0e23\u0e24\u0e25\u0e26\u0e27\u0e28\u0e5b~stuvwxyz\u0e29\u0e2a\u0e2b\u0e2c\u0e2d\u0e2e\u0e50\u0e51\u0e52\u0e53\u0e54\u0e55\u0e56\u0e57\u0e58\u0e59\u0e2f\u0e30\u0e31\u0e32\u0e33\u0e34{ABCDEFGHI\u0e49\u0e35\u0e36\u0e37\u0e38\u0e39}JKLMNOPQR\u0e3a\u0e40\u0e41\u0e42\u0e43\u0e44\\\u0e4aSTUVWXYZ\u0e45\u0e46\u0e47\u0e48\u0e49\u0e4a0123456789\u0e4b\u0e4c\u0e4d\u0e4b\u20ac\u009f",
|
||||||
|
Aliases: []string{"ibm-1160_P100-1999", "ibm-1160"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1162_P100-1999",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u20ac\u0081\u0082\u0083\u0084\u2026\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u0e01\u0e02\u0e03\u0e04\u0e05\u0e06\u0e07\u0e08\u0e09\u0e0a\u0e0b\u0e0c\u0e0d\u0e0e\u0e0f\u0e10\u0e11\u0e12\u0e13\u0e14\u0e15\u0e16\u0e17\u0e18\u0e19\u0e1a\u0e1b\u0e1c\u0e1d\u0e1e\u0e1f\u0e20\u0e21\u0e22\u0e23\u0e24\u0e25\u0e26\u0e27\u0e28\u0e29\u0e2a\u0e2b\u0e2c\u0e2d\u0e2e\u0e2f\u0e30\u0e31\u0e32\u0e33\u0e34\u0e35\u0e36\u0e37\u0e38\u0e39\u0e3a\ufffd\ufffd\ufffd\ufffd\u0e3f\u0e40\u0e41\u0e42\u0e43\u0e44\u0e45\u0e46\u0e47\u0e48\u0e49\u0e4a\u0e4b\u0e4c\u0e4d\u0e4e\u0e4f\u0e50\u0e51\u0e52\u0e53\u0e54\u0e55\u0e56\u0e57\u0e58\u0e59\u0e5a\u0e5b\ufffd\ufffd\ufffd\ufffd",
|
||||||
|
Aliases: []string{"ibm-1162_P100-1999", "ibm-1162"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1164_P100-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u0103\u00e5\u00e7\u00f1[.<(+!&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u0303\u00df]$*);^-/\u00c2\u00c4\u00c0\u00c1\u0102\u00c5\u00c7\u00d1\u00a6,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u20ab`:#@'=\"\u00d8abcdefghi\u00ab\u00bb\u0111\u0309\u0300\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u0152\u00c6\u20ac\u00b5~stuvwxyz\u00a1\u00bf\u0110\u0323\u0301\u00ae\u00a2\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be\u00ac|\u00af\u0153\u0178\u00d7{ABCDEFGHI\u00ad\u00f4\u00f6\u01b0\u00f3\u01a1}JKLMNOPQR\u00b9\u00fb\u00fc\u00f9\u00fa\u00ff\\\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u01af\u00d3\u01a00123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ibm-1164_P100-1999", "ibm-1164"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-4517_P100-2005",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\ufe7c\ufe7d\u0640\u200b\ufe80\ufe81\ufe82\ufe83\u00b0.<(+!&\ufe84\ufe85\ufffd\ufffd\ufe8b\ufe8d\ufe8e\ufe8f\ufe91\u00a7$*);^-/\ufe93\ufe95\ufe97\ufe99\ufe9b\ufe9d\ufe9f\ufea1\u00fa,%_>?\ufea3\ufea5\ufea7\ufea9\ufeab\ufead\ufeaf\ufeb1\ufeb3\u00a3:\u00b5\u00e1'=\"\ufeb5abcdefghi\ufeb7\ufeb9\ufebb\ufebd\ufebf\ufec3\ufec7jklmnopqr\ufec9\ufeca\ufecb\ufecc\ufecd\ufece\ufecf\u00a8stuvwxyz\ufed0\ufed1\ufed3\ufed5\ufed7\ufed9\ufedb\ufedd\ufef5\ufef6\ufef7\ufef8\ufffd\ufffd\ufefb\ufefc\ufedf\ufee1\ufee3\ufee5\ufee7\ufee9\u00e9ABCDEFGHI\u00ad\ufeeb\ufffd\ufeec\ufffd\ufeed\u00e8JKLMNOPQR\ufeef\ufef0\ufef1\ufef2\ufef3\ufffd\u00e7\u2007STUVWXYZ\u00f7\u060c\ufffd\u00d7\u061f\u061b0123456789\ufffd\ufffd\ufffd\ufffd\ufffd\u009f",
|
||||||
|
Aliases: []string{"ibm-4517_P100-2005", "ibm-4517"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-4899_P100-1998",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd$.<(+|\u05d0\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd!\u00a2*);\u00ac-/\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd,%_>?\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd:#@'=\"\ufffd\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\ufffd\ufffd\u20ac\ufffd\u20aa\ufffd\ufffd\ufffd\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdABCDEFGHI\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdJKLMNOPQR\ufffd\u202d\u202e\u202c\ufffd\ufffd\ufffd\ufffdSTUVWXYZ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd0123456789\ufffd\u202a\u202b\u200e\u200f\u009f",
|
||||||
|
Aliases: []string{"ibm-4899_P100-1998", "ibm-4899"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-4909_P100-1999",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0\u2018\u2019\u00a3\u20ac\ufffd\u00a6\u00a7\u00a8\u00a9\ufffd\u00ab\u00ac\u00ad\ufffd\u2015\u00b0\u00b1\u00b2\u00b3\u00b4\u0385\u0386\u0387\u0388\u0389\u038a\u00bb\u038c\u00bd\u038e\u038f\u0390\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\ufffd\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab\u03ac\u03ad\u03ae\u03af\u03b0\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c2\u03c3\u03c4\u03c5\u03c6\u03c7\u03c8\u03c9\u03ca\u03cb\u03cc\u03cd\u03ce\ufffd",
|
||||||
|
Aliases: []string{"ibm-4909_P100-1999", "ibm-4909"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-4971_P100-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399[.<(+!&\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\u03a3]$*);^-/\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab|,%_>?\u00a8\u0386\u0388\u0389\u00a0\u038a\u038c\u038e\u038f`:#@'=\"\u0385abcdefghi\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u00b0jklmnopqr\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u00b4~stuvwxyz\u03bd\u03be\u03bf\u03c0\u03c1\u03c3\u00a3\u03ac\u03ad\u03ae\u03ca\u03af\u03cc\u03cd\u03cb\u03ce\u03c2\u03c4\u03c5\u03c6\u03c7\u03c8{ABCDEFGHI\u00ad\u03c9\u0390\u03b0\u2018\u2015}JKLMNOPQR\u00b1\u00bd\ufffd\u0387\u2019\u00a6\\\ufffdSTUVWXYZ\u00b2\u00a7\ufffd\ufffd\u00ab\u00ac0123456789\u00b3\u00a9\u20ac\ufffd\u00bb\u009f",
|
||||||
|
Aliases: []string{"ibm-4971_P100-1999", "ibm-4971"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-5123_P100-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \ufffd\uff61\uff62\uff63\uff64\uff65\uff66\uff67\uff68\u00a2.<(+|&\uff69\uff6a\uff6b\uff6c\uff6d\uff6e\uff6f\uff70\uff71!$*);\u00ac-/\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\ufffd,%_>?\uff7a\uff7b\uff7c\uff7d\uff7e\uff7f\uff80\uff81\uff82`:#@'=\"\ufffdabcdefghi\uff83\uff84\uff85\uff86\uff87\uff88\ufffdjklmnopqr\uff89\uff8a\uff8b\uff8c\uff8d\uff8e\u203e~stuvwxyz\uff8f\uff90\uff91[\uff92\uff93^\u00a3\u00a5\uff94\uff95\uff96\uff97\uff98\uff99\uff9a\uff9b\uff9c\uff9d]\uff9e\uff9f{ABCDEFGHI\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd}JKLMNOPQR\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\\\u20acSTUVWXYZ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd0123456789\ufffd\ufffd\ufffd\ufffd\ufffd\u009f",
|
||||||
|
Aliases: []string{"ibm-5123_P100-1999", "ibm-5123"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-8482_P100-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \uff61\uff62\uff63\uff64\uff65\uff66\uff67\uff68\uff69\u00a3.<(+|&\uff6a\uff6b\uff6c\uff6d\uff6e\uff6f\ufffd\uff70\ufffd!\u00a5*);\u00ac-/abcdefgh\ufffd,%_>?[ijklmnop`:#@'=\"]\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\uff7aq\uff7b\uff7c\uff7d\uff7e\uff7f\uff80\uff81\uff82\uff83\uff84\uff85\uff86\uff87\uff88\uff89r\ufffd\uff8a\uff8b\uff8c~\u203e\uff8d\uff8e\uff8f\uff90\uff91\uff92\uff93\uff94\uff95s\uff96\uff97\uff98\uff99^\u00a2\\tuvwxyz\uff9a\uff9b\uff9c\uff9d\uff9e\uff9f{ABCDEFGHI\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd}JKLMNOPQR\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd$\u20acSTUVWXYZ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd0123456789\ufffd\ufffd\ufffd\ufffd\ufffd\u009f",
|
||||||
|
Aliases: []string{"ibm-8482_P100-1999", "ibm-8482"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-9067_X100-2005",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399[.<(+!&\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\u03a3]$*);^-/\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab|,%_>?\u00a8\u0386\u0388\u0389\u00a0\u038a\u038c\u038e\u038f`:#@'=\"\u0385abcdefghi\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u00b0jklmnopqr\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u00b4~stuvwxyz\u03bd\u03be\u03bf\u03c0\u03c1\u03c3\u00a3\u03ac\u03ad\u03ae\u03ca\u03af\u03cc\u03cd\u03cb\u03ce\u03c2\u03c4\u03c5\u03c6\u03c7\u03c8{ABCDEFGHI\u00ad\u03c9\u0390\u03b0\u2018\u2015}JKLMNOPQR\u00b1\u00bd\ufffd\u0387\u2019\u00a6\\\u20afSTUVWXYZ\u00b2\u00a7\u037a\ufffd\u00ab\u00ac0123456789\u00b3\u00a9\u20ac\ufffd\u00bb\u009f",
|
||||||
|
Aliases: []string{"ibm-9067_X100-2005", "ibm-9067"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-12712_P100-1998",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u00a2.<(+|&\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1!$*);\u00ac-/\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u00a6,%_>?\ufffd\u05ea\ufffd\ufffd\u00a0\ufffd\ufffd\ufffd\u2017`:#@'=\"\ufffdabcdefghi\u00ab\u00bb\ufffd\ufffd\ufffd\u00b1\u00b0jklmnopqr\ufffd\ufffd\u20ac\u00b8\u20aa\u00a4\u00b5~stuvwxyz\ufffd\ufffd\ufffd\ufffd\ufffd\u00ae^\u00a3\u00a5\u2022\u00a9\u00a7\u00b6\u00bc\u00bd\u00be[]\u203e\u00a8\u00b4\u00d7{ABCDEFGHI\u00ad\ufffd\ufffd\ufffd\ufffd\ufffd}JKLMNOPQR\u00b9\u202d\u202e\u202c\ufffd\ufffd\\\u00f7STUVWXYZ\u00b2\ufffd\ufffd\ufffd\ufffd\ufffd0123456789\u00b3\u202a\u202b\u200e\u200f\u009f",
|
||||||
|
Aliases: []string{"ibm-12712_P100-1998", "ibm-12712", "ebcdic-he"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-16804_X110-1999",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\u0085\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u0651\ufe7d\u0640\u200b\u0621\u0622\ufe82\u0623\u00a2.<(+|&\ufe84\u0624\ufffd\ufffd\u0626\u0627\ufe8e\u0628\ufe91!$*);\u00ac-/\u0629\u062a\ufe97\u062b\ufe9b\u062c\ufe9f\u062d\u00a6,%_>?\ufea3\u062e\ufea7\u062f\u0630\u0631\u0632\u0633\ufeb3\u060c:#@'=\"\u0634abcdefghi\ufeb7\u0635\ufebb\u0636\ufebf\u0637\u0638jklmnopqr\u0639\ufeca\ufecb\ufecc\u063a\ufece\ufecf\u00f7stuvwxyz\ufed0\u0641\ufed3\u0642\ufed7\u0643\ufedb\u0644\ufef5\ufef6\ufef7\ufef8\ufffd\ufffd\ufefb\ufefc\ufedf\u0645\ufee3\u0646\ufee7\u0647\u061bABCDEFGHI\u00ad\ufeeb\ufffd\ufeec\ufffd\u0648\u061fJKLMNOPQR\u0649\ufef0\u064a\ufef2\ufef3\u0660\u00d7\u2007STUVWXYZ\u0661\u0662\ufffd\u0663\u0664\u06650123456789\u20ac\u0666\u0667\u0668\u0669\u009f",
|
||||||
|
Aliases: []string{"ibm-16804_X110-1999", "ibm-16804", "ebcdic-ar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "KOI8-R",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u2500\u2502\u250c\u2510\u2514\u2518\u251c\u2524\u252c\u2534\u253c\u2580\u2584\u2588\u258c\u2590\u2591\u2592\u2593\u2320\u25a0\u2219\u221a\u2248\u2264\u2265\u00a0\u2321\u00b0\u00b2\u00b7\u00f7\u2550\u2551\u2552\u0451\u2553\u2554\u2555\u2556\u2557\u2558\u2559\u255a\u255b\u255c\u255d\u255e\u255f\u2560\u2561\u0401\u2562\u2563\u2564\u2565\u2566\u2567\u2568\u2569\u256a\u256b\u256c\u00a9\u044e\u0430\u0431\u0446\u0434\u0435\u0444\u0433\u0445\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u044f\u0440\u0441\u0442\u0443\u0436\u0432\u044c\u044b\u0437\u0448\u044d\u0449\u0447\u044a\u042e\u0410\u0411\u0426\u0414\u0415\u0424\u0413\u0425\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u042f\u0420\u0421\u0422\u0423\u0416\u0412\u042c\u042b\u0417\u0428\u042d\u0429\u0427\u042a",
|
||||||
|
Aliases: []string{"csKOI8R"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "KOI8-U",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u2500\u2502\u250c\u2510\u2514\u2518\u251c\u2524\u252c\u2534\u253c\u2580\u2584\u2588\u258c\u2590\u2591\u2592\u2593\u2320\u25a0\u2219\u221a\u2248\u2264\u2265\u00a0\u2321\u00b0\u00b2\u00b7\u00f7\u2550\u2551\u2552\u0451\u0454\u2554\u0456\u0457\u2557\u2558\u2559\u255a\u255b\u0491\u255d\u255e\u255f\u2560\u2561\u0401\u0404\u2563\u0406\u0407\u2566\u2567\u2568\u2569\u256a\u0490\u256c\u00a9\u044e\u0430\u0431\u0446\u0434\u0435\u0444\u0433\u0445\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u044f\u0440\u0441\u0442\u0443\u0436\u0432\u044c\u044b\u0437\u0448\u044d\u0449\u0447\u044a\u042e\u0410\u0411\u0426\u0414\u0415\u0424\u0413\u0425\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u042f\u0420\u0421\u0422\u0423\u0416\u0412\u042c\u042b\u0417\u0428\u042d\u0429\u0427\u042a",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1051_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\ufffd\u00c0\u00c2\u00c8\u00ca\u00cb\u00ce\u00cf\u00b4`\u02c6\u00a8\u02dc\u00d9\u00db\u00a3\u203e\u00dd\u00fd\u02da\u00c7\u00e7\u00d1\u00f1\u00a1\u00bf\u00a4\u00a3\u00a5\u00a7\u0192\u00a2\u00e2\u00ea\u00f4\u00fb\u00e1\u00e9\u00f3\u00fa\u00e0\u00e8\u00f2\u00f9\u00e4\u00eb\u00f6\u00fc\u00c5\u00ee\u00d8\u00c6\u00e5\u00ed\u00f8\u00e6\u00c4\u00ec\u00d6\u00dc\u00c9\u00ef\u00df\u00d4\u00c1\u00c3\u00e3\u00d0\u00f0\u00cd\u00cc\u00d3\u00d2\u00d5\u00f5\u0160\u0161\u00da\u0178\u00ff\u00de\u00fe\u00b7\u03bc\u00b6\u00be-\u00bc\u00bd\u00aa\u00ba\u00ab\u25a0\u00bb\u00b1\ufffd",
|
||||||
|
Aliases: []string{"ibm-1051_P100-1995", "ibm-1051", "hp-roman8", "roman8", "r8", "csHPRoman8"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ibm-1276_P100-1995",
|
||||||
|
SubstitutionChar: '?',
|
||||||
|
Repertoire: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&\u2019()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\u2018abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\ufffd\u00a1\u00a2\u00a3\u2044\u00a5\u0192\u00a7\u00a4'\u201c\u00ab\u2039\u203a\ufb01\ufb02\ufffd\u2013\u2020\u2021\u00b7\ufffd\u00b6\u2022\u201a\u201e\u201d\u00bb\u2026\u2030\ufffd\u00bf\ufffd`\u00b4\u02c6\u02dc\u00af\u02d8\u02d9\u00a8\ufffd\u02da\u00b8\ufffd\u02dd\u02db\u02c7\u2014\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u00c6\ufffd\u00aa\ufffd\ufffd\ufffd\ufffd\u0141\u00d8\u0152\u00ba\ufffd\ufffd\ufffd\ufffd\ufffd\u00e6\ufffd\ufffd\ufffd\u0131\ufffd\ufffd\u0142\u00f8\u0153\u00df\ufffd\ufffd\ufffd\ufffd",
|
||||||
|
Aliases: []string{"ibm-1276_P100-1995", "ibm-1276", "Adobe-Standard-Encoding", "csAdobeStandardEncoding"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ebcdic-xml-us",
|
||||||
|
SubstitutionChar: 0x6f,
|
||||||
|
Repertoire: "\x00\x01\x02\x03\u009c\t\u0086\x7f\u0097\u008d\u008e\v\f\r\x0e\x0f\x10\x11\x12\x13\u009d\n\b\u0087\x18\x19\u0092\u008f\x1c\x1d\x1e\x1f\u0080\u0081\u0082\u0083\u0084\n\x17\x1b\u0088\u0089\u008a\u008b\u008c\x05\x06\a\u0090\u0091\x16\u0093\u0094\u0095\u0096\x04\u0098\u0099\u009a\u009b\x14\x15\u009e\x1a \u00a0\u00e2\u00e4\u00e0\u00e1\u00e3\u00e5\u00e7\u00f1\u00a2.<(+|&\u00e9\u00ea\u00eb\u00e8\u00ed\u00ee\u00ef\u00ec\u00df!$*);\u00ac-/\u00c2\u00c4\u00c0\u00c1\u00c3\u00c5\u00c7\u00d1\u00a6,%_>?\u00f8\u00c9\u00ca\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc`:#@'=\"\u00d8abcdefghi\u00ab\u00bb\u00f0\u00fd\u00fe\u00b1\u00b0jklmnopqr\u00aa\u00ba\u00e6\u00b8\u00c6\u20ac\u00b5~stuvwxyz\u00a1\u00bf\u00d0\u00dd\u00de\u00ae^\u00a3\u00a5\u00b7\u00a9\u00a7\u00b6\u00bc\u00bd\u00be[]\u00af\u00a8\u00b4\u00d7{ABCDEFGHI\u00ad\u00f4\u00f6\u00f2\u00f3\u00f5}JKLMNOPQR\u00b9\u00fb\u00fc\u00f9\u00fa\u00ff\\\u00f7STUVWXYZ\u00b2\u00d4\u00d6\u00d2\u00d3\u00d50123456789\u00b3\u00db\u00dc\u00d9\u00da\u009f",
|
||||||
|
Aliases: []string{"ebcdic-xml-us"},
|
||||||
|
},
|
||||||
|
}
|
76
modules/mahonia/ASCII.go
Normal file
76
modules/mahonia/ASCII.go
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package mahonia
|
||||||
|
|
||||||
|
// Converters for ASCII and ISO-8859-1
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for i := 0; i < len(asciiCharsets); i++ {
|
||||||
|
RegisterCharset(&asciiCharsets[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var asciiCharsets = []Charset{
|
||||||
|
{
|
||||||
|
Name: "US-ASCII",
|
||||||
|
NewDecoder: func() Decoder { return decodeASCIIRune },
|
||||||
|
NewEncoder: func() Encoder { return encodeASCIIRune },
|
||||||
|
Aliases: []string{"ASCII", "US", "ISO646-US", "IBM367", "cp367", "ANSI_X3.4-1968", "iso-ir-6", "ANSI_X3.4-1986", "ISO_646.irv:1991", "csASCII"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ISO-8859-1",
|
||||||
|
NewDecoder: func() Decoder { return decodeLatin1Rune },
|
||||||
|
NewEncoder: func() Encoder { return encodeLatin1Rune },
|
||||||
|
Aliases: []string{"latin1", "ISO Latin 1", "IBM819", "cp819", "ISO_8859-1:1987", "iso-ir-100", "l1", "csISOLatin1"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeASCIIRune(p []byte) (c rune, size int, status Status) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
status = NO_ROOM
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b := p[0]
|
||||||
|
if b > 127 {
|
||||||
|
return 0xfffd, 1, INVALID_CHAR
|
||||||
|
}
|
||||||
|
return rune(b), 1, SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeASCIIRune(p []byte, c rune) (size int, status Status) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
status = NO_ROOM
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if c < 128 {
|
||||||
|
p[0] = byte(c)
|
||||||
|
return 1, SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
p[0] = '?'
|
||||||
|
return 1, INVALID_CHAR
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeLatin1Rune(p []byte) (c rune, size int, status Status) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
status = NO_ROOM
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return rune(p[0]), 1, SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeLatin1Rune(p []byte, c rune) (size int, status Status) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
status = NO_ROOM
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if c < 256 {
|
||||||
|
p[0] = byte(c)
|
||||||
|
return 1, SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
p[0] = '?'
|
||||||
|
return 1, INVALID_CHAR
|
||||||
|
}
|
13707
modules/mahonia/big5-data.go
Normal file
13707
modules/mahonia/big5-data.go
Normal file
File diff suppressed because it is too large
Load diff
89
modules/mahonia/big5.go
Normal file
89
modules/mahonia/big5.go
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
package mahonia
|
||||||
|
|
||||||
|
// Converters for Big 5 encoding.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterCharset(&Charset{
|
||||||
|
Name: "Big5",
|
||||||
|
Aliases: []string{"csBig5"},
|
||||||
|
NewDecoder: func() Decoder {
|
||||||
|
return decodeBig5Rune
|
||||||
|
},
|
||||||
|
NewEncoder: func() Encoder {
|
||||||
|
big5Once.Do(reverseBig5Table)
|
||||||
|
return encodeBig5Rune
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeBig5Rune(p []byte) (r rune, size int, status Status) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
status = NO_ROOM
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b := p[0]
|
||||||
|
if b < 128 {
|
||||||
|
return rune(b), 1, SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p) < 2 {
|
||||||
|
status = NO_ROOM
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c := int(p[0])<<8 + int(p[1])
|
||||||
|
c = int(big5ToUnicode[c])
|
||||||
|
if c > 0 {
|
||||||
|
return rune(c), 2, SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0xfffd, 1, INVALID_CHAR
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeBig5Rune(p []byte, r rune) (size int, status Status) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
status = NO_ROOM
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if r < 128 {
|
||||||
|
p[0] = byte(r)
|
||||||
|
return 1, SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p) < 2 {
|
||||||
|
status = NO_ROOM
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if r < 0x10000 {
|
||||||
|
c := unicodeToBig5[r]
|
||||||
|
if c > 0 {
|
||||||
|
p[0] = byte(c >> 8)
|
||||||
|
p[1] = byte(c)
|
||||||
|
return 2, SUCCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p[0] = '?'
|
||||||
|
return 1, INVALID_CHAR
|
||||||
|
}
|
||||||
|
|
||||||
|
var big5Once sync.Once
|
||||||
|
|
||||||
|
var unicodeToBig5 []uint16
|
||||||
|
|
||||||
|
func reverseBig5Table() {
|
||||||
|
unicodeToBig5 = make([]uint16, 65536)
|
||||||
|
|
||||||
|
for big5, unicode := range big5ToUnicode {
|
||||||
|
if unicode > 0 {
|
||||||
|
unicodeToBig5[unicode] = uint16(big5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
115
modules/mahonia/charset.go
Normal file
115
modules/mahonia/charset.go
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
// This package is a character-set conversion library for Go.
|
||||||
|
//
|
||||||
|
// (DEPRECATED: use code.google.com/p/go.text/encoding, perhaps along with
|
||||||
|
// code.google.com/p/go.net/html/charset)
|
||||||
|
package mahonia
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Status is the type for the status return value from a Decoder or Encoder.
|
||||||
|
type Status int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SUCCESS means that the character was converted with no problems.
|
||||||
|
SUCCESS = Status(iota)
|
||||||
|
|
||||||
|
// INVALID_CHAR means that the source contained invalid bytes, or that the character
|
||||||
|
// could not be represented in the destination encoding.
|
||||||
|
// The Encoder or Decoder should have output a substitute character.
|
||||||
|
INVALID_CHAR
|
||||||
|
|
||||||
|
// NO_ROOM means there were not enough input bytes to form a complete character,
|
||||||
|
// or there was not enough room in the output buffer to write a complete character.
|
||||||
|
// No bytes were written, and no internal state was changed in the Encoder or Decoder.
|
||||||
|
NO_ROOM
|
||||||
|
|
||||||
|
// STATE_ONLY means that bytes were read or written indicating a state transition,
|
||||||
|
// but no actual character was processed. (Examples: byte order marks, ISO-2022 escape sequences)
|
||||||
|
STATE_ONLY
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Decoder is a function that decodes a character set, one character at a time.
|
||||||
|
// It works much like utf8.DecodeRune, but has an aditional status return value.
|
||||||
|
type Decoder func(p []byte) (c rune, size int, status Status)
|
||||||
|
|
||||||
|
// An Encoder is a function that encodes a character set, one character at a time.
|
||||||
|
// It works much like utf8.EncodeRune, but has an additional status return value.
|
||||||
|
type Encoder func(p []byte, c rune) (size int, status Status)
|
||||||
|
|
||||||
|
// A Charset represents a character set that can be converted, and contains functions
|
||||||
|
// to create Converters to encode and decode strings in that character set.
|
||||||
|
type Charset struct {
|
||||||
|
// Name is the character set's canonical name.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Aliases returns a list of alternate names.
|
||||||
|
Aliases []string
|
||||||
|
|
||||||
|
// NewDecoder returns a Decoder to convert from the charset to Unicode.
|
||||||
|
NewDecoder func() Decoder
|
||||||
|
|
||||||
|
// NewEncoder returns an Encoder to convert from Unicode to the charset.
|
||||||
|
NewEncoder func() Encoder
|
||||||
|
}
|
||||||
|
|
||||||
|
// The charsets are stored in charsets under their canonical names.
|
||||||
|
var charsets = make(map[string]*Charset)
|
||||||
|
|
||||||
|
// aliases maps their aliases to their canonical names.
|
||||||
|
var aliases = make(map[string]string)
|
||||||
|
|
||||||
|
// simplifyName converts a name to lower case and removes non-alphanumeric characters.
|
||||||
|
// This is how the names are used as keys to the maps.
|
||||||
|
func simplifyName(name string) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for _, c := range name {
|
||||||
|
switch {
|
||||||
|
case unicode.IsDigit(c):
|
||||||
|
buf.WriteRune(c)
|
||||||
|
case unicode.IsLetter(c):
|
||||||
|
buf.WriteRune(unicode.ToLower(c))
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterCharset adds a charset to the charsetMap.
|
||||||
|
func RegisterCharset(cs *Charset) {
|
||||||
|
name := cs.Name
|
||||||
|
charsets[name] = cs
|
||||||
|
aliases[simplifyName(name)] = name
|
||||||
|
for _, alias := range cs.Aliases {
|
||||||
|
aliases[simplifyName(alias)] = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCharset fetches a charset by name.
|
||||||
|
// If the name is not found, it returns nil.
|
||||||
|
func GetCharset(name string) *Charset {
|
||||||
|
return charsets[aliases[simplifyName(name)]]
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDecoder returns a Decoder to decode the named charset.
|
||||||
|
// If the name is not found, it returns nil.
|
||||||
|
func NewDecoder(name string) Decoder {
|
||||||
|
cs := GetCharset(name)
|
||||||
|
if cs == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return cs.NewDecoder()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEncoder returns an Encoder to encode the named charset.
|
||||||
|
func NewEncoder(name string) Encoder {
|
||||||
|
cs := GetCharset(name)
|
||||||
|
if cs == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return cs.NewEncoder()
|
||||||
|
}
|
135
modules/mahonia/convert_string.go
Normal file
135
modules/mahonia/convert_string.go
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
package mahonia
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConvertString converts a string from UTF-8 to e's encoding.
|
||||||
|
func (e Encoder) ConvertString(s string) string {
|
||||||
|
dest := make([]byte, len(s)+10)
|
||||||
|
destPos := 0
|
||||||
|
|
||||||
|
for _, rune := range s {
|
||||||
|
retry:
|
||||||
|
size, status := e(dest[destPos:], rune)
|
||||||
|
|
||||||
|
if status == NO_ROOM {
|
||||||
|
newDest := make([]byte, len(dest)*2)
|
||||||
|
copy(newDest, dest)
|
||||||
|
dest = newDest
|
||||||
|
goto retry
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == STATE_ONLY {
|
||||||
|
destPos += size
|
||||||
|
goto retry
|
||||||
|
}
|
||||||
|
|
||||||
|
destPos += size
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(dest[:destPos])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertString converts a string from d's encoding to UTF-8.
|
||||||
|
func (d Decoder) ConvertString(s string) string {
|
||||||
|
bytes := []byte(s)
|
||||||
|
runes := make([]rune, len(s))
|
||||||
|
destPos := 0
|
||||||
|
|
||||||
|
for len(bytes) > 0 {
|
||||||
|
c, size, status := d(bytes)
|
||||||
|
|
||||||
|
if status == STATE_ONLY {
|
||||||
|
bytes = bytes[size:]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == NO_ROOM {
|
||||||
|
c = 0xfffd
|
||||||
|
size = len(bytes)
|
||||||
|
status = INVALID_CHAR
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = bytes[size:]
|
||||||
|
runes[destPos] = c
|
||||||
|
destPos++
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(runes[:destPos])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertStringOK converts a string from UTF-8 to e's encoding. It also
|
||||||
|
// returns a boolean indicating whether every character was converted
|
||||||
|
// successfully.
|
||||||
|
func (e Encoder) ConvertStringOK(s string) (result string, ok bool) {
|
||||||
|
dest := make([]byte, len(s)+10)
|
||||||
|
destPos := 0
|
||||||
|
ok = true
|
||||||
|
|
||||||
|
for i, r := range s {
|
||||||
|
// The following test is copied from utf8.ValidString.
|
||||||
|
if r == utf8.RuneError && ok {
|
||||||
|
_, size := utf8.DecodeRuneInString(s[i:])
|
||||||
|
if size == 1 {
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
retry:
|
||||||
|
size, status := e(dest[destPos:], r)
|
||||||
|
|
||||||
|
switch status {
|
||||||
|
case NO_ROOM:
|
||||||
|
newDest := make([]byte, len(dest)*2)
|
||||||
|
copy(newDest, dest)
|
||||||
|
dest = newDest
|
||||||
|
goto retry
|
||||||
|
|
||||||
|
case STATE_ONLY:
|
||||||
|
destPos += size
|
||||||
|
goto retry
|
||||||
|
|
||||||
|
case INVALID_CHAR:
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
|
||||||
|
destPos += size
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(dest[:destPos]), ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertStringOK converts a string from d's encoding to UTF-8.
|
||||||
|
// It also returns a boolean indicating whether every character was converted
|
||||||
|
// successfully.
|
||||||
|
func (d Decoder) ConvertStringOK(s string) (result string, ok bool) {
|
||||||
|
bytes := []byte(s)
|
||||||
|
runes := make([]rune, len(s))
|
||||||
|
destPos := 0
|
||||||
|
ok = true
|
||||||
|
|
||||||
|
for len(bytes) > 0 {
|
||||||
|
c, size, status := d(bytes)
|
||||||
|
|
||||||
|
switch status {
|
||||||
|
case STATE_ONLY:
|
||||||
|
bytes = bytes[size:]
|
||||||
|
continue
|
||||||
|
|
||||||
|
case NO_ROOM:
|
||||||
|
c = 0xfffd
|
||||||
|
size = len(bytes)
|
||||||
|
ok = false
|
||||||
|
|
||||||
|
case INVALID_CHAR:
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = bytes[size:]
|
||||||
|
runes[destPos] = c
|
||||||
|
destPos++
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(runes[:destPos]), ok
|
||||||
|
}
|
76
modules/mahonia/cp51932.go
Normal file
76
modules/mahonia/cp51932.go
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package mahonia
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Converters for Microsoft's version of the EUC-JP encoding
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterCharset(&Charset{
|
||||||
|
Name: "cp51932",
|
||||||
|
Aliases: []string{"windows-51932"},
|
||||||
|
NewDecoder: func() Decoder {
|
||||||
|
return decodeCP51932
|
||||||
|
},
|
||||||
|
NewEncoder: func() Encoder {
|
||||||
|
msJISTable.Reverse()
|
||||||
|
return encodeCP51932
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeCP51932(p []byte) (c rune, size int, status Status) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
return 0, 0, NO_ROOM
|
||||||
|
}
|
||||||
|
|
||||||
|
b := p[0]
|
||||||
|
switch {
|
||||||
|
case b < 0x80:
|
||||||
|
return rune(b), 1, SUCCESS
|
||||||
|
|
||||||
|
case b == 0x8e:
|
||||||
|
if len(p) < 2 {
|
||||||
|
return 0, 0, NO_ROOM
|
||||||
|
}
|
||||||
|
b2 := p[1]
|
||||||
|
if b2 < 0xa1 || b2 > 0xdf {
|
||||||
|
return utf8.RuneError, 1, INVALID_CHAR
|
||||||
|
}
|
||||||
|
return rune(b2) + (0xff61 - 0xa1), 2, SUCCESS
|
||||||
|
|
||||||
|
case 0xa1 <= b && b <= 0xfe:
|
||||||
|
return msJISTable.DecodeHigh(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return utf8.RuneError, 1, INVALID_CHAR
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeCP51932(p []byte, c rune) (size int, status Status) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
return 0, NO_ROOM
|
||||||
|
}
|
||||||
|
|
||||||
|
if c < 0x80 {
|
||||||
|
p[0] = byte(c)
|
||||||
|
return 1, SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p) < 2 {
|
||||||
|
return 0, NO_ROOM
|
||||||
|
}
|
||||||
|
|
||||||
|
if c > 0xffff {
|
||||||
|
p[0] = '?'
|
||||||
|
return 1, INVALID_CHAR
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0xff61 <= c && c <= 0xff9f {
|
||||||
|
p[0] = 0x8e
|
||||||
|
p[1] = byte(c - (0xff61 - 0xa1))
|
||||||
|
return 2, SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
return msJISTable.EncodeHigh(p, c)
|
||||||
|
}
|
179
modules/mahonia/entity.go
Normal file
179
modules/mahonia/entity.go
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
package mahonia
|
||||||
|
|
||||||
|
// decoding HTML entities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EntityDecoder returns a Decoder that decodes HTML character entities.
|
||||||
|
// If there is no valid character entity at the current position, it returns INVALID_CHAR.
|
||||||
|
// So it needs to be combined with another Decoder via FallbackDecoder.
|
||||||
|
func EntityDecoder() Decoder {
|
||||||
|
var leftover rune // leftover rune from two-rune entity
|
||||||
|
return func(p []byte) (r rune, size int, status Status) {
|
||||||
|
if leftover != 0 {
|
||||||
|
r = leftover
|
||||||
|
leftover = 0
|
||||||
|
return r, 0, SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p) == 0 {
|
||||||
|
return 0, 0, NO_ROOM
|
||||||
|
}
|
||||||
|
|
||||||
|
if p[0] != '&' {
|
||||||
|
return 0xfffd, 1, INVALID_CHAR
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p) < 3 {
|
||||||
|
return 0, 1, NO_ROOM
|
||||||
|
}
|
||||||
|
|
||||||
|
r, size, status = 0xfffd, 1, INVALID_CHAR
|
||||||
|
n := 1 // number of bytes read so far
|
||||||
|
|
||||||
|
if p[n] == '#' {
|
||||||
|
n++
|
||||||
|
c := p[n]
|
||||||
|
hex := false
|
||||||
|
if c == 'x' || c == 'X' {
|
||||||
|
hex = true
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
|
||||||
|
var x rune
|
||||||
|
for n < len(p) {
|
||||||
|
c = p[n]
|
||||||
|
n++
|
||||||
|
if hex {
|
||||||
|
if '0' <= c && c <= '9' {
|
||||||
|
x = 16*x + rune(c) - '0'
|
||||||
|
continue
|
||||||
|
} else if 'a' <= c && c <= 'f' {
|
||||||
|
x = 16*x + rune(c) - 'a' + 10
|
||||||
|
continue
|
||||||
|
} else if 'A' <= c && c <= 'F' {
|
||||||
|
x = 16*x + rune(c) - 'A' + 10
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if '0' <= c && c <= '9' {
|
||||||
|
x = 10*x + rune(c) - '0'
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if c != ';' {
|
||||||
|
n--
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if n == len(p) && p[n-1] != ';' {
|
||||||
|
return 0, 0, NO_ROOM
|
||||||
|
}
|
||||||
|
|
||||||
|
size = n
|
||||||
|
if p[n-1] == ';' {
|
||||||
|
n--
|
||||||
|
}
|
||||||
|
if hex {
|
||||||
|
n--
|
||||||
|
}
|
||||||
|
n--
|
||||||
|
// Now n is the number of actual digits read.
|
||||||
|
if n == 0 {
|
||||||
|
return 0xfffd, 1, INVALID_CHAR
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0x80 <= x && x <= 0x9F {
|
||||||
|
// Replace characters from Windows-1252 with UTF-8 equivalents.
|
||||||
|
x = replacementTable[x-0x80]
|
||||||
|
} else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF {
|
||||||
|
// Replace invalid characters with the replacement character.
|
||||||
|
return 0xfffd, size, INVALID_CHAR
|
||||||
|
}
|
||||||
|
|
||||||
|
r = x
|
||||||
|
status = SUCCESS
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for a named entity in EntityList.
|
||||||
|
|
||||||
|
possible := entityList
|
||||||
|
for len(possible) > 0 {
|
||||||
|
if len(p) <= n {
|
||||||
|
leftover = 0
|
||||||
|
return 0, 0, NO_ROOM
|
||||||
|
}
|
||||||
|
|
||||||
|
c := p[n]
|
||||||
|
|
||||||
|
// Narrow down the selection in possible to those items that have c in the
|
||||||
|
// appropriate byte.
|
||||||
|
first := sort.Search(len(possible), func(i int) bool {
|
||||||
|
e := possible[i].name
|
||||||
|
if len(e) < n {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return e[n-1] >= c
|
||||||
|
})
|
||||||
|
possible = possible[first:]
|
||||||
|
last := sort.Search(len(possible), func(i int) bool {
|
||||||
|
return possible[i].name[n-1] > c
|
||||||
|
})
|
||||||
|
possible = possible[:last]
|
||||||
|
|
||||||
|
n++
|
||||||
|
if len(possible) > 0 && len(possible[0].name) == n-1 {
|
||||||
|
r, leftover = possible[0].r1, possible[0].r2
|
||||||
|
size = n
|
||||||
|
status = SUCCESS
|
||||||
|
// but don't return yet, since we need the longest match
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This table is copied from /src/pkg/html/escape.go in the Go source
|
||||||
|
//
|
||||||
|
// These replacements permit compatibility with old numeric entities that
|
||||||
|
// assumed Windows-1252 encoding.
|
||||||
|
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
|
||||||
|
var replacementTable = [...]rune{
|
||||||
|
'\u20AC', // First entry is what 0x80 should be replaced with.
|
||||||
|
'\u0081',
|
||||||
|
'\u201A',
|
||||||
|
'\u0192',
|
||||||
|
'\u201E',
|
||||||
|
'\u2026',
|
||||||
|
'\u2020',
|
||||||
|
'\u2021',
|
||||||
|
'\u02C6',
|
||||||
|
'\u2030',
|
||||||
|
'\u0160',
|
||||||
|
'\u2039',
|
||||||
|
'\u0152',
|
||||||
|
'\u008D',
|
||||||
|
'\u017D',
|
||||||
|
'\u008F',
|
||||||
|
'\u0090',
|
||||||
|
'\u2018',
|
||||||
|
'\u2019',
|
||||||
|
'\u201C',
|
||||||
|
'\u201D',
|
||||||
|
'\u2022',
|
||||||
|
'\u2013',
|
||||||
|
'\u2014',
|
||||||
|
'\u02DC',
|
||||||
|
'\u2122',
|
||||||
|
'\u0161',
|
||||||
|
'\u203A',
|
||||||
|
'\u0153',
|
||||||
|
'\u009D',
|
||||||
|
'\u017E',
|
||||||
|
'\u0178', // Last entry is 0x9F.
|
||||||
|
// 0x00->'\uFFFD' is handled programmatically.
|
||||||
|
// 0x0D->'\u000D' is a no-op.
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue