text:
Source code of debugmyhttp.com

By using the website (www.debugmyhttp.com) or by setting up your own using this code, you create test URLs that you can use in your application. The log view of the site will provide you with the HTTP traffic captured (sent to the test URL) in order to debug your application.

What is included:

#### bucket.py

The bucket.py is responsible for serving the homepage, the log page, generating marker keys and providing a WebSocket connection to the browser.

Features

1. Serves the main homepage
2. Serves the log page
3. It will generate marker keys
4. It will provide WebSocket channel to client browser to push the captured HTTP traffic to the user

Usage:
```
bucket.py options:

  --address                        address to listen on (default 0.0.0.0)
  --channelttl                     redis hash key ttl (default 3600)
  --clientlimit                    client keys limit per ip (default 10)
  --debug                          set Tornado to debug (default True)
  --historylength                  list of last N http requests (default 50)
  --port                           port to listen on (default 5000)
  --redisdb                        redis database (default 0)
  --redishost                      redis server (default 127.0.0.1)
  --redispassword                  redis server password
  --redisport                      redis port (default 6379)
  --requestlimit                   request limit per marker key (default 50)
```

#### grabber.py

The grapper.py is a pcap sniffer. It sniffs for HTTP traffic coming into any interface searching for the marker keys requested by the UI. If the marker key does not exist in REDIS, no traffic is returned. If marked traffic is found it is pushed into REDIS in a pubsub channel.

Features

1. Requires root to run. It will capture HTTP traffic even malformed HTTP. It will scan for traffic in a specific port (--sniffport)
2. Will scan HTTP traffic for the marker key
3. Once traffic is found it will publish it into REDIS
4. It will also push the captured HTTP traffic into a REDIS set (no more than N HTTP requests, defined by the option -t HISTORYLENGTH) for historical purposes
5. Once marked HTTP request captured reaches the limit of -l REQUESTLIMIT then the grabber will stop capturing that marked traffic

Usage:
```
optional arguments:
  -h, --help            show this help message and exit
  -i INTERFACE, --interface INTERFACE
                        select interface to capture HTTP requests on
  -v, --verbose         be more verbose, show HTTP requests as they are
                        captured
  -o REDISHOST, --redishost REDISHOST
                        redis server hostname
  -p REDISPORT, --redisport REDISPORT
                        redis server port
  -b REDISDB, --redisdb REDISDB
                        redis server database
  -s REDISPASSWORD, --redispassword REDISPASSWORD
                        redis server password
  -n SNIFFPORT, --sniffport SNIFFPORT
                        sniffer port
  -c, --promiscuous     use promiscuous mode
  -l REQUESTLIMIT, --requestlimit REQUESTLIMIT
                        request limit per key
  -e CHANNELTTL, --channelttl CHANNELTTL
                        TTL for the channel (set of keys in redis per session)
  -t HISTORYLENGTH, --historylength HISTORYLENGTH
                        number of HTTP requests to keep into a queue for
                        historical purposes
  -k HISTORYKEEP, --historykeep HISTORYKEEP
                        seconds to keep the queue that contains the history of
                        HTTP requests
```

```
$ sudo python grabber.py -i lo -c -n 5000
Available devices: ['enp8s0', 'any', 'lo', 'bluetooth-monitor', 'nflog', 'nfqueue', 'usbmon1', 'usbmon2', 'usbmon3', 'usbmon4', 'usbmon5', 'usbmon6']
Capturing on lo...
Found HTTP request for hash 3080b73b4e
Found HTTP request for hash 3080b73b4e
Found HTTP request for hash 3080b73b4e
Found HTTP request for hash 3080b73b4e
Found HTTP request for hash 3080b73b4e
...
```

#### config/

In the config/ directory you will find sample configuration files for Nginx and Supervisor.


text:
'use strict';

/**
 * This script publishes a new version of react-native to NPM.
 * It is supposed to run in CI environment, not on a developer's machine.
 *
 * To make it easier for developers it uses some logic to identify with which version to publish the package.
 *
 * To cut a branch (and release RC):
 * - Developer: `git checkout -b 0.XY-stable`
 * - Developer: `git tag v0.XY.0-rc` and `git push --tags` to git@github.com:facebook/react-native.git
 * - CI: test and deploy to npm (run this script) with version 0.XY.0-rc with tag "next"
 *
 * To update RC release:
 * - Developer: `git checkout 0.XY-stable`
 * - Developer: cherry-pick whatever changes needed
 * - Developer: `git tag v0.XY.0-rc1` and `git push --tags` to git@github.com:facebook/react-native.git
 * - CI: test and deploy to npm (run this script) with version 0.XY.0-rc1 with tag "next"
 *
 * To publish a release:
 * - Developer: `git checkout 0.XY-stable`
 * - Developer: cherry-pick whatever changes needed
 * - Developer: `git tag latest`
 * - Developer: `git tag v0.XY.0`
 * - Developer: `git push --tags` to git@github.com:facebook/react-native.git
 * - CI: test and deploy to npm (run this script) with version 0.XY.0 with and not tag (latest is implied by npm)
 *
 * To patch old release:
 * - Developer: `git checkout 0.XY-stable`
 * - Developer: cherry-pick whatever changes needed
 * - Developer: `git tag v0.XY.Z`
 * - Developer: `git push` to git@github.com:facebook/react-native.git (or merge as pull request)
 * - CI: test and deploy to npm (run this script) with version 0.XY.Z with no tag, npm will not mark it as latest if
 * there is a version higher than XY
 *
 * Important tags:
 * If tag v0.XY.0-rcZ is present on the commit then publish to npm with version 0.XY.0-rcZ and tag next
 * If tag v0.XY.Z is present on the commit then publish to npm with version 0.XY.Z and no tag (npm will consider it latest)
 */

/*eslint-disable no-undef */
require(`shelljs/global`);

const buildBranch = process.env.CIRCLE_BRANCH;

let branchVersion;
if (buildBranch.indexOf(`-stable`) !== -1) {
  branchVersion = buildBranch.slice(0, buildBranch.indexOf(`-stable`));
} else {
  echo(`Error: We publish only from stable branches`);
  exit(0);
}

// 34c034298dc9cad5a4553964a5a324450fda0385
const currentCommit = exec(`git rev-parse HEAD`, {silent: true}).stdout.trim();
// [34c034298dc9cad5a4553964a5a324450fda0385, refs/heads/0.33-stable, refs/tags/latest, refs/tags/v0.33.1, refs/tags/v0.34.1-rc]
const tagsWithVersion = exec(`git ls-remote origin | grep ${currentCommit}`, {silent: true})
  .stdout.split(/\s/)
  // ['refs/tags/v0.33.0', 'refs/tags/v0.33.0-rc', 'refs/tags/v0.33.0-rc1', 'refs/tags/v0.33.0-rc2', 'refs/tags/v0.34.0']
  .filter(version => !!version && version.indexOf(`refs/tags/v${branchVersion}`) === 0)
  // ['refs/tags/v0.33.0', 'refs/tags/v0.33.0-rc', 'refs/tags/v0.33.0-rc1', 'refs/tags/v0.33.0-rc2']
  .filter(version => version.indexOf(branchVersion) !== -1)
  // ['v0.33.0', 'v0.33.0-rc', 'v0.33.0-rc1', 'v0.33.0-rc2']
  .map(version => version.slice(`refs/tags/`.length));

if (tagsWithVersion.length === 0) {
  echo(`Error: Can't find version tag in current commit. To deploy to NPM you must add tag v0.XY.Z[-rc] to your commit`);
  exit(1);
}
let releaseVersion;
if (tagsWithVersion[0].indexOf(`-rc`) === -1) {
  // if first tag on this commit is non -rc then we are making a stable release
  // '0.33.0'
  releaseVersion = tagsWithVersion[0].slice(1);
} else {
  // otherwise pick last -rc tag alphabetically
  // 0.33.0-rc2
  releaseVersion = tagsWithVersion[tagsWithVersion.length - 1].slice(1);
}

// -------- Generating Android Artifacts with JavaDoc
if (exec(`./gradlew :ReactAndroid:installArchives`).code) {
  echo(`Couldn't generate artifacts`);
  exit(1);
}

// undo uncommenting javadoc setting
exec(`git checkout ReactAndroid/gradle.properties`);

echo("Generated artifacts for Maven");

let artifacts = ['-javadoc.jar', '-sources.jar', '.aar', '.pom'].map((suffix) => {
  return `react-native-${releaseVersion}${suffix}`;
});

artifacts.forEach((name) => {
  if (!test(`-e`, `./android/com/facebook/react/react-native/${releaseVersion}/${name}`)) {
    echo(`file ${name} was not generated`);
    exit(1);
  }
});

if (releaseVersion.indexOf(`-rc`) === -1) {
  // release, package will be installed by default
  exec(`npm publish`);
} else {
  // RC release, package will be installed only if users specifically do it
  exec(`npm publish --tag next`);
}

echo(`Published to npm ${releaseVersion}`);

exit(0);
/*eslint-enable no-undef */

redpajama_set_name: RedPajamaGithub


text:
import React, { Component } from 'react'

import { Row, Col, Well, Button, Image } from 'react-bootstrap'

import './style.css'

class BookItem extends Component {
  constructor (props) {
    super(props)

    this.state = {
      isReadMoreEnabled: false
    }

    this.handleCart = this.handleCart.bind(this)
    this.onToggleReadMore = this.onToggleReadMore.bind(this)
  }

  onToggleReadMore = () => {
    this.setState({ isReadMoreEnabled: !this.state.isReadMoreEnabled })
  }

  // Can do without this function and call addToCart directly
  handleCart () {
    this.props.addToCart({ ...this.props.book, quantity: 1 })
  }

  render () {
    return (
      <Well>
        <Row key={this.props.book.id}>
          <Col xs={12} sm={4}>
            <Image responsive src={this.props.book.image} />
          </Col>
          <Col xs={6} sm={8}>

{this.props.title}

              {
                (this.props.book.description.length > 5 && !this.state.isReadMoreEnabled)
                  ? (`${this.props.book.description.substring(0, 5)}...`) : (this.props.book.description)
              }
              <button
                className="toggleButton"
                onClick={this.onToggleReadMore}
              >
                {(!this.state.isReadMoreEnabled && this.props.book.description.length > 5) ? ('More...') : ('Less...')}
              </button>

{this.props.book.price}

            <Button onClick={this.handleCart} bsStyle="primary">Buy now</Button>
          </Col>
        </Row>
      </Well>
    )
  }
}

export default BookItem


text:
"""
Random ID generation.

Mind that we cannot use ``uuid.uuid4`` because RFC 4122 does not define UUID4 to be securely
random. Python and Linux implementations (which Python falls back to) do the right thing but we
shouldn't rely on that.
"""
import os
import types
from binascii import hexlify

def get_random_id(length: int = 16, urandom: types.FunctionType = os.urandom) -> str:
    """
    Get ``length`` bytes of system random as hexadecimal string.

    :param length: number of bytes to get from `urandom`
    :param urandom: function that takes an integer and returns system random bytes of length equal
        to the integer passed to it
    """
    return hexlify(urandom(length)).decode()


text:
using System;
using System.Xml;

namespace Nohros.Configuration
{
  public partial class SimpleProviderNode
  {
    /// <summary>
    /// Parses the specified <see cref="XmlElement"/> element into a
    /// <see cref="CacheProviderNode"/> object.
    /// </summary>
    /// <param name="element">
    /// A Xml element that contains the repositories configuration data.
    /// </param>
    /// <param name="base_directory">
    /// The base directory to use when resolving the providers's location.
    /// </param>
    /// <returns>
    /// A <see cref="CacheProviderNode"/> containing the configured cache
    /// providers.
    /// </returns>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="element"/> is a <c>null</c> reference.
    /// </exception>
    /// <exception cref="ConfigurationException">
    /// The <paramref name="element"/> contains invalid configuration data.
    /// </exception>
    public static SimpleProviderNode Parse(XmlElement element,
      string base_directory) {
      CheckPreconditions(element, base_directory);
      string name = GetAttributeValue(element, Strings.kNameAttribute);
      string type = GetAttributeValue(element, Strings.kTypeAttribute);
      string group = GetAttributeValue(element, Strings.kNameAttribute,
        string.Empty);
      string alias = GetAttributeValue(element, Strings.kAliasAttribute,
        string.Empty);
      return new SimpleProviderNode(name, alias, type, group);
    }
  }
}


text:
---
layout: post
title: "Android FBE"
keywords: [""]
description: ""
categories: "Security"
tags: ["FBE","文件级加密"]
author: Chen An
permalink: /android-p-fbe.html
---

## Android FBE

### 1. FBE 简介

- 名称: FBE, File-Based Encryption,基于文件的加密
- 凭据加密 (CE) 存储空间:这是默认存储位置,只有在用户解锁设备后才可用。设备加密 (DE) 存储空间:在直接启动模式期间以及用户解锁设备后均可用。
- 开启 FBE 方式,在相关的 fstab 文件中添加相关的代码:

```
/dev/block/bootdevice/by-name/userdata                  /data              ext4    noatime,nosuid,nodev,barrier=1,noauto_da_alloc,discard wait,check,resize,**fileencryption=aes-256-xts**,quota

```

- 一些概念性内容这里不再赘述,如有需要自行阅读 [Goole FBE](https://source.android.com/security/encryption/file-based)

### 2. FBE 流程分析

#### 2.1 开机过程中,加密前的准备

- init.rc 中加入相关的代码,用于根据 fstab 文件中进行相关的挂载操作

```
on fs
    wait /dev/block/bootdevice
    write /proc/sys/vm/swappiness 100
    mount_all fstab.qcom
```

- 看完 init.rc 中,当然是查看 init 进程中如何解析 init.rc ,代码在 `system/core/init/builtins.cpp` 中:

```cpp
const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
...
{"mount_all",               {1,     kMax, do_mount_all}},
...
}
static int do_mount_all(const std::vector<std::string>& args) {
    ...
    /*mount_fstab 会 fork 出一个子进程调用 fs_mgr_read_fstab 以及 fs_mgr_mount_all 函数,前一个函数用于读取 fstab 文件,后者用于 mount,之后重点分析 fs_mgr_mount_all函数*/
    int ret =  mount_fstab(fstabfile, mount_mode);
    ...
    if (queue_event) {
        /* queue_fs_event will queue event based on mount_fstab return code
         * and return processed return code*/
        ret = queue_fs_event(ret);
    }
}

```

- 现在来看一下 fs_mgr_mount_all 函数,代码路径在`system/core/fs_mgr/fs_mgr.cpp`

```cpp
int fs_mgr_mount_all(struct fstab *fstab, int mount_mode){
	int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
    ...
    for (i = 0; i < fstab->num_entries; i++) {
		......
        int last_idx_inspected;
        int top_idx = i;

        mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx);
        i = last_idx_inspected;
        mount_errno = errno;

        /* Deal with encryptability. */
        if (!mret) {
            int status = handle_encryptable(&fstab->recs[attempted_idx]);

            if (status == FS_MGR_MNTALL_FAIL) {
                /* Fatal error - no point continuing */
                return status;
            }

            if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
                if (encryptable != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
                    // Log and continue
                    LERROR << "Only one encryptable/encrypted partition supported";
                }
                //结果赋值给 encryptable
                encryptable = status;
            }

            /* Success!  Go get the next one */
            continue;
        }
       }
        ......
    /*此处返回给父进程,即 queue_fs_event 接收返回值进行之后的处理*/
    if (error_count) {
        return FS_MGR_MNTALL_FAIL;
    } else {
        return encryptable;
    }
- [ ] }

```

- 先来看一下 queue_fs_event 函数,它会根据 mount_fstab 的返回值结果进行不同的操作,而 mount_fstab 会返回 FS_MGR_MNTALL_DEV_FILE_ENCRYPTED 给 queue_fs_event,然后调用 e4crypt_install_keyring 函数用于安装 e4crypt keyring,这个用于存放文件加密的 key,之后设置相关的属性,然后触发 nonencrypted 这个 trigger 。

```cpp
static int queue_fs_event(int code) {
    int ret = code;
    if (code == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
        ActionManager::GetInstance().QueueEventTrigger("encrypt");
    } else if (code == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
        property_set("ro.crypto.state", "encrypted");
        property_set("ro.crypto.type", "block");
        ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
    } else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
        property_set("ro.crypto.state", "unencrypted");
        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
    } else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
        property_set("ro.crypto.state", "unsupported");
        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
    } else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
        /* Setup a wipe via recovery, and reboot into recovery */
        PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
        const std::vector<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" };
        reboot_into_recovery(options);
        return 0;
        /* If reboot worked, there is no return. */
    } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
        if (e4crypt_install_keyring()) {
            return -1;
        }
        property_set("ro.crypto.state", "encrypted");
        property_set("ro.crypto.type", "file");

        // Although encrypted, we have device key, so we do not need to
        // do anything different from the nonencrypted case.
        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
    } else if (code == FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED) {
        if (e4crypt_install_keyring()) {
            return -1;
        }
        property_set("ro.crypto.state", "encrypted");
        property_set("ro.crypto.type", "file");

        // defaultcrypto detects file/block encryption. init flow is same for each.
        ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
    } else if (code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
        if (e4crypt_install_keyring()) {
            return -1;
        }
        property_set("ro.crypto.type", "file");

        // encrypt detects file/block encryption. init flow is same for each.
        ActionManager::GetInstance().QueueEventTrigger("encrypt");
    } else if (code > 0) {
        PLOG(ERROR) << "fs_mgr_mount_all returned unexpected error " << code;
    }
    /* else ... < 0: error */

    return ret;
}

```

- 之前如果有了解过全盘加密的同学应该会很熟悉,全盘加密会返回 FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION ,然后触发一个 trigger ,最后在 init.rc 中执行 vdc 进程,最后启动 vold 进行全盘加密操作.那现在我们来看一下 FBE 中的 nonencrypted 这个 trigger 中做了什么操作,没看到有触发 vold 的操作啊,那文件加密是什么时候做的呢?不着急,我们继续往下看.

```
on nonencrypted
    class_start main
    class_start late_start
```

- 我们知道,正常系统起来后,init 的执行顺序为 `early-init`,`init`,`late-init`.既然我们一下子无法知道 FBE 中 vold 是在什么时候执行的,那就只能一步步跟 init.rc,看下能否发现一些端倪,功夫不负有心人,终于在 init.rc 中发现了一点可能和 FBE 相关的东西. **installkey /data** 这个看着有点像.

```
on post-fs-data
    # We chown/chmod /data again so because mount is run as root + defaults
    chown system system /data
    chmod 0771 /data
    # We restorecon /data in case the userdata partition has been reset.
    restorecon /data

    # Make sure we have the device encryption key.
    start vold
    installkey /data

```

- 类似 mount 的处理流程, installkey /data 最后会调用`system/core/init/builtins.cpp` 中的 do_installkey 函数,do_installkey 首先判断是否为文件加密方式,如果是文件加密方式,则会执行 vdc 命令,到这里终于开始进入加密流程过程了.

```cpp
static int do_installkey(const std::vector<std::string>& args) {
    if (!is_file_crypto()) {
        return 0;
    }
    auto unencrypted_dir = args[1] + e4crypt_unencrypted_folder;
    if (do_installkeys_ensure_dir_exists(unencrypted_dir.c_str())) {
        PLOG(ERROR) << "Failed to create " << unencrypted_dir;
        return -1;
    }
    std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
                                          "enablefilecrypto"};
    return do_exec(exec_args);
}
```

#### 2.2 FBE 加密处理流程

- 先看一下 vdc 代码中的处理流程,在 `system/vold/vdc.cpp`, 通过 local socket 实现了 vdc 通知 vold 进行之后的操作

```cpp
    ........
    while ((sock = socket_local_client(sockname,
                                 ANDROID_SOCKET_NAMESPACE_RESERVED,
                                 SOCK_STREAM)) < 0) {
        if (!wait_for_socket) {
            PLOG(ERROR) << "Error connecting to " << sockname;
            exit(4);
        } else {
            usleep(10000);
        }
    }

    if (!strcmp(argv[1], "monitor")) {
        exit(do_monitor(sock, 0));
    } else {
        exit(do_cmd(sock, argc, argv));
    }
    ........
        if (TEMP_FAILURE_RETRY(write(sock, cmd.c_str(), cmd.length() + 1)) < 0) {
        PLOG(ERROR) << "Failed to write command";
        return errno;
    }

```

- 代码在 system/vold/CryptCommandListener.cpp,通过之前的命令执行到 e4crypt_initialize_global_de 函数,到这里终于进入了文件加密的核心部分了,该函数会生成 /data/unencrypted/key.unencrypted key用来设置/data下除了`directories_to_exclude` (system/extras/ext4_utils/ext4_crypt_init_extensions.cpp 中定义)目录的当前所有目录的policy,(更准确的说,用的是 /data/unencrypted/ref ,该文件是是key 的引用(),key 其实是存入到密钥环(keyring)当中去的 ).其实 FBE 下有三种类型的 key 用于整个 Android 系统,那这里只是生成的一把 key,之后的 key 是在哪里生成的呢?

```cpp
bool e4crypt_initialize_global_de() {
    LOG(INFO) << "e4crypt_initialize_global_de";

    if (s_global_de_initialized) {
        LOG(INFO) << "Already initialized";
        return true;
    }

    const char *contents_mode;
    const char *filenames_mode;
    cryptfs_get_file_encryption_modes(&contents_mode, &filenames_mode);
    std::string modestring = std::string(contents_mode) + ":" + filenames_mode;

    std::string mode_filename = std::string("/data") + e4crypt_key_mode;
    if (!android::base::WriteStringToFile(modestring, mode_filename)) {
        PLOG(ERROR) << "Cannot save type";
        return false;
    }

    std::string device_key_ref;
    //生成 /data/unencrypted/key这个文件夹  key 是怎样生成的 ,首先会读取 /dev/urandom 节点生成一个随机数,再通过 keymaster key 进行签名操作

    //同时会生成 /data/uncrypt/key/version(版本信息)  /data/uncrypt/key/encrypt_key(之前通过/dev/urandom 生成的 key 再通过 keymaster key 加密过的 key)
    if (!android::vold::retrieveAndInstallKey(true,
        device_key_path, device_key_temp, &device_key_ref)) return false;

    std::string ref_filename = std::string("/data") + e4crypt_key_ref;
    if (!android::base::WriteStringToFile(device_key_ref, ref_filename)) {
        PLOG(ERROR) << "Cannot save key reference to:" << ref_filename;
        return false;
    }
    LOG(INFO) << "Wrote system DE key reference to:" << ref_filename;

    s_global_de_initialized = true;
    return true;
}
```

- 生成了 uncryptkey 之后, 分析 init.rc 看看之后做了什么操作,看了大部分都是 mkdir 操作啊.

```
    # Start bootcharting as soon as possible after the data partition is
    # mounted to collect more data.
    mkdir /data/bootchart 0755 shell shell
    bootchart start

    # Avoid predictable entropy pool. Carry over entropy from previous boot.
    copy /data/system/entropy.dat /dev/urandom

    # create basic filesystem structure
    mkdir /data/misc 01771 system misc
    mkdir /data/misc/recovery 0770 system log

```

- 也类似 mount_all ,mkdir 最终调用了 init/builtins.cpp 中的 do_mkdir 函数,关注 e4crypt_set_directory_policy 函数实现

```cpp
static int do_mkdir(const std::vector<std::string>& args) {
	......
    //判断是否未文件加密方式,是则执行之后的流程
    if (e4crypt_is_native()) {
        if (e4crypt_set_directory_policy(args[1].c_str())) {
            const std::vector<std::string> options = {
                "--prompt_and_wipe_data",
                "--reason=set_policy_failed:"s + args[1]};
            reboot_into_recovery(options);
            return 0;
        }
    }
    return 0;
}
```

- 设置相关目录的加密 policy,使用的 policy 便是上面生成的 /data/unencrypted/ref (ref 是 key 经过填充后 再经过 sha512 算法得到的东西). directories_to_exclude 指定的相关目录不会被加密,因为该部分相关的子目录需要加密 (加密 key 使用之后生成的 CE/DE)

```cpp
int e4crypt_set_directory_policy(const char* dir)
{
    if (!dir || strncmp(dir, "/data/", 6)) {
        return 0;
    }

    // Special-case /data/media/obb per b/64566063
    if (strcmp(dir, "/data/media/obb") == 0) {
        // Try to set policy on this directory, but if it is non-empty this may fail.
        set_system_de_policy_on(dir);
        return 0;
    }

    // Only set policy on first level /data directories
    // To make this less restrictive, consider using a policy file.
    // However this is overkill for as long as the policy is simply
    // to apply a global policy to all /data folders created via makedir
    if (strchr(dir + 6, '/')) {
        return 0;
    }

    // Special case various directories that must not be encrypted,
    // often because their subdirectories must be encrypted.
    // This isn't a nice way to do this, see b/26641735
    std::vector<std::string> directories_to_exclude = {
        "lost+found",
        "system_ce", "system_de",
        "misc_ce", "misc_de",
        "media",
        "data", "user", "user_de",
    };
    std::string prefix = "/data/";
    for (auto d: directories_to_exclude) {
        if ((prefix + d) == dir) {
            LOG(INFO) << "Not setting policy on " << dir;
            return 0;
        }
    }
    return set_system_de_policy_on(dir);
}
```
- e4crypt_policy_set 先填充了 eep 这个结构体,相关的加密 key 与加密方式都是通过这个结构体进行进一步操作的.最后通过 ioctl 实现相关目录的 key policy ,kernel 部分这里就不去深究了,相关代码位置在 kernel/fs/crypto/ 中

```cpp
static bool e4crypt_policy_set(const char *directory, const char *policy,
                               size_t policy_length,
                               int contents_encryption_mode,
                               int filenames_encryption_mode) {
    if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
        LOG(ERROR) << "Policy wrong length: " << policy_length;
        return false;
    }
    int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
    if (fd == -1) {
        PLOG(ERROR) << "Failed to open directory " << directory;
        return false;
    }
	//填充 eep
    ext4_encryption_policy eep;
    eep.version = 0;
    eep.contents_encryption_mode = contents_encryption_mode;
    eep.filenames_encryption_mode = filenames_encryption_mode;
    eep.flags = e4crypt_get_policy_flags(filenames_encryption_mode);
    memcpy(eep.master_key_descriptor, policy, EXT4_KEY_DESCRIPTOR_SIZE);
    //ioctl 实现最后的加密操作
    if (ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &eep)) {
        PLOG(ERROR) << "Failed to set encryption policy for " << directory;
        close(fd);
        return false;
    }
    close(fd);

    char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
    policy_to_hex(policy, policy_hex);
    LOG(INFO) << "Policy for " << directory << " set to " << policy_hex;
    return true;
}

```

- 上面已经分析了 uncryptkey 加密操作. 那么文章开头说的 CE/DE 又是在哪做的操作呢? 继续分析 init.rc,发现在 init.rc 中,在 post-fs-data 中创建了一些必要的文件后,是时候为用户0创建相应的key 了 , `init_user0` 就是做了这个操作,类似之前的 do_installkey 操作, init_user0 最终会调用了 vold 下的 e4crypt_init_user0 函数,该函数会生成 /data/misc/vold/user_keys 目录下的相关文件.注:DE key 加密相关的存储空间就是在这个阶段实现的 CE 加密相关的存储空间还未生成

```cpp
bool e4crypt_init_user0() {
    LOG(DEBUG) << "e4crypt_init_user0";
    if (e4crypt_is_native()) {
        if (!prepare_dir(user_key_dir, 0700, AID_ROOT, AID_ROOT)) return false;
        if (!prepare_dir(user_key_dir + "/ce", 0700, AID_ROOT, AID_ROOT)) return false;
        if (!prepare_dir(user_key_dir + "/de", 0700, AID_ROOT, AID_ROOT)) return false;
        if (!android::vold::pathExists(get_de_key_path(0))) {
        //第一次系统起来, de/ce key 未创建,所以会走这,创建 DE/CE key 的过程都是在这个函数里面做的,类似 uncrypted key 的生成流程,
        // 也会通过调用 randomKey 函数生成随机 key ,storeKeyAtomically 函数生成 keymaster key ,
        //最后调用 installKey 将 key 加入到 密钥环(keyring)中
            if (!create_and_install_user_keys(0, false)) return false;
        }
        // TODO: switch to loading only DE_0 here once framework makes
        // explicit calls to install DE keys for secondary users
        // 加密之后,第一次系统起来直接走这,load key 然后用 keymaster key进行校验
        if (!load_all_de_keys()) return false;
    }
    // We can only safely prepare DE storage here, since CE keys are probably
    // entangled with user credentials.  The framework will always prepare CE
    // storage once CE keys are installed.
    //开始准备 DE 存储空间,e4crypt_prepare_user_storage 先是准备了相关的 DE 目录,之后查找相关用户id 的 key ,最后调用 ensure_policy 用户设置相关目录的加密策略
    if (!e4crypt_prepare_user_storage(nullptr, 0, 0, FLAG_STORAGE_DE)) {
        LOG(ERROR) << "Failed to prepare user 0 storage";
        return false;
    }

    // If this is a non-FBE device that recently left an emulated mode,
    // restore user data directories to known-good state.
    if (!e4crypt_is_native() && !e4crypt_is_emulated()) {
        e4crypt_unlock_user_key(0, 0, "!", "!");
    }

    return true;
}

```

- 接着上面的 ensure_policy 函数,通过 cryptfs_get_file_encryption_modes 函数,根据 fstab 文件获取了 FBE 加密方式(contents_mode,filenames_mode),最后通过 e4crypt_policy_ensure 函数设置相关目录的 policy

```cpp
int e4crypt_policy_ensure(const char *directory, const char *policy,
                          size_t policy_length,
                          const char *contents_encryption_mode,
                          const char *filenames_encryption_mode) {
    int contents_mode = 0;
    int filenames_mode = 0;

    if (!strcmp(contents_encryption_mode, "software") ||
        !strcmp(contents_encryption_mode, "aes-256-xts")) {
        contents_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
    } else if (!strcmp(contents_encryption_mode, "ice")) {
        contents_mode = EXT4_ENCRYPTION_MODE_PRIVATE;
    } else {
        LOG(ERROR) << "Invalid file contents encryption mode: "
                   << contents_encryption_mode;
        return -1;
    }

    if (!strcmp(filenames_encryption_mode, "aes-256-cts")) {
        filenames_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS;
    } else if (!strcmp(filenames_encryption_mode, "aes-256-heh")) {
        filenames_mode = EXT4_ENCRYPTION_MODE_AES_256_HEH;
    } else {
        LOG(ERROR) << "Invalid file names encryption mode: "
                   << filenames_encryption_mode;
        return -1;
    }

    bool is_empty;
    if (!is_dir_empty(directory, &is_empty)) return -1;
    if (is_empty) {
        if (!e4crypt_policy_set(directory, policy, policy_length,
                                contents_mode, filenames_mode)) return -1;
    } else {
        if (!e4crypt_policy_check(directory, policy, policy_length,
                                  contents_mode, filenames_mode)) return -1;
    }
    return 0;
}
```

- 那么 CE 空间是在什么时候准备好的?其实那部分代码是在 framework 里面做的。framework 相关代码在 `frameworks/base/services/core/java/com/android/server/StorageManagerService.java`,调用了 unlockUserKey 函数,该部分代码还是很简单的,主要就是通过 `mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,encodeBytes(token), encodeBytes(secret));`通知 vold 需要去生成 key 了。

```java
    @Override
    public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
        enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
        waitForReady();

        if (StorageManager.isFileEncryptedNativeOrEmulated()) {
            // When a user has secure lock screen, require secret to actually unlock.
            // This check is mostly in place for emulation mode.
            if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(secret)) {
                throw new IllegalStateException("Secret required to unlock secure user " + userId);
            }

            try {
                mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,
                        encodeBytes(token), encodeBytes(secret));
            } catch (NativeDaemonConnectorException e) {
                throw e.rethrowAsParcelableException();
            }
        }

        synchronized (mLock) {
            mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
        }
        if (userId == UserHandle.USER_SYSTEM) {
            String propertyName = "sys.user." + userId + ".ce_available";
            Slog.d(TAG, "Setting property: " + propertyName + "=true");
            SystemProperties.set(propertyName, "true");
        }
    }
```

- 调用 system/vold/Ext4Crypt.cpp 中的 `e4crypt_unlock_user_key` 函数进行解密操作,第一次系统起来的时候,因为用户没有设置密码,所以此时的 key 是没有用 auth 进行签名的,s_ce_key_raw_refs 会直接返回,即此时的 key 是已经解密过的 key 。

```cpp
// TODO: rename to 'install' for consistency, and take flags to know which keys to install
bool e4crypt_unlock_user_key(userid_t user_id, int serial, const char* token_hex,
                             const char* secret_hex) {
    LOG(DEBUG) << "e4crypt_unlock_user_key " << user_id << " serial=" << serial
               << " token_present=" << (strcmp(token_hex, "!") != 0);
    if (e4crypt_is_native()) {
        if (s_ce_key_raw_refs.count(user_id) != 0) {
            LOG(WARNING) << "Tried to unlock already-unlocked key for user " << user_id;
            return true;
        }
        std::string token, secret;
        if (!parse_hex(token_hex, &token)) return false;
        if (!parse_hex(secret_hex, &secret)) return false;
        android::vold::KeyAuthentication auth(token, secret);
        if (!read_and_install_user_ce_key(user_id, auth)) {
            LOG(ERROR) << "Couldn't read key for " << user_id;
            return false;
        }
    } else {
        // When in emulation mode, we just use chmod. However, we also
        // unlock directories when not in emulation mode, to bring devices
        // back into a known-good state.
        if (!emulated_unlock(android::vold::BuildDataSystemCePath(user_id), 0771) ||
            !emulated_unlock(android::vold::BuildDataMiscCePath(user_id), 01771) ||
            !emulated_unlock(android::vold::BuildDataMediaCePath(nullptr, user_id), 0770) ||
            !emulated_unlock(android::vold::BuildDataUserCePath(nullptr, user_id), 0771)) {
            LOG(ERROR) << "Failed to unlock user " << user_id;
            return false;
        }
    }
    return true;
}
```

- 之后调用 prepareUserStorage 用于设置 ce 空间相关的 policy

```java
    @Override
    public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
        enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
        waitForReady();

        try {
            mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
                    userId, serialNumber, flags);
        } catch (NativeDaemonConnectorException e) {
            throw e.rethrowAsParcelableException();
        }
    }
```

- 类似 DE 空间的加密流程 CE 空间也会调用 e4crypt_prepare_user_storage 进行设置目录的 policy ,这样子,加密空间就全部准备好了。

```cpp
bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int serial,
        int flags) {
    LOG(DEBUG) << "e4crypt_prepare_user_storage for volume " << escape_null(volume_uuid)
               << ", user " << user_id << ", serial " << serial << ", flags " << flags;

    if (flags & FLAG_STORAGE_DE) {
        // DE_sys key
        auto system_legacy_path = android::vold::BuildDataSystemLegacyPath(user_id);
        auto misc_legacy_path = android::vold::BuildDataMiscLegacyPath(user_id);
        auto profiles_de_path = android::vold::BuildDataProfilesDePath(user_id);

        // DE_n key
        auto system_de_path = android::vold::BuildDataSystemDePath(user_id);
        auto misc_de_path = android::vold::BuildDataMiscDePath(user_id);
        auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id);

        if (!prepare_dir(system_legacy_path, 0700, AID_SYSTEM, AID_SYSTEM)) return false;
#if MANAGE_MISC_DIRS
        if (!prepare_dir(misc_legacy_path, 0750, multiuser_get_uid(user_id, AID_SYSTEM),
                multiuser_get_uid(user_id, AID_EVERYBODY))) return false;
#endif
        if (!prepare_dir(profiles_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;

        if (!prepare_dir(system_de_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false;
        if (!prepare_dir(misc_de_path, 01771, AID_SYSTEM, AID_MISC)) return false;
        if (!prepare_dir(user_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;

        if (e4crypt_is_native()) {
            std::string de_raw_ref;
            if (!lookup_key_ref(s_de_key_raw_refs, user_id, &de_raw_ref)) return false;
            if (!ensure_policy(de_raw_ref, system_de_path)) return false;
            if (!ensure_policy(de_raw_ref, misc_de_path)) return false;
            if (!ensure_policy(de_raw_ref, user_de_path)) return false;
        }
    }

    if (flags & FLAG_STORAGE_CE) {
        // CE_n key
        auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
        auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
        auto media_ce_path = android::vold::BuildDataMediaCePath(volume_uuid, user_id);
        auto user_ce_path = android::vold::BuildDataUserCePath(volume_uuid, user_id);

        if (!prepare_dir(system_ce_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false;
        if (!prepare_dir(misc_ce_path, 01771, AID_SYSTEM, AID_MISC)) return false;
        if (!prepare_dir(media_ce_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return false;
        if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;

        if (e4crypt_is_native()) {
            std::string ce_raw_ref;
            if (!lookup_key_ref(s_ce_key_raw_refs, user_id, &ce_raw_ref)) return false;
            if (!ensure_policy(ce_raw_ref, system_ce_path)) return false;
            if (!ensure_policy(ce_raw_ref, misc_ce_path)) return false;
            if (!ensure_policy(ce_raw_ref, media_ce_path)) return false;
            if (!ensure_policy(ce_raw_ref, user_ce_path)) return false;

            // Now that credentials have been installed, we can run restorecon
            // over these paths
            // NOTE: these paths need to be kept in sync with libselinux
            android::vold::RestoreconRecursive(system_ce_path);
            android::vold::RestoreconRecursive(misc_ce_path);
        }
    }

    return true;
}

```

#### 2.3 锁屏密码与 FBE key 的关系
开始前,先说说加密思想。Android FBE 中会通过密码文件生成一个 auth ,用这个 auth 再对 key 进行签名。这样子,用户在没有输入正确密码时,是无法进行解密 CE 空间的。那按照这样子,用户在不输入密码的时候岂不是用不了这些内存位置。其实,根据 auth 对 key 的签名,只针对了 CE 空间的 key 进行签名,所以系统在正常起来时,DE 空间其实已经解密完成了,现在就来看下用户在设置密码后,vold 做了哪些处理吧。

- 用户设置完成密码后,vold 进程首先会调用 e4crypt_add_user_key_auth 用于生成新的 CE key,一个疑惑,在设置密码完成后,会调用两次该函数,第一次会生成一个未经过 auth 签名的 key,之后会再次生成一个经过 auth 签名的 key,不知这样的意图为何?

- e4crypt_fixate_newest_user_key_auth 主要是将用户设置密码后生成的 auth 签名过 key 给重命名成之前的 key 名称

- secdiscard 主要用于删除旧的 key 文件

#### 2.4 FBE 解密
这里说的解密的意思理解成读取可能会比较好理解. Android 的加密思想是如果是未经过授权的读取操作都是无法进行访问的.其实 FBE 解密流程和系统第一次起来时 set policy 的流程几乎是一样的。不同的是,在调用 ensure_policy 时,会对目录检测是否为空,如果是空,则进行 set policy 操作,而如果为非空,则进行 check_policy 操作,所以对 /data 的解密操作都在这个 check_policy ,当校验成功后,kernel 会自动对 /data 进行解密操作。如果要实现对 /data 的解密,最难的倒不是 vold 中解密流程的移植,反倒是 framework 中根据 password 生成的 auth 的提取,因为此时的 key 是使用了 auth 进行签名的 key 了,如何把加密的 key 给解出来倒成了开发的难点。

### 3. 总结
分析到最后,其实 FBE 的加密思想并不复杂,相对于 Android 之前的全盘加密,整个流程加密思想几乎是相同的。但无疑文件加密是更为人性化的,用户无需在输入密码就可进行一些基础操作。文中可能还有些不足以及 kernel 部分详细的加密操作都未详谈,欢迎各位指正补充。


text:
**[do-wrapper](../README.md)**

> [Globals](../globals.md) / "modules/droplets"

# Module: "modules/droplets"

## Index

### Classes

* [Droplets](../classes/_modules_droplets_.droplets.md)


text:
<?php

/**
 * Class MySQLCore
 */
class MySQLCore extends Db
{
    /** @var resource */
    protected $link;

    /* @var resource */
    protected $result;

    /**
     * Tries to connect to the database
     *
     * @see DbCore::connect()
     * @return resource
     * @throws PrestaShopDatabaseException
     */
    public function connect()
    {
        if (!defined('_PS_MYSQL_REAL_ESCAPE_STRING_')) {
            define('_PS_MYSQL_REAL_ESCAPE_STRING_', function_exists('mysql_real_escape_string'));
        }

        if (!$this->link = mysql_connect($this->server, $this->user, $this->password)) {
            throw new PrestaShopDatabaseException(Tools::displayError('Link to database cannot be established.'));
        }

        if (!$this->set_db($this->database)) {
            throw new PrestaShopDatabaseException(Tools::displayError('The database selection cannot be made.'));
        }

        // UTF-8 support
        if (!mysql_query('SET NAMES \'utf8\'', $this->link)) {
            throw new PrestaShopDatabaseException(Tools::displayError('PrestaShop Fatal error: no utf-8 support. Please check your server configuration.'));
        }

        return $this->link;
    }

    /**
     * Tries to connect and create a new database
     *
     * @param string $host
     * @param string $user
     * @param string $password
     * @param string $dbname
     * @param bool $dropit If true, drops the created database.
     * @return bool|resource
     */
    public static function createDatabase($host, $user, $password, $dbname, $dropit = false)
    {
        $link = mysql_connect($host, $user, $password);
        $success = mysql_query('CREATE DATABASE `'.str_replace('`', '\\`', $dbname).'`', $link);
        if ($dropit && (mysql_query('DROP DATABASE `'.str_replace('`', '\\`', $dbname).'`', $link) !== false)) {
            return true;
        }

        return $success;
    }

    /**
     * Destroys the database connection link
     *
     * @see DbCore::disconnect()
     */
    public function disconnect()
    {
        mysql_close($this->link);
    }

    /**
     * Executes an SQL statement, returning a result set as a result resource object.
     *
     * @see DbCore::_query()
     * @param string $sql
     * @return resource
     */
    protected function _query($sql)
    {
        return mysql_query($sql, $this->link);
    }

    /**
     * Returns the next row from the result set.
     *
     * @see DbCore::nextRow()
     * @param bool|resource $result
     * @return array|bool
     */
    public function nextRow($result = false)
    {
        $return = false;
        if (is_resource($result) && $result) {
            $return = mysql_fetch_assoc($result);
        } elseif (is_resource($this->_result) && $this->_result) {
            $return = mysql_fetch_assoc($this->_result);
        }

        return $return;
    }

    /**
     * Returns the next row from the result set.
     *
     * @see DbCore::_numRows()
     * @param resource $result
     * @return int
     */
    protected function _numRows($result)
    {
        return mysql_num_rows($result);
    }

    /**
     * Returns ID of the last inserted row.
     *
     * @see DbCore::Insert_ID()
     * @return int
     */
    public function Insert_ID()
    {
        return mysql_insert_id($this->link);
    }

    /**
     * Return the number of rows affected by the last SQL query.
     *
     * @see DbCore::Affected_Rows()
     * @return int
     */
    public function Affected_Rows()
    {
        return mysql_affected_rows($this->link);
    }

    /**
     * Returns error message.
     *
     * @see DbCore::getMsgError()
     * @param bool $query
     * @return string
     */
    public function getMsgError($query = false)
    {
        return mysql_error($this->link);
    }

    /**
     * Returns error code.
     *
     * @see DbCore::getNumberError()
     * @return int
     */
    public function getNumberError()
    {
        return mysql_errno($this->link);
    }

    /**
     * Returns database server version.
     *
     * @see DbCore::getVersion()
     * @return string
     */
    public function getVersion()
    {
        return mysql_get_server_info($this->link);
    }

    /**
     * Escapes illegal characters in a string.
     *
     * @see DbCore::_escape()
     * @param string $str
     * @return string
     */
    public function _escape($str)
    {
        return _PS_MYSQL_REAL_ESCAPE_STRING_ ? mysql_real_escape_string($str, $this->link) : addslashes($str);
    }

    /**
     * Switches to a different database.
     *
     * @see DbCore::set_db()
     * @param string $db_name
     * @return bool
     */
    public function set_db($db_name)
    {
        return mysql_select_db($db_name, $this->link);
    }

    /**
     * Returns all rows from the result set.
     *
     * @see DbCore::getAll()
     * @param bool|resource $result
     * @return array
     */
    protected function getAll($result = false)
    {
        if (!$result) {
            $result = $this->result;
        }

        $data = array();
        while ($row = $this->nextRow($result)) {
            $data[] = $row;
        }

        return $data;
    }

    /**
     * Try a connection to the database and check if at least one table with same prefix exists
     *
     * @see Db::hasTableWithSamePrefix()
     * @param string $server Server address
     * @param string $user Login for database connection
     * @param string $pwd Password for database connection
     * @param string $db Database name
     * @param string $prefix Tables prefix
     * @return bool
     */
    public static function hasTableWithSamePrefix($server, $user, $pwd, $db, $prefix)
    {
        if (!$link = @mysql_connect($server, $user, $pwd, true)) {
            return false;
        }
        if (!@mysql_select_db($db, $link)) {
            return false;
        }

        $sql = 'SHOW TABLES LIKE \''.$prefix.'%\'';
        $result = mysql_query($sql);
        return (bool)@mysql_fetch_assoc($result);
    }

    /**
     * Try a connection to the database
     *
     * @see Db::checkConnection()
     * @param string $server Server address
     * @param string $user Login for database connection
     * @param string $pwd Password for database connection
     * @param string $db Database name
     * @param bool $newDbLink
     * @param string|null $engine
     * @param int $timeout
     * @return int Error code or 0 if connection was successful
     */
    public static function tryToConnect($server, $user, $pwd, $db, $new_db_link = true, $engine = null, $timeout = 5)
    {
        ini_set('mysql.connect_timeout', $timeout);
        if (!$link = @mysql_connect($server, $user, $pwd, $new_db_link)) {
            return 1;
        }
        if (!@mysql_select_db($db, $link)) {
            return 2;
        }
        @mysql_close($link);

        return 0;
    }

    /**
     * Selects best table engine.
     *
     * @return string
     */
    public function getBestEngine()
    {
        $value = 'InnoDB';

        $sql = 'SHOW VARIABLES WHERE Variable_name = \'have_innodb\'';
        $result = mysql_query($sql);
        if (!$result) {
            $value = 'MyISAM';
        }
        $row = mysql_fetch_assoc($result);
        if (!$row || strtolower($row['Value']) != 'yes') {
            $value = 'MyISAM';
        }

        /* MySQL >= 5.6 */
        $sql = 'SHOW ENGINES';
        $result = mysql_query($sql);
        while ($row = mysql_fetch_assoc($result)) {
            if ($row['Engine'] == 'InnoDB') {
                if (in_array($row['Support'], array('DEFAULT', 'YES'))) {
                    $value = 'InnoDB';
                }
                break;
            }
        }

        return $value;
    }

    /**
     * Tries to connect to the database and create a table (checking creation privileges)
     *
     * @param string $server
     * @param string $user
     * @param string $pwd
     * @param string $db
     * @param string $prefix
     * @param string|null $engine Table engine
     * @return bool|string True, false or error
     */
    public static function checkCreatePrivilege($server, $user, $pwd, $db, $prefix, $engine = null)
    {
        ini_set('mysql.connect_timeout', 5);
        if (!$link = @mysql_connect($server, $user, $pwd, true)) {
            return false;
        }
        if (!@mysql_select_db($db, $link)) {
            return false;
        }

        if ($engine === null) {
            $engine = 'MyISAM';
        }

        $result = mysql_query('
		CREATE TABLE `'.$prefix.'test` (
			`test` tinyint(1) unsigned NOT NULL
		) ENGINE='.$engine, $link);

        if (!$result) {
            return mysql_error($link);
        }

        mysql_query('DROP TABLE `'.$prefix.'test`', $link);
        return true;
    }

    /**
     * Try a connection to the database and set names to UTF-8
     *
     * @see Db::checkEncoding()
     * @param string $server Server address
     * @param string $user Login for database connection
     * @param string $pwd Password for database connection
     * @return bool
     */
    public static function tryUTF8($server, $user, $pwd)
    {
        $link = @mysql_connect($server, $user, $pwd);
        $ret = mysql_query('SET NAMES \'utf8\'', $link);
        @mysql_close($link);
        return $ret;
    }

    /**
     * Checks if auto increment value and offset is 1
     *
     * @param string $server
     * @param string $user
     * @param string $pwd
     * @return bool
     */
    public static function checkAutoIncrement($server, $user, $pwd)
    {
        $link = @mysql_connect($server, $user, $pwd);
        $ret = (bool)(($result = mysql_query('SELECT @@auto_increment_increment as aii', $link)) && ($row = mysql_fetch_assoc($result)) && $row['aii'] == 1);
        $ret &= (bool)(($result = mysql_query('SELECT @@auto_increment_offset as aio', $link)) && ($row = mysql_fetch_assoc($result)) && $row['aio'] == 1);
        @mysql_close($link);
        return $ret;
    }
}


text:
namespace remoting {

URLRequestContextGetter::URLRequestContextGetter(
    scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
    scoped_refptr<base::SingleThreadTaskRunner> file_task_runner)
    : network_task_runner_(network_task_runner),
      file_task_runner_(file_task_runner),
      proxy_config_service_(
          net::ProxyService::CreateSystemProxyConfigService(
              network_task_runner, file_task_runner)) {}

net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
  if (!url_request_context_.get()) {
    net::URLRequestContextBuilder builder;
    builder.SetFileTaskRunner(file_task_runner_);
    net_log_.reset(new VlogNetLog());
    builder.set_net_log(net_log_.get());
    builder.DisableHttpCache();
    builder.set_proxy_config_service(proxy_config_service_.Pass());
    url_request_context_ = builder.Build().Pass();
  }
  return url_request_context_.get();
}

scoped_refptr<base::SingleThreadTaskRunner>
URLRequestContextGetter::GetNetworkTaskRunner() const {
  return network_task_runner_;
}

URLRequestContextGetter::~URLRequestContextGetter() {
}

}  // namespace remoting


text:
pansi is an abstraction that combines several Ansible patterns (and perhaps an anti-pattern
or two) to reduce "cloud playbook sprawl" and make it easier to codify into version control
how services deployed to cloud providers are structured **without** using static host
inventory or preventing the use of dynamic inventory scripts. Other goals are to make it
easier to move hosts that are part of a service from one cloud provider to another, and to
target hosts from multiple providers in a single run.

### Definitions

**NOTE**: The purpose of the odd spellings is to help maintain manageability. For example,
the term 'servis' is merely a misspelling of 'service'. The misspelled option is more
easily located and distinguished in codebases, which often use these common terms in
many different contexts. Should a term ever need to be renamed or modified procedurally,
the find/replace or other operation will be much easier on the human running it and there
may be 100 instances of the misspelled term to sort through instead of (in some cases)
thousands of unrelated instances in the case of using a generic term spelled correctly
in a project that contains many other libraries/dependencies.

**host**: An Ansible host.

**servis**: A 'service', or 'deployment', the thing being deployed. A servis is a host (or
hosts working together) to do an assigned job such as run builds, host a package cache,
store backups, host a database or web frontend, or etc.

**servisName**, and **servisType**: Each servis has a "servisName" and is an instance of its
 "servisType", just as a traditional named programming object is an instance of its
 declaration. Servis names and types are semi-arbitrary so long as they are consistent in
 the couple of places they are defined in pansi. A servis named 'debby' might be of the
 servisType 'apt-cache', while a servis named 'who' might be of the servisType 'bind9-deploy'.
 The fictitious included example servis 'testar' is an instance of the fictitious servisType
 'skylab' which consists of some hosts that run just an aptly apt-cache and other hosts that
 run both Jenkins and LDAP.

**servisParams**: A data structure that stores these other parameters that define a servis,
 which takes the form of an Ansible group_vars file named for the servisName.

**providr**: Hosts are provided by providrs. These are Infrastructure as a Service (IAAS)
 providers such as EC2 and Rackspace. Providrs' names are semi-arbitrary, as long as they
 match in the couple of places they are defined in pansi. Providrs are actually a reference
 to an individual tennant/project/VPC-subnet within an IAAS provider (as opposed to the
 entire IAAS company, or everything a you host there... which would be too broad). Example
 providr names might be 'awapne2' if you had a single VPC in the Asia-Pacific
 Northeast-2 region of AWS or 'raxord2' for the second of two Rackspace accounts that
 deploy into the ORD datacenter in Chicago.

**labeling_group**: A host's "labeling_group" is the primary Ansible group pansi uses to keep
track of the host. The aforementioned example servis 'testar' is primarily tasked with
running Jenkins so the labeling_group is 'jenkins'.

Aside from providing a portion of the host's name in IAAS providers, distinguishing one group
as the labeling_group is mainly intended as a convenience for us humans. However, because the
idempotence of Ansible's cloud modules must depend on a label and the labeling_group is used
for that here, changing the labeling_group requires redeploying the servis unless the value
can be manually updated "out of band" in the IAAS provider's interface (where it may have to
be updated in several places/contexts). Otherwise you'll end up with twice the intended hosts
(one set with the new labeling_group, and one orphaned set set with the old one *which may
still see requests going to the old set and cause a sort of split-brain*).

**roles_applied**: The host will get added to a group named for each item in this list. The
plays in the playbook that apply roles will specify target hosts based on these groups.

Implementation notes:
**The list of groups a host is a member of will (at a minimum) consist of the union of the
labeling_group and the roles_applied list.** Although this means the labeling_group can be
used as if it were a value in the roles_applied list (regardless of whether it is also
listed there or not - this is a stylistic preference), the labeling_group is given no
special precedence in the deploy order. The order that entries are defined in the
roles_applied list also has no bearing. **The deploy order is determined by the playbook
for the servisType**. Returning to our fictitious included example 'testar': The playbook
deploying a skylab servis needs LDAP running before Jenkins can use it for auth, so the
group and plays for LDAP in the skylab playbook appear earlier than those for Jenkins in
spite of 'jenkins' being those host's labeling_group.

### What issue does pansi primarily target?

Ansible's documentation defines patterns for idempotently maintaining set numbers of hosts on IAAS providers such as AWS and Rackspace using attributes or tags to maintain desired counts for each type of host (specifically, the pattern of running a cloud module as a 'local_action:' and then iterating with 'add_host:' to get the cloud hosts into live inventory). However, the natural progression of deploying with this model is to statically write these host tags and counts into the playbook for each type of service that needs to be deployed. Further, if some instances of a service are on different providers or need to run different numbers of each type of host, the playbook for that specific service instance will then itself have multiple versions. Playbook upkeep and task duplication under this approach can become an issue even with a relatively small number of services deployed.

### How does pansi address the issue; are there other options?

The main goal of pansi is to document a pattern in which the variables that define the host-layout of a service can be stored in a variables file and "passed" (by the playbook for the service being deployed) to a set of generalized IAAS roles that will do the actual work with Ansible's cloud modules. Or in other words it is an abstraction designed to separate the playbooks that create and deploy the service from the variables that distinguish it from other services of the same type. Under this approach, each service only needs one playbook to deploy and maintain all instances of itself.

The distinction between pansi and maintaining static inventory is that pansi stores what types of hosts a service requires, how many there are of each type, and what service-specific variables there might be, but knows next to nothing about any individual host (thereby leaving that job to dynamic inventory scripts). This is a critical distinction for the purposes of staying on the 'cattle' side of the traditional pets v. cattle analogy.

Adding separate infrastructure tooling like Terraform to your systems is another solution (and in many cases a better, more full featured longterm option) but adoption can take time and may often get blocked by more immediate tasks. Pansi can be used as a stepping stone here because it has conceptual similarities to these "declarative infrastructure" tools, and because it consists purely of Ansible concepts and processes it is more quickly understood and implemented.

### Secondary issues/benefits

**Moving hosts with the traditional 'add_host:' loop**
Statically writing the 'local_action:' cloud module tasks into the playbooks that deploy your services (or, slightly better, storing those tasks separately and importing them) makes it cumbersome to move services or parts of services to other providers.

**Moving hosts with pansi**
Storing the parameters that define a service's layout separately allows for moving a host to another provider by changing a single variable. (Though, whether or not the entire service must be redeployed or host being relocated is simply killed prior to re-running Ansible still depends on what the service does and how it manages its state.)

### What does the name mean?

Deploying named instances of services onto providers is kind of PAAS-like; pansi is an assortment of
letters from the phrase "PAAS in Ansible" run together.

### Is there any other information about pansi that maybe hasn't been completely formatted yet that you could just sort of paste-vomit into this space for me to read?

These values are important to pansi:

- Creating new concepts and terms should be avoided in most cases in favor of recycling existing Ansible (or general
"cloud-ops") concepts and terminology. For example pansi defines host's Ansible group memberships directly in the
 group_vars files that define the servisParams, rather than creating a "servisRole" or "servisComponentType"
 parameter for what each host's purpose is and then having to map the appropriate set of Ansible groups in a
 servisRole-to-ansibleGroup data structure. Calling them what they are right in the servisParams (the
 "labeling_group" and the "roles_applied") removes the need for this extra layer of indirection.
- As pansi itself will be seen by some as an anti-pattern anyway, it's reasonable to utilize some anti-patterns or
 generally odd methods of accomplishing its goals. **HOWEVER**, finding innovative ways to make pansi's operations
 work more like current established Ansible patterns is a high-priority goal.
- The roadmap (not quite yet written down!) should always include discussion of options for further removing
concepts, terms, and anti-patterns that do not have their own application outside of pansi.

This is the current model in brief (and probably with technical omissions or misstatements):

- group_vars files that are understood to be used solely for pansi are created with a structure that defines an
instance of a service, and any variables specific to that service.
- The name of the service to be deployed is passed on the ansible-playbook command line (-e).
- A localhost play imports the group_vars file using the service name passed on the command line.
- 'add_host:' is used to create an alias of localhost for each combination of: 'IAAS_provider:labeling_group'.
  - host vars that will be used by provider roles are passed along in the add_host task.
- The play calls the provider role(s) once for each alias of localhost.

pansi is currently part of a production deployment and includes some interesting features like replacing the
default administrative user in the IAAS provider's disk image and switching to the new user both within a single run
of ansible-playbook, as well as deploying services divided arbitrarily across multiple IAAS providers (because of
how Ansible's cloud modules are used, the provider roles are written specifically for pansi, but they are all
functionally very similar to one another. EC2, Rackspace, and private OpenStack [the older nova compute module]
are implemented thus far).

Most if not all of this functionality will be added to this repo as portions of the existing implementation
are cleaned up and made less specific to their current use case.

### A couple of screen shots

![Untitled1.png](Untitled1.png)

![Untitled2.png](Untitled2.png)


text:
package com.redkite.plantcare.model.nosql;

import com.datastax.driver.mapping.annotations.Column;
import com.datastax.driver.mapping.annotations.PartitionKey;
import com.datastax.driver.mapping.annotations.Table;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "invalidated_tokens")
public class InvalidatedTokens {

  @PartitionKey
  @Column(name = "user_id")
  private Long userId;

  @Column
  private Long timestamp;
}


text:
foam.CLASS({
  package: 'foam.nanos.auth',
  name: 'CreatedAwareDAO',
  extends: 'foam.dao.ProxyDAO',

  documentation: 'DAO that sets created property',

  javaImports: [
    'java.util.Calendar',
    'java.util.TimeZone'
  ],

  methods: [
    {
      name: 'put_',
      code: function(x, obj) {
        if ( ! foam.nanos.auth.CreatedAware.isInstance(obj) ) {
          return this.delegate.put_(x, obj);
        }
        return this.delegate.find_(x, obj).then(function(result) {
          if ( result == null ) {
            obj.created = new Date();
          }
          return this.delegate.put_(x, obj);
        }.bind(this));
      },
      javaCode: `
        // only set created if object does not exist in DAO yet
        if ( obj instanceof CreatedAware && getDelegate().find_(x, obj) == null ) {
          ((CreatedAware) obj).setCreated(Calendar.getInstance(TimeZone.getTimeZone("UTC")).getTime());
        }
        return super.put_(x, obj);
      `
    }
  ]
});


text:
<?php

namespace Arisharyanto\Laracrop;

use Illuminate\Support\ServiceProvider;
use Illuminate\Routing\Router;
use Route;
use Blade;
use URL;

class LaracropServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot(\Illuminate\Routing\Router $router)
    {
        $this->mergeConfigFrom(
            __DIR__.'/config/laracrop.php', 'laracrop'
        );
        $this->publishes([__DIR__.'/config' => config_path()], 'config');
        $this->publishes([__DIR__.'/plugins' => public_path('vendor/laracrop')], 'public');

        $this->setupRoutes($this->app->router);

        $baseUrl = URL::to('/');
        $uploadUrl = $baseUrl.'/'.config('laracrop.route_prefix').'/'.config('laracrop.upload_url');

        Blade::directive('laracropCss', function ($bootstrap = false) use ($baseUrl) {
            $addBootsrap = '';
            if($bootstrap){
                $addBootsrap = '<link rel="stylesheet" href="'.$baseUrl.'/vendor/laracrop/bootstrap/css/bootstrap.min.css">';
            }
            return $addBootsrap.'<link rel="stylesheet" href="'.$baseUrl.'/vendor/laracrop/jCrop/css/Jcrop.css">
                    <link rel="stylesheet" href="'.$baseUrl.'/vendor/laracrop/jCrop/css/demos.css">';
        });
        Blade::directive('laracropJs', function ($jQuery = false) use ($baseUrl) {
            $addjQuery = '';
            if($jQuery){
                $addjQuery = '<script src="'.$baseUrl.'/vendor/laracrop/jQuery/jquery-2.2.3.min.js"></script>';
            }
            return $addjQuery.'<script src="'.$baseUrl.'/vendor/laracrop/jCrop/js/Jcrop.js"></script>
                    <script src="'.$baseUrl.'/vendor/laracrop/laracrop.js"></script>';
        });
        Blade::directive('laracrop', function ($option) use ($baseUrl, $uploadUrl) {

            $newArr = array();
            $option = preg_replace('/\s+/', '', $option);
            if (preg_match('/\[|]/', $option)){

                $arr = explode('|', $option);
                foreach ($arr as $data) {
                    $exp = explode('=', $data);
                    $newArr[$exp[0]] = $exp[1];
                }

            }else{
                $newArr['name'] = $option;
            }
            $newArr = (object) $newArr;

            $name = $newArr->name;
            $aspectratio    = isset($newArr->aspectratio) ? $newArr->aspectratio : config('laracrop.aspectratio');
            $minsize        = isset($newArr->minsize) ? $newArr->minsize : config('laracrop.minsize');
            $maxsize        = isset($newArr->maxsize) ? $newArr->maxsize : config('laracrop.maxsize');
            $bgcolor        = isset($newArr->bgcolor) ? $newArr->bgcolor : config('laracrop.bgcolor');
            $bgopacity      = isset($newArr->bgopacity) ? $newArr->bgopacity : config('laracrop.bgopacity');
            $boxwidth       = isset($newArr->boxwidth) ? $newArr->boxwidth : config('laracrop.boxwidth');
            $boxheight      = isset($newArr->boxheight) ? $newArr->boxheight : config('laracrop.boxheight');

            return '<div class="form-group showimage">
                      <input type="file" class="cropimage form-control" name="'.$name.'"
                        data-uploadurl="'.$uploadUrl.'"
                        data-aspectratio="'.$aspectratio.'"
                        data-minsize="'.$minsize.'"
                        data-maxsize="'.$maxsize.'"
                        data-bgcolor="'.$bgcolor.'"
                        data-bgopacity="'.$bgopacity.'"
                        data-boxwidth="'.$boxwidth.'"
                        data-boxheight="'.$boxheight.'"
                        class="form-control">
                    </div>';
        });
    }

    public function setupRoutes(Router $router)
    {
        $router->group(['namespace' => 'Arisharyanto\Laracrop'], function ($router) {
            Route::group(['prefix' => config('laracrop.route_prefix')], function () {
                Route::post(config('laracrop.upload_url'), 'Laracrop@uploadAjax');
            });
        });
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {

    }
}


text:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE locale SYSTEM "../../../../../lib/pkp/dtd/locale.dtd">

<!--
  * plugins/paymethod/manual/locale/nb_NO/locale.xml
  *
  * Copyright (c) 2003-2013 John Willinsky
  * Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
  *
  * Localization strings for the nb_NO (Norwegian) locale.
  -->

<locale name="nb_NO" full_name="Norwegian">
	<message key="plugins.paymethod.manual.displayName">Manuell betaling av gebyr</message>
	<message key="plugins.paymethod.manual.description">Redaksjonsleder vil registrere og kvittere for brukernes innbetalinger manuelt (utenfor denne programvaren).</message>
	<message key="plugins.paymethod.manual">Manuell betaling av gebyr</message>
	<message key="plugins.paymethod.manual.settings">Innstillinger for Manuell betaling av gebyr</message>
	<message key="plugins.paymethod.manual.settings.instructions">Instruks</message>
	<message key="plugins.paymethod.manual.settings.manualInstructions">Instruks for gebyrinnbetaling for brukere som velger Manuell betaling av gebyr</message>

	<message key="plugins.paymethod.manual.sendNotificationOfPayment">Send betalingsvarsel</message>
	<message key="plugins.paymethod.manual.paymentNotification">Betalingsvarsel</message>
	<message key="plugins.paymethod.manual.notificationSent">Betalingsvarsel sendt</message>

	<message key="plugins.paymethod.manual.purchase.title">Tittel</message>
	<message key="plugins.paymethod.manual.purchase.fee">Gebyr</message>
</locale>


text:
@interface MockTest : SenTestCase

@end


text:
package common.zeroquest.world;

import net.minecraft.world.WorldType;
import net.minecraft.world.gen.layer.GenLayer;
import net.minecraft.world.gen.layer.GenLayerAddIsland;
import net.minecraft.world.gen.layer.GenLayerAddMushroomIsland;
import net.minecraft.world.gen.layer.GenLayerAddSnow;
import net.minecraft.world.gen.layer.GenLayerBiome;
import net.minecraft.world.gen.layer.GenLayerFuzzyZoom;
import net.minecraft.world.gen.layer.GenLayerHills;
import net.minecraft.world.gen.layer.GenLayerIsland;
import net.minecraft.world.gen.layer.GenLayerRiver;
import net.minecraft.world.gen.layer.GenLayerRiverInit;
import net.minecraft.world.gen.layer.GenLayerRiverMix;
import net.minecraft.world.gen.layer.GenLayerShore;
import net.minecraft.world.gen.layer.GenLayerSmooth;
import net.minecraft.world.gen.layer.GenLayerSwampRivers;
import net.minecraft.world.gen.layer.GenLayerVoronoiZoom;
import net.minecraft.world.gen.layer.GenLayerZoom;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.terraingen.WorldTypeEvent;

public abstract class GenLayerZQuest extends GenLayer
{
	public GenLayerZQuest(long seed) {
		super(seed);
	}

	public static GenLayer[] makeTheWorld(long seed) {

		GenLayer biomes = new GenLayerBiomesZeroQuest(1L);

		// more GenLayerZoom = bigger biomes
		biomes = new GenLayerZoom(1000L, biomes);
		biomes = new GenLayerZoom(1001L, biomes);
		biomes = new GenLayerZoom(1002L, biomes);
		biomes = new GenLayerZoom(1003L, biomes);
		biomes = new GenLayerZoom(1004L, biomes);
		biomes = new GenLayerZoom(1005L, biomes);

		GenLayer genlayervoronoizoom = new GenLayerVoronoiZoom(10L, biomes);

		biomes.initWorldGenSeed(seed);
		genlayervoronoizoom.initWorldGenSeed(seed);

		return new GenLayer[] {biomes, genlayervoronoizoom};
	}
}


text:
from bibliopixel.animation.matrix import Matrix
from bibliopixel.util.image import load_image
from random import shuffle
import os

class ImageDissolve(Matrix):

    def __init__(self, layout, imageFiles=None, pixelRate=10, waitFrames=30,
                 **kwds):
        super().__init__(layout, **kwds)
        self.pixelRate = pixelRate
        if imageFiles is None:
            imageFiles = []
            cur_dir = os.path.dirname(os.path.realpath(__file__))
            imageFiles.append(os.path.abspath(os.path.join(cur_dir, '../../Graphics/ml_logo.bmp')))
            imageFiles.append(os.path.abspath(os.path.join(cur_dir, '../../Graphics/rainbow.jpg')))
        self.imageFiles = imageFiles
        self.imgIndex = 0
        self.waitFrames = waitFrames
        self.waitCount = 0

    def pre_run(self):
        self.resetAndLoad()
        self.imgIndex = 0
        self.waitCount = 0

    def resetAndLoad(self):
        self.layout.setTexture(load_image.loadImage(self.layout, imagePath=self.imageFiles[self.imgIndex]))
        self.map = [(x, y) for x in range(self.width) for y in range(self.height)]
        shuffle(self.map)

    def step(self, amt):
        if self.waitCount == 0:
            for i in range(self.pixelRate):
                x, y = self.map.pop()
                self.layout.set(x, y)
                if len(self.map) == 0:
                    if len(self.imageFiles) == 1:
                        self.layout.all_off()
                        self.animComplete = True
                    else:
                        self.imgIndex += 1
                        if self.imgIndex >= len(self.imageFiles):
                            self.animComplete = True
                            self.imgIndex = 0
                    self.waitCount = self.waitFrames
                    self.resetAndLoad()
                    break
        else:
            self.waitCount -= 1


text:
body.toplevel_page_bp-groups table.groups th#status,
body.toplevel_page_bp-groups table.groups th#members {
	width: 10%;
}

body.toplevel_page_bp-groups table.groups th#last_active {
	width: 15%;
}

#bp-groups-form .avatar {
	float: left;
	margin-right: 10px;
	margin-top: 1px;
}

#bp-groups-edit-form input {
	outline: medium none;
}

#bp-groups-edit-form input#bp-groups-name {
	font-size: 1.7em;
	width: 100%;
	margin-bottom: 6px;
}

#bp-groups-edit-form input#bp-groups-new-members {
	border: 1px solid #e5e5e5;
	margin-top: 6px;
	width: 100%;
}

#bp-groups-new-members-list {
	margin: 0;
}

.bp-groups-settings-section {
	margin-top: 10px;
	line-height: 2;
}

.bp-groups-settings-section legend {
	margin-top: 10px;
	font-weight: 700;
}

.bp-groups-settings-section label {
	clear: left;
	display: block;
	float: left;
	vertical-align: middle;
}

#bp-groups-permalink-box {
	line-height: 24px;
	color: #666;
}

#bp-groups-permalink {
	margin-right: 24px;
}

.bp-groups-member-type {
	position: relative;
}

.bp-groups-member-type > h4 {
	margin-bottom: 0.5em;
}

ul.bp-group-delete-list {
	list-style-type: disc;
	margin: 4px 26px;
}

/*
 * Members Pagination
 */
.bp-group-admin-pagination {
	position: absolute;
	text-align: right;
	width: 100%;
}

.bp-group-admin-pagination.table-top {
	top: 0;
}

.bp-group-admin-pagination.table-bottom {
	bottom: 0;
}

.bp-group-admin-pagination-viewing {
	color: #777;
	font-size: 12px;
	font-style: italic;
}

.bp-group-admin-pagination-links {
	white-space: nowrap;
	padding-left: 15px;
}

.bp-group-admin-pagination-links .page-numbers {
	display: inline-block;
	min-width: 12px;
	border: 1px solid #ccc;
	padding: 2px 4px 4px;
	background: #e5e5e5;
	line-height: 1;
	font-weight: 400;
	text-align: center;
	text-decoration: none;
}

.bp-group-admin-pagination-links a.page-numbers:hover {
	text-decoration: underline;
}

.bp-group-admin-pagination-links .page-numbers.current,
.bp-group-admin-pagination-links .page-numbers.dots {
	border-color: #ddd;
	background: #f7f7f7;
	color: #a0a5aa;
}

/*
 * Members List
 */
table.bp-group-members .uid-column {
	padding-left: 20px;
	padding-right: 20px;
}

table.bp-group-members .uname-column {
	width: 70%;
}

table.bp-group-members .urole-column {
	padding-left: 20px;
	padding-right: 20px;
}

@media screen and (max-width: 782px) {

	.bp-groups-settings-section label {
		margin: 0.25em 0;
	}
}


text:
import { Routes } from '@angular/router';
import { HomeComponent } from './home';
import { NoContentComponent } from './no-content';

export const ROUTES: Routes = [
  { path: '',      component: HomeComponent },
  { path: 'home',  component: HomeComponent },
  { path: '**',    component: NoContentComponent },
];


text:
(function(can, window, undefined){

can.each([ can.Observe, can.Model ], function(clss){
	// in some cases model might not be defined quite yet.
	if(clss === undefined){
		return;
	}

	can.extend(clss, {
		/**
		 * @attribute can.Observe.static.attributes
		 * @parent can.Observe.attributes
		 *
		 * `can.Observe.attributes` is a property that contains key/value pair(s) of an attribute's name and its
		 * respective type for using in [can.Observe.static.convert convert] and [can.Observe.prototype.serialize serialize].
		 *
		 *		var Contact = can.Observe({
		 *			attributes : {
		 *				birthday : 'date',
		 *				age: 'number',
		 *				name: 'string'
		 *			}
		 *		});
		 *
		 */
		attributes : {},

		/**
		 * @attribute can.Observe.static.convert
		 * @parent can.Observe.attributes
		 *
		 * You often want to convert from what the observe sends you to a form more useful to JavaScript.
		 * For example, contacts might be returned from the server with dates that look like: "1982-10-20".
		 * We can observe to convert it to something closer to `new Date(1982,10,20)`.
		 *
		 * Convert comes with the following types:
		 *
		 * - __date__ Converts to a JS date. Accepts integers or strings that work with Date.parse
		 * - __number__ An integer or number that can be passed to parseFloat
		 * - __boolean__ Converts "false" to false, and puts everything else through Boolean()
		 *
		 * The following sets the birthday attribute to "date" and provides a date conversion function:
		 *
		 *		var Contact = can.Observe({
		 *			attributes : {
		 *				birthday : 'date'
		 *			},
		 *			convert : {
		 *				date : function(raw){
		 *					if(typeof raw == 'string'){
		 *						//- Extracts dates formated 'YYYY-DD-MM'
		 *						var matches = raw.match(/(\d+)-(\d+)-(\d+)/);
		 *
		 *						//- Parses to date object and returns
		 *						return new Date(matches[1],
		 *								        (+matches[2])-1,
		 *									    matches[3]);
		 *
		 *					}else if(raw instanceof Date){
		 *						return raw;
		 *					}
		 *				}
		 *			}
		 *		},{});
		 *
		 *		var contact = new Contact();
		 *
		 *		//- calls convert on attribute set
		 *		contact.attr('birthday', '4-26-2012')
		 *
		 *		contact.attr('birthday'); //-> Date
		 *
		 * ## Assocations and Convert
		 *
		 * If you have assocations defined within your model(s), you can use convert to automatically
		 * call seralize on those models.
		 *
		 * 		can.Model("Contact",{
		 * 			attributes : {
		 * 				tasks: "Task.models"
		 * 			}
		 * 		}, {});
		 *
		 * 		can.Model("Task",{
		 * 			attributes : {
		 * 				due : 'date'
		 * 			}
		 * 		},{});
		 *
		 * 		var contact = new Contact({
		 * 			tasks: [ new Task({
		 * 				due: new Date()
		 * 			}) ]
		 * 		});
		 *
		 * 		contact.seralize();
		 * 		//-> { tasks: [ { due: 1333219754627 } ] }
		 *
		 */
		convert: {
			"date": function( str ) {
				var type = typeof str;
				if ( type === "string" ) {
					return isNaN(Date.parse(str)) ? null : Date.parse(str)
				} else if ( type === 'number' ) {
					return new Date(str)
				} else {
					return str
				}
			},
			"number": function( val ) {
				return parseFloat(val);
			},
			"boolean": function( val ) {
				return Boolean(val === "false" ? 0 : val);
			},
			"default": function( val, error, type ) {
				var construct = can.getObject(type),
					context = window,
					realType;
				// if type has a . we need to look it up
				if ( type.indexOf(".") >= 0 ) {
					// get everything before the last .
					realType = type.substring(0, type.lastIndexOf("."));
					// get the object before the last .
					context = can.getObject(realType);
				}
				return typeof construct == "function" ? construct.call(context, val) : val;
			}
		},
		/**
		 * @attribute can.Observe.static.serialize
		 * @parent can.Observe.attributes
		 *
		 * `can.Observe.static.seralize` is object of name-function pairs that are used to
		 * serialize attributes.
		 *
		 * Similar to [can.Observe.convert], in that the keys of this object correspond to
		 * the types specified in [can.Observe.attributes].
		 *
		 * By default every attribute will be passed through the 'default' serialization method
		 * that will return the value if the property holds a primitive value (string, number, ...),
		 * or it will call the "serialize" method if the property holds an object with the "serialize" method set.
		 *
		 * For example, to serialize all dates to ISO format:
		 *
		 * 		var Contact = can.Observe({
		 * 			attributes : {
		 * 				birthday : 'date'
		 * 			},
		 * 			serialize : {
		 * 				date : function(val, type){
		 * 					return new Date(val).toISOString();
		 * 				}
		 * 			}
		 * 		},{});
		 *
		 * 		var contact = new Contact({
		 * 			birthday: new Date("Oct 25, 1973")
		 * 		}).serialize();
		 * 		//-> { "birthday" : "1973-10-25T05:00:00.000Z" }
		 *
		 */
		serialize: {
			"default": function( val, type ) {
				return isObject(val) && val.serialize ? val.serialize() : val;
			},
			"date": function( val ) {
				return val && val.getTime()
			}
		}
	});

	// overwrite setup to do this stuff
	var oldSetup = clss.setup;

	/**
	 * @hide
	 * @attribute can.Observe.static.setup
	 * @parent can.Observe.attributes
	 *
	 * `can.Observe.static.setup` overrides default `can.Observe` setup to provide
	 * functionality for attributes.
	 *
	 */
	clss.setup = function(superClass, stat, proto){
		var self = this;
		oldSetup.call(self, superClass, stat, proto);

		can.each(["attributes", "validations"], function( name ) {
			if (!self[name] || superClass[name] === self[name] ) {
				self[name] = {};
			}
		});

		can.each(["convert", "serialize"], function( name ) {
			if ( superClass[name] != self[name] ) {
				self[name] = can.extend({}, superClass[name], self[name]);
			}
		});
	};
});

/**
 * @hide
 * @function can.Observe.prototype.convert
 * @parent can.Observe.attributes
 */
can.Observe.prototype.__convert = function(prop, value){
	// check if there is a

	var Class = this.constructor,
		val, type, converter;

	if(Class.attributes){
		// the type of the attribute
		type = Class.attributes[prop];
		converter = Class.convert[type] || Class.convert['default'];
	}

	return value === null || !type ?
			// just use the value
			value :
			// otherwise, pass to the converter
			converter.call(Class, value, function() {}, type);
};

/**
 * @function can.Observe.prototype.serialize
 * @parent can.Observe.attributes
 *
 * `can.Observe.prototype.serialize` serializes an object for the object.
 * Serialized data is typically used to send back to a server.
 *
 * You can set the serialization methods similar to the convert methods:
 *
 *		var Contact = can.Observe({
 *			attributes : {
 *				birthday : 'date'
 *			},
 *			serialize : {
 *				date : function( val, type ){
 *					return val.getYear() +
 *						"-" + (val.getMonth() + 1) +
 *						"-" + val.getDate();
 *				}
 *			}
 *		},{})
 *
 *		var contact = new Contact();
 *		contact.attr('birthday', new Date());
 *		contact.serialize()
 *		//-> { birthday: 'YYYY-MM-DD' }
 *
 * You can also get and serialize an individual property by passing the attribute
 * name to the `serialize` function.  Building on the above demo, we can serialize
 * the `birthday` attribute only.
 *
 *		contact.serialize('birthday') //-> 'YYYY-MM-DD'
 *
 * @param {Object} attrName (optional) when passed returns only that attribute name
 */
can.Observe.prototype.serialize = function(attrName){
	var where = {},
		Class = this.constructor,
		attrs = {};

	if(attrName != undefined){
		attrs[attrName] = this[attrName];
	} else {
		attrs = this.__get();
	}

	can.each(attrs, function( val, name ) {
		var type = Class.attributes[name],
			converter= Class.serialize[type];

		// if the value is an object, and has a attrs or serialize function
		where[name] = val && typeof val.serialize == 'function' ?
		// call attrs or serialize to get the original data back
		val.serialize() :
		// otherwise if we have  a converter
		converter ?
			// use the converter
			converter(val, type) :
			// or return the val
			val
	});

	return attrName != undefined ? where[attrName] : where;
};

})(this.can, this )


text:
! { dg-do compile }
! PR 18197: Check that dummy functions with RESULT variable and dimension works.
module innerfun
contains
  function f(n,x) result(y)
    integer, intent(in) :: n
    real, dimension(:), intent(in) :: x
    real, dimension(n) :: y
    y = 1
  end function f
end module innerfun

module outerfun
contains
   subroutine foo(n,funname)
     integer, intent(in) :: n
     real, dimension(n) :: y
     real, dimension(2) :: x
     interface
       function funname(n,x) result(y)
         integer, intent(in) :: n
         real, dimension(:), intent(in) :: x
         real, dimension(n)  :: y
       end function funname
     end interface

     y = funname(n, (/ 0.2, 0.3 /) )

   end subroutine foo
end module outerfun

program test
   use outerfun
   use innerfun
   call foo(3,f)
end program test

! { dg-final { cleanup-modules "innerfun outerfun" } }


text:
package rtdc.android.impl;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import rtdc.android.R;
import rtdc.core.impl.UiDropdown;
import rtdc.core.util.Stringifier;

import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;

/**
 * Android abstraction of a dropdown box
 */
public class AndroidUiDropdown<T> extends Spinner implements UiDropdown<T> {

    private final CustomAdapter adapter;
    private T[] dropDownValues;
    private Stringifier<T> stringifier = DEFAULT_STRINGIFIER;

    public AndroidUiDropdown(Context context) {
        super(context);

        adapter = new CustomAdapter(context, R.layout.dropdown_list_item);
        setAdapter(adapter);
    }

    public AndroidUiDropdown(Context context, AttributeSet attrs) {
        super(context, attrs);
        adapter = new CustomAdapter(context, R.layout.dropdown_list_item);
        setAdapter(adapter);
    }

    public AndroidUiDropdown(Context context, AttributeSet attrs, int defStyle){
        super(context, attrs, defStyle);
        adapter = new CustomAdapter(context, R.layout.dropdown_list_item);
        setAdapter(adapter);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int getSelectedIndex(){
        return getSelectedItemPosition();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setStringifier(Stringifier<T> stringifier) {
        this.stringifier = stringifier;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public T getValue() {
        return adapter.getItem(getSelectedItemPosition());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setArray(T[] elements) {
        adapter.clear();
        adapter.addAll(Arrays.asList(elements));
        adapter.notifyDataSetChanged();
        dropDownValues = elements;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setValue(T value) {
        int position = adapter.getPosition(value);

        if(position != -1) {
            for (int i = 0; i < dropDownValues.length; i++) {
                T dropDownValue = dropDownValues[i];
                if (stringifier.toString(dropDownValue).equals(stringifier.toString(value))) {
                    position = adapter.getPosition(value);
                }
            }
        }

        if(position != -1)
            setSelection(position);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getErrorMessage() {
        return "";
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setErrorMessage(String errorMessage) {
        //Does nothing
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setFocus(boolean hasFocus) {
        if(hasFocus)
            requestFocus();
    }

    private class CustomAdapter extends ArrayAdapter<T> {

        public CustomAdapter(Context context, int resource) {
            super(context, resource);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null)
                convertView = LayoutInflater.from(this.getContext())
                        .inflate(R.layout.dropdown_selected_item, parent, false);
            return getCustomView(position, convertView, parent);
        }

        @Override
        public View getDropDownView(int position, View convertView,ViewGroup parent) {
            if (convertView == null)
                convertView = LayoutInflater.from(this.getContext())
                        .inflate(R.layout.dropdown_list_item, parent, false);
            return getCustomView(position, convertView, parent);
        }

        private View getCustomView(int position, View convertView, ViewGroup parent){

            T item = getItem(position);
            TextView textView = (TextView) convertView.findViewById(R.id.dropDownText);

            String name = stringifier.toString(item);

            if (item!= null)
                textView.setText(name);

            return convertView;
        }

    }

}


text:
<?xml version="1.0" encoding="UTF-8"?>
<!--   Copyright (C) 2013-2014 Computer Sciences Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. -->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>ezbake</groupId>
        <artifactId>ezbake-parent</artifactId>
        <version>0.1-SNAPSHOT</version>
    </parent>

    <groupId>ezbake</groupId>
    <artifactId>ins-parent</artifactId>
    <packaging>pom</packaging>

    <modules>
        <module>gen</module>
        <module>impl</module>
        <module>web</module>
	<module>admin</module>
    </modules>

    <dependencies>
        <dependency>
            <groupId>org.apache.thrift</groupId>
            <artifactId>libthrift</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>


text:
package com.espirit.moddev.cli.api.parsing.identifier;

import de.espirit.firstspirit.access.store.IDProvider;
import de.espirit.firstspirit.access.store.Store;
import de.espirit.firstspirit.access.store.contentstore.Content2;
import de.espirit.firstspirit.access.store.mediastore.Media;
import de.espirit.firstspirit.access.store.mediastore.MediaFolder;
import de.espirit.firstspirit.access.store.pagestore.Page;
import de.espirit.firstspirit.access.store.pagestore.PageFolder;
import de.espirit.firstspirit.access.store.sitestore.DocumentGroup;
import de.espirit.firstspirit.access.store.sitestore.PageRef;
import de.espirit.firstspirit.access.store.sitestore.PageRefFolder;
import de.espirit.firstspirit.access.store.templatestore.*;

import java.util.Locale;

import de.espirit.firstspirit.access.store.globalstore.GCAPage;

/**
 * This enum specifies all valid prefixes for {@link UidIdentifier}. A prefix
 * always determines in which store to search for an element, which FirstSpirit
 * {@link de.espirit.firstspirit.access.store.IDProvider.UidType} is addressed by
 * the prefix and by which class the found result should be filtered.
 */
public enum UidMapping {
    CONTENT2(Store.Type.CONTENTSTORE, IDProvider.UidType.CONTENTSTORE, Content2.class),
    GCAPAGE(Store.Type.GLOBALSTORE, IDProvider.UidType.GLOBALSTORE, GCAPage.class),
    MEDIAFOLDER(Store.Type.MEDIASTORE, IDProvider.UidType.MEDIASTORE_FOLDER, MediaFolder.class),
    MEDIA(Store.Type.MEDIASTORE, IDProvider.UidType.MEDIASTORE_LEAF, Media.class),
    PAGE(Store.Type.PAGESTORE, IDProvider.UidType.PAGESTORE, Page.class),
    PAGEFOLDER(Store.Type.PAGESTORE, IDProvider.UidType.PAGESTORE, PageFolder.class),
    PAGEREFFOLDER(Store.Type.SITESTORE, IDProvider.UidType.SITESTORE_FOLDER, PageRefFolder.class),
    DOCUMENTGROUP(Store.Type.SITESTORE, IDProvider.UidType.SITESTORE_LEAF, DocumentGroup.class),
    PAGEREF(Store.Type.SITESTORE, IDProvider.UidType.SITESTORE_LEAF, PageRef.class),
    PAGETEMPLATE(Store.Type.TEMPLATESTORE, IDProvider.UidType.TEMPLATESTORE, PageTemplate.class),
    SCRIPT(Store.Type.TEMPLATESTORE, IDProvider.UidType.TEMPLATESTORE, Script.class),
    SECTIONTEMPLATE(Store.Type.TEMPLATESTORE, IDProvider.UidType.TEMPLATESTORE, SectionTemplate.class),
    WORKFLOW(Store.Type.TEMPLATESTORE, IDProvider.UidType.TEMPLATESTORE, Workflow.class),
    FORMATTEMPLATE(Store.Type.TEMPLATESTORE, IDProvider.UidType.TEMPLATESTORE_FORMATTEMPLATE, FormatTemplate.class),
    LINKTEMPLATE(Store.Type.TEMPLATESTORE, IDProvider.UidType.TEMPLATESTORE_LINKTEMPLATE, LinkTemplate.class),
    QUERY(Store.Type.TEMPLATESTORE, IDProvider.UidType.TEMPLATESTORE_SCHEMA, Query.class),
    TABLETEMPLATE(Store.Type.TEMPLATESTORE, IDProvider.UidType.TEMPLATESTORE_SCHEMA, TableTemplate.class),
    STYLETEMPLATE(Store.Type.TEMPLATESTORE, IDProvider.UidType.TEMPLATESTORE_STYLETEMPLATE, StyleTemplate.class),
    TABLEFORMATTEMPLATE(Store.Type.TEMPLATESTORE, IDProvider.UidType.TEMPLATESTORE_TABLEFORMATTEMPLATE, TableFormatTemplate.class);

    private IDProvider.UidType uidType;
    private Class<?> correspondingType;
    private Store.Type storeType;

    UidMapping(Store.Type storeType, IDProvider.UidType uidType, Class correspondingType) {
        this.storeType = storeType;
        this.uidType = uidType;
        this.correspondingType = correspondingType;
    }

    /**
     * Getter for the prefix string, that identifies a mapping.
     * @return the prefix string that corresponds to this mapping
     */
    public String getPrefix() {
        return this.name().toLowerCase(Locale.UK);
    }

    /**
     * Getter for the {@link de.espirit.firstspirit.access.store.IDProvider.UidType} the
     * uid mapping corresponds to.
     * @return the {@link de.espirit.firstspirit.access.store.IDProvider.UidType} for this mapping
     */
    public IDProvider.UidType getUidType() {
        return uidType;
    }

    /**
     * Getter for the class, a uid mapping uses for filtering.
     * @return the class of which corresponding elements should be
     */
    public Class<?> getCorrespondingType() {
        return correspondingType;
    }

    /**
     * Getter for the {@link de.espirit.firstspirit.base.store.StoreType}
     * @return the {@link de.espirit.firstspirit.base.store.StoreType} used by this mapping
     */
    public Store.Type getStoreType() {
        return storeType;
    }
}


text:
package TestAPI::response;

# testing Apache2::Response methods
#
# XXX: a proper test is needed (at the moment just test that methods
# can be invoked as documented)

use strict;
use warnings FATAL => 'all';

use Apache2::RequestRec ();
use Apache2::Response ();

use Apache::Test;
use Apache::TestUtil;

use Apache2::Const -compile => 'OK';

sub handler {
    my $r = shift;

    plan $r, tests => 7;

    my $etag = $r->make_etag();
    t_debug $etag;
    ok $etag;

    $r->set_content_length(0);

    ok 1;

    ok $r->meets_conditions || 1;

    ok $r->rationalize_mtime(time) >= $r->request_time;

    my $mtime = (stat __FILE__)[9];

    $r->update_mtime($mtime);

    ok $r->mtime == $mtime;

    ok $r->set_keepalive() || 1;

    $r->set_last_modified;

    # $r->custom_response() is tested in TestAPI::custom_response

    ok 1;

    Apache2::Const::OK;
}

1;