HTTP方法中PUT与POST的区别

HTTP中的PUT和POST方法通常被用于创建和更新页面上的对象,但如何更精确地区分它们的区别呢?

幂等的概念

PUT与POST方法最根本的区别是PUT是幂等的,所谓幂等是指“ PUT 方法是幂等的。幂等的方法意味着请求成功执行所得到的的结果不依赖于该方法被执行的次数。”

Example

为了更好的理解幂等,这里有一个例子:

在设计图书馆的restful接口时,设计了一个创建用户的API,用户使用user{id,name}来定义

这时候需要用API创建一个新的名字为White的user,id则为自增

POST: 若该用户不存在,创建一个新用户,返回201
      若已经存在,则返回409 - Conflict

PUT: 若该用户不存在,创建一个新用户,返回201
     若已经存在,返回200或者202
  • 注意:在设计restful接口的时候,尽量要符合restful的设计规范,使POST和PUT的区别在设计中能够显现。

SQLAlchemy及ORM笔记

前言

ORM是把Object-Oriented Programming language和SQL语句做映射的工具,而其中SQLAlchemy就是python中的其中一个ORM框架,在上Designing Restful API 这门Udacity公开课的时候接触到了ORM和SQLAlchemy,于是想记录一下他们的概念和用法

SQLAlchemy的安装条件

  • Python 2.6+
  • Python 3.3+
  • Pypy 2.1+

    pip install sqlalchemy
    

安装数据库驱动

SQLAlchemy默认支持SQLite3,不需要安装驱动,但对其他数据库都需要用符合Python的DBAPI标准的驱动。

PostgreSQL

Psycopg2提供了PostgreSQL的驱动,可以用pip install psycopg2安装

Mysql

PyMySQL是mysql的驱动,可以用pip install pymysql安装

连接数据库

from sqlalchemy import create_engine
engine = create_engine('sqlite:///puppies.db')

如何授予远程登录mysql的主机访问权限

步骤

  1. 登录mysql主机

    譬如mysql的用户名密码为 host,host123

  2. 键入命令

    GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'host123';
    
    • % 在这里是指所有主机的意思,即赋予所有其他host登录权限
    • Identified by后面跟的是mysql对应用户名root的密码,这里是host123
  3. 键入命令

    flush priviledges;
    

    更新mysql中的权限设置

这样修改权限设置之后,就可以在主机上远程访问该ip下的mysql数据库了

在pycharm中安装lib的方法非常简单

  1. 打开File-> Setting
  2. 选择Project:你需要添加lib的project
  3. 点击Project Interpreter
  4. 点击添加按钮

  1. 输入要添加的lib名字,搜索得到结果后安装即可

前言

Git是一个很强大的version control工具,从入门coding开始的那天工作和日常就离不开git,但是git的这些常用命令有时候还是会忘记,我在这里把git commands大概的记录下来,已方便自己的查阅。

设定你的Git

设定作者的信息

git config --global user.name "jimmy kuo"
git config --global user.email "jimmy@gogojimmy.net"

查看git的设定

git config -- list

建立自己的Git Repository

自己建立一个新的Repository

git init

Clone别人的Repository

git clone

Git的基本功(status, add, commit, log, .gitignore)

查看git repository的修改状况

git status 

Untracked files(未被追踪的files,新增/修改的files还没被提交到git repository上的)

git add *

提交后状态变为 Changes to be committed

changes to be commited

committed之后的状态叫做stage,修改过但还没使用git add的file叫做unstage

git log

查看过去commit的记录

git log –stat

git log -p

更详细的变更内容,具体到代码

Git流程整理

修改file -> 加入stage(git add) -> 提交(git commit)-> 继续修改其他file

Git Branch

查看当前branch

git branch

开一个新的branch,名叫cat

git branch cat

切换到别的branch

git checkout cat

合并branch到master branch

基于master branch目前最后一次的commit内容再往后把你在cat branch上commit的内容加上去

git rebase

查看master branch和其他branch的差异

git diff

把cat branch上开发的东西合并到master上

git merge cat

Confict: 冲突处理

通常在merge或是rebase的过程中产生了confict,这时候git会停下来请你去处理

  1. 将发生confict的档案打开,处理内容(删除<<<.===,>>>)
  2. 使用git add 将处理好的file加入stage
  3. 反复1~2直到所有confict处理完毕
  4. git commit提交合并信息
  5. 完成

取消上一次的操作

取消刚刚的merge动作

git reset --hard ORIG_HEAD

取消已暂存的file

取消刚刚add到stage中还没修改完的file

git reset HEAD file

取消刚刚修改过的file

git checkout -- file

回复前修改的档案要记得备份

修改上一次的commit讯息

git commit --amend

强制恢复到上一次commit的版本

git reset --hard HEAD

恢复到上一次commit的版本,HEAD^指目前版本的上一个版本,Head~2是再上一个

  • git reset, hard 與 soft 的差異

你可能會在這邊感到疑惑,在使用 git reset 的時候都會看到一個 soft 或是 hard 的參數,這代表什麼樣的意義?基本上在使用 git reset 的時候,都會把目前狀態回復到你想回復的版本,但若是不加參數的情況,會把你做過的修改仍然保留,但是,若是加上 —soft 參數,則會把做過的修改加入 stage ,若是加上 hard 參數的話則是把做過的修改完全刪除,回到那個版本原本的樣子。

暂存操作(Stash)

将目前所做的修改都暂存起来

git stash

取出最新一次的暂存

git stash appl

取出最新一次的暂存并将他从暂存清单中移除

git stash pop

显示出所有的暂存清单

git stash list

清楚所有的暂存

git stash clear

Git情景剧:在什么情况下该使用什么命令

最近一直在做公司数据湖的项目,我们用的是Apache正在incubating的开源项目atlas, atlas在管理元数据方面的功能十分强大。

这篇blog是介绍如何在centos中编译和安装atlas

Atlas的安装和编译

编译Atlas

  1. 从git下载源码库

    git clone https://git-wip-us.apache.org/repos/asf/incubator-atlas.git atlas
    git checkout altas-0.7-incubating
    
  2. 切换到atlas文件夹

    cd atlas
    
  3. 编译atlas

    export MAVEN_OPTS="-Xmx1536m -XX:MaxPermSize=512m" && mvn clean install -DskipTests -Drat.numUnapprovedLicenses=100
    
  4. skip Licenses

    http://stackoverflow.com/questions/30181154/skipping-some-license-tests-in-maven
    
    -Drat.numUnapprovedLicenses=100
    
  5. Skip test cases

    mvn install 
    

Atlas编译要求

  1. maven版本到3.1.0以上

Atlas安装与配置

  1. mvn clean package -Pdist -DskipTests
  2. 编译完之后解压生成的tar包

    tar -xzvf apache-atlas-${project.version}-bin.tar.gz
    cd atlas-${project.version}
    
  3. 配置atlas参数

    所有atlas参数配置都在conf文件夹下,这里主要修改atlas-application.properties的配置

    配置kafka相关参数

    atlas.notification.embedded=false
    atlas.kafka.data=${sys:atlas.home}/data/kafka
    atlas.kafka.zookeeper.connect=localhost:2181
    atlas.kafka.bootstrap.servers=fsdn1:6667
    

    配置Zookeeper相关参数

    atlas.audit.hbase.zookeeper.quorum={zookeeeper_host}:2181
    

启动atlas

bin/atlas_start.py 

这样可在浏览器中输入:http://localhost:21000,就可以打开atlas的web页面

错误排查

Kafka启动失败

论坛提问: https://community.hortonworks.com/questions/67795/fail-to-start-kafka-when-starting-the-atlas.html

关闭Zookeeper,报错Connection Refused
开启Zookeeper,报错cannot assign requested address

Resolution:
修改Kafka相关参数:

atlas.notification.embedded=false

参考资料 – 集成atlas与kafka

UI Keep Loading

如图:

论坛提问贴 – 多亏了这个帖子,找到了解决方案

Resolution:

根据论坛的回复,有两个解决方案,我用了第一种,就是下载hdp2.5然后把atlas web相关的文件夹覆盖掉0.7的文件夹

  1. I have replaced web folder from Sandbox(HDP 2.5 with Atlas 0.7) and it worked fine.

    下载HDP2.5,找到usr/hdp/2.5.0.0-1245/atlas文件夹,将其中的web相关文件夹copy and replace原本atlas的对应文件夹
    ![](http://i.imgur.com/CEvYjx5.png)
    
  2. Download the patch and git apply it – ATLAS-1199-PATCH

    Git Apply Patch Failed (http://www.fwolf.com/blog/post/448)

    $ git apply --reject 0001-BUG-Sybase.patch
    Checking patch source.php...
    error: while searching for:
            // 注释
            // 以下为几行代码片断
    error: patch failed: source.php:38
    Applying patch source.php with 1 rejects...
    Rejected hunk #1.
    
  3. Full Authentication needed to access the Atlas API

    论坛帖子

    Per default, Atlas uses Basic Authentication. So use your Atlas user and password, e.g. like

    curl -s -u admin:admin http://atlas-server:21000/api/atlas/types
    
  4. Out of Memory

    https://cwiki.apache.org//confluence/display/MAVEN/OutOfMemoryError
    

系统要求

  • Java Development Kit (JDK)

    Maven 3.3 需安装JDK 1.7及以上版本
    
  • Memory

    没有特别要求
    
  • Disk

    安装maven大概需要10M左右的硬盘,除此以外,对于本地的maven仓库也需要额外的硬盘空间,这取决于你的使用情况,但理想状况下最好留出至少500M的硬盘空间
    
  • Operating System

    没有特别要求
    

下载安装包

wget http://mirrors.cnnic.cn/apache/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz

解压及安装

tar xzvf apache-maven-3.3.9-bin.tar.gz

修改环境变量 – 把opt改为apache maven的当前路径

export PATH=/opt/apache-maven-3.3.9/bin:$PATH

在配置文件中修改

/etc/profile
export PATH=/opt/apache-maven-3.3.9/bin:$PATH

安装确认

mvn -v

结果应显示为

Apache Maven 3.3.3 (7994120775791599e205a5524ec3e0dfe41d4a06; 2015-04-22T04:57:37-07:00)
Maven home: /opt/apache-maven-3.3.3
Java version: 1.8.0_45, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.8.5", arch: "x86_64", family: "mac"

安装Pyhs2

在CentOS上安装Pyhs2流程如下:

  • https://pypi.python.org/pypi/ez_setup 下载ez_setup的tar包

    - tar -vzxf ez_setup-**.tar.gz
    - python ez_setup.py
    - easy_install pip
    - yum install gcc-c++
    - yum install cyrus-sasl-devel.x86_64
    - yum install python-devel.x86_64
    - pip install pyhs2
    

解决No Mechanism Available问题

thrift.transport.TTransport.TTransportException: Could not start SASL: Error in sasl_client_start (-4) SASL(-4): no mechanism available: No worthy mechs found
  1. 检查是否安装所有配置所需要的包

    rpm -qa | grep cyrus
    

    至少需要有以下包

    cyrus-sasl-lib-2.1.23-15.el6_6.2.x86_64
    cyrus-sasl-plain-2.1.23-15.el6_6.2.x86_64
    cyrus-sasl-md5-2.1.23-15.el6_6.2.x86_64
    cyrus-sasl-devel-2.1.23-15.el6_6.2.x86_64
    cyrus-sasl-2.1.23-15.el6_6.2.x86_64
    cyrus-sasl-gssapi-2.1.23-15.el6_6.2.x86_64
    

    没有的话,yum install 安装所需的包

  2. 检查hive-site.xml配置
    到 /etc/hive/conf/hive-site.xml 查看配置

其中

<property>
  <name>hive.server2.authentication</name>
  <value>KERBEROS</value>
</property>

可以把Value值改成NOSASL/PLAIN,etc

More Info

Python代码

import pyhs2

引入pyhs2 lib

hive_client = HiveClient(db_host='192.168.100.173', port=10000, user='user', password='password', database='default', authMechanism='PLAIN')

连接到Hive服务器,其中host为hive主机的ip地址,port默认为10000,用户名密码不能为空,authMechanism的值必须与hive-site.xml配置文件中hive.server2.authentication的值相同。

class HiveClient:
    # create connection to hive server2
    def __init__(self, db_host, user, password, database, port=10000, authMechanism="PLAIN"):
        self.conn = pyhs2.connect(host=db_host,
                                  port=port,
                                  authMechanism=authMechanism,
                                  user=user,
                                  password=password,
                                  database=database,
                                  )

    def query(self, sql):
        with self.conn.cursor() as cursor:
            cursor.execute(sql)
            return cursor.fetch()

    def loaddata(self, sql):
        with self.conn.cursor() as cursor:
            cursor.execute(sql)

    def close(self):
        self.conn.close()



def main():
    # 注意authMechanism初始的时候是PLAIN,最好的解决方案是加上认证模块
    hive_client = HiveClient(db_host='192.168.100.171', port=10000, user='root', password='Qianxin123', database='default', authMechanism='PLAIN')
    print "Connect to Hive!"
    # 测试select语句

    sql = 'select * from country1;'
    print sql
    try:
        fetch = hive_client.query(sql)
        for i in fetch:
            print i
        sql = "insert into country1 values(1,/"hello/")"
        hive_client.query(sql)
        sql = 'select * from country1'
        fetch = hive_client.query(sql)
        for i in fetch:
            print i
    except Exception as e:
        print e
    hive_client.close()


if __name__ == '__main__':
    main()

Apache Atlas详解

By Qinglin,Xia

什么是Atlas?

Atlas是数据治理中很重要的一个工具,它通过对元数据(Metadata)的管理,实现Hadoop中各个组件之间数据的流通与交换,亦或是与Hadoop外界组件的数据交流(如Mysql等数据库),从而实现跨平台的数据治理,解决数据孤岛(Data Solo)的问题

数据孤岛与数据湖

数据孤岛

数据孤岛是目前大数据领域面对的一大问题,我们可以把每个企业看做一个数据孤岛,在他们与其他企业进行数据流通的时候,因为数据定义,存储方式和维护方式的不同,使得合并或者交换数据变得异常困难。而当企业发展到一定阶段,每个事业部也可以看做是一个数据孤单,使得企业内部数据流通也出现巨大的困难

数据湖

数据湖是把数据孤岛的数据打通,整合到一起,一个数据湖通常符合这三个条件:

  • 收集所有数据(Collect everything): 数据湖可以包含各种数据,可以有raw data也可以有被处理过的数据
  • 适用于所有场合 (Dive in anywhere):数据湖使各行各业的用户都可以按照他们的标准修改,查看或者丰富里面的数据
  • 灵活的访问模式 (Flexible access): 数据湖支持各种数据访问模式对共享的结构进行访问: batch, interactive, online, search,in-memory,etc

More info: Enterprise Hadoop Journey to Data Lake

Atlas可以做什么?

你面对的问题

  • 你知道你的数据在那里么? Do you know where is your data ?
  • 你知道这个指定数据集由谁负责么? Do you know who is responsible of this specific
    datasets ?
  • 你知道上周五是哪个应用或者任务修改了这块数据么?Do you know from which application or task this entity
    was modified last friday ?

Atlas的解决方式

为了解决数据孤岛的问题,使数据湖得以实现,Hadoop提供了数据治理(Data Governance)的工具,而Apache Atlas就是其中很重要的一个工具。 它主要可以实现以下功能:

  • 搜索和追溯血统(Search and Proscriptive Lineage)– 可以使探究事先定义(pre-define)或者临时的(ad-hoc)数据和元数据变得更便利, 同时保留数据源的历史,便于追溯数据的起源,产生和演变

  • 由元数据驱动的数据访问控制(Ranger + Atlas)

  • 对商业数据(business data)或者工作数据(operational data)灵活建模

  • 数据分类 – help understand the nature of data within Hadoop and classify it based on external and internal sources

  • 与其他元数据工具进行数据交换

Apache Atlas的功能

总结来说,Atlas的功能主要有以下四大类:

数据分类

  • 导入或定义以商业为导向的注解的分类
  • 定义,注解,和自动捕获数据集与底层元素的关系,包括数据来源,数据终点,和获取过程 (Source, Target, and Derivation processes)
  • 导出元数据到第三方系统

集中化审计

  • 得到每个应用,进程的安全访问控制信息
  • 得到execution, steps和activities的操作性信息

搜索 & 血缘(查看)

  • 预先设定查看路径,用以浏览数据分类和信息审计
  • 用以Text为基准的搜索去定位相关的数据
  • 数据集血缘的可视化 Visualization of data set lineage

安全&政策 引擎

  • 在runtime的数据分类机制政策 Policy at runtime based on data classification schemes
  • 定义预防数据掠夺的政策

More Info: Features

Atlas 的架构

主要模块

  • Web应用 (A Web service): 提供了RESTful APIs以及一个Web UI,使用户可以创建,更新和搜索元数据(Metadata)。

  • 元数据仓库 (Metadata store): Falcon用图(graph model)对元数据进行建模,用图数据库Titan对元数据进行具体操作。Titan有一系列的备选仓库可以用来维护图,包括一种嵌入式Berkeley DB, Apache HBase和Apache Cassandra。对备选仓库的选择将决定可选的服务层级。

  • 索引仓库(Index store): 为了使全文搜索在元数据上得以实现,Altas,通过Titan,对元数据建立了索引。而全文检索的备选仓库是像ElasticSearch或是Apache Solr的一个搜索后端。

  • Bridges / Hooks: 为了在Atlas中添加元数据,一种叫做”hooks”的libararis被各种应用启用,像是Apache Hive, Apache Falcon和Apache Sqoop, 它们都可以在各自系统中捕捉元数据events,并把这些events传送到Atlas中。而Atlas服务器则会吸收这些Events并更新他自己的仓库。

  • 元数据提醒events(Metadata notification events): 在Atlas中任意对元数据的更新,不论是通过Hooks或是API,都会通过events从Atlas传送到它下层的应用。像是Apache Ranger这样的应用会吸收这些events然后让管理员对他们进行操作,譬如:对访问控制的政策进行配置。

  • Notification服务器 (Notification Server): Atlas用Apache Kafka作为Notification服务器,使Hooks和它下层的应用可以就元数据提醒事件进行沟通(metadata notification events)。这些事件由hooks和Atlas写入到不同的Kafka主题中。Kafka可以对这些分散的应用实现宽松的成对整合。

Bridges

Bridge/Hook 的主要作用就是使得装有Bridge的应用,在生成一个entity的时候,也会有一个对应的entity在Atlas中生成。

有这样Bridges的应用是:

- Hive Bridge
- Sqoop Bridge
- Falcon Bridge
- Storm Bridge

Notification

Notification被应用于从Hook对Atlas的entity注册,和entity/type交换提醒。这些都由Kafka实现,Atlas启动时也默认启动Kafka Server。

More Info: Atlas Architecture

Apache Atlas的应用

Apache Atlas – Knowledge Store

知识仓库通过以商业为导向的分类学来分类:

  • 数据集合 & 对象 Data sets & objects
  • 表/列 Tables / Columns
  • 逻辑上下文 Logical context
  • 起点,终点 Source, destination

支持Atlas基本模块和外部第三方应用/数据治理工具的元数据交换

Tech:

  • Titan with Apache HBase

Apache Atlas – Data Life Management

功能:

  • 跨集群复制
  • 数据集合保留/驱逐
  • 迟到的数据处理
  • 自动化

Tech:

  • Apache Falcon

Apache Atlas – Audit Store

存储所有数据治理相关的Historical Repository

  • 安全性 Security: 访问权限的给予和拒绝 Access Grant & Deny
  • 功能性 Operational: 数据起源和数据矩阵 Data Provenance &
    Metrics
  • 建立索引,使数据可搜索 Indexed and Searchable

Tech:

  • YARN ATS, Apache HBase, Apache Hive, Solr,
    ElasticSearch
    (Pluggable)

Apache Atlas – Policy Engine


关于数据集合的合并以及时间的(data asset combinations
and time)政策条例

  • 基于元数据的
  • 基于地理位置的条例 Geo based rules
  • 基于时间的条例 Time-based rules
  • 列/属性禁用 Column /Attribute Prohibitions
  • 预览:Hive的行和列隐藏 Preview: Hive Row and Column Masking

Tech:

  • Ranger

Apache Atlas – Security

建立基于数据分类的全球安全条例(global security policies)

Type System

Data Types Overview

Types Instances Overview

有两种在Atlas中搜索元数据的方法:

  • DSL
  • 全文检索

Falcon UI

More Info: Search Feature

Walk Through A Use Case

Collect Data

从Twitter中导入数据,将Raw Data存入HDFS中,并构建四张表(tweets,users,url,Hash tags)将数据分别存入,通过分析生成的表格,构建基于Hive表格的Social Network。

而在这每一步中,生成的数据的元数据都会被存入Atlas。

Search on Atlas

Search based on DB

Search based on Application

表格元数据

血缘

配置环境

Centos服务器+Windows客户端

Github.io

亲爱哒Github为每位用户提供了一个域名,只需注册成为Github用户,将代码提交到指定repository下,就可以在域名下看到自己的网站了。

创建一个repository

在Github下创建一个repository,命名为username.github.io,username就是你的github用户名(如果repository名字和你的github用户名不一致,域名就不会生效)

1
2
譬如:
如果你的github用户名为Gitdog,那么repository就需被命名为Gitdog.github.io

Clone Repository到Linux

将Repository下载到你想存放的文件夹下

  • 去到你想存放repository的文件夹下
  • git clone https://github.com/username/username.github.io

创建一个Hello World页面

  1. cd username.github.io
  2. echo "Hello World" > index.html

将repository上传到Git

  1. git add --all
  2. git commit -m "Initial commit"
  3. git push -u origin master

Done!

这样就完成了github.io域名的搭建,随便找一个浏览器然后打开http://username.github.io查看吧

More Info: 官方文档

Hexo

Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。

Hexo.io官网

安装Node.js

- wget http://nodejs.org/dist/v0.6.1/node-v0.6.1.tar.gz 
- tar -vzxf node-v0.6.1.tar.gz 
- cd node-v0.6.1
- ./configure
- make
- make install

顺利安装完后检查一下是否安装成功

node -V

检查是否返回

v0.6.1

Node.JS

安装Hexo

使用npm命令安装

npm install hexo-cli -g
npm install hexo --save

#如果命令无法运行,可以尝试更换taobao的npm源
npm install -g cnpm --registry=https://registry.npm.taobao.org

初始化Hexo

随意选择自己喜好的位置存放hexo文件夹,最好和之前生成的git repositroy在同一个文件夹下

hexo init

#安装 Hexo 完成后,请执行下列命令,Hexo 将会在指定文件夹中新建所需要的文件。
$ hexo init <folder>
$ cd <folder>
$ npm install

#新建完成后,指定文件夹的目录如下
.
├── _config.yml
├── package.json
├── scaffolds
├── scripts
├── source
|      ├── _drafts
|      └── _posts
└── themes

安装Hexo插件

npm install hexo-generator-index --save
npm install hexo-generator-archive --save
npm install hexo-generator-category --save
npm install hexo-generator-tag --save
npm install hexo-server --save
npm install hexo-deployer-git --save
npm install hexo-deployer-heroku --save
npm install hexo-deployer-rsync --save
npm install hexo-deployer-openshift --save
npm install hexo-renderer-marked@0.2 --save
npm install hexo-renderer-stylus@0.2 --save
npm install hexo-generator-feed@1 --save
npm install hexo-generator-sitemap@1 --save

使用Hexo博客框架搭建Github.io博客

选择Hexo主题

Hexo有许多高大上的博客模板,简单易用,白狗这里用的是Jacman (Jacman)

主题更换方法很简单,一般是去github clone源代码到hexo/themes文件夹下,再修改_config.yml文件下的theme栏

生成博客

1. 执行hexo g命令会生成一个public文件夹
2. 将public文件夹下的内容全部拷贝到git repository文件夹下
3. 将git repository文件夹下的内容同步到github上
4. 刷新http://username.github.io查看吧

下图为搭建完的博客

页面修改

要生成新的页面或修改页面,都需要在hexo init的文件夹下执行hexo命令,再将修改完的结果同步更新到git repository和github上去,就可以在http://username.github.io上看到更新的效果了!

  • 生成新的页面

    hexo new "My new post"

  • 生成静态站点

    hexo generate

  • Run Server

    hexo server

  • 部署站点

    hexo deploy

More Info: Hexo Docs