#include <srs_app_http_conn.hpp>

#if defined(SRS_AUTO_HTTP_CORE)

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

#include <sstream>
using namespace std;

#include <srs_protocol_buffer.hpp>
#include <srs_rtmp_utility.hpp>
#include <srs_kernel_log.hpp>
#include <srs_kernel_error.hpp>
#include <srs_app_st.hpp>
#include <srs_core_autofree.hpp>
#include <srs_app_config.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_kernel_file.hpp>
#include <srs_kernel_flv.hpp>
#include <srs_rtmp_stack.hpp>
#include <srs_app_source.hpp>
#include <srs_rtmp_msg_array.hpp>
#include <srs_kernel_aac.hpp>
#include <srs_kernel_mp3.hpp>
#include <srs_kernel_ts.hpp>
#include <srs_app_pithy_print.hpp>
#include <srs_app_source.hpp>
#include <srs_app_server.hpp>
#include <srs_app_http_static.hpp>
#include <srs_app_http_stream.hpp>
#include <srs_app_http_api.hpp>
#include <srs_app_utility.hpp>

#endif

#ifdef SRS_AUTO_HTTP_CORE

SrsHttpResponseWriter::SrsHttpResponseWriter(SrsStSocket* io)
{
    skt = io;
    hdr = new SrsHttpHeader();
    header_wrote = false;
    status = SRS_CONSTS_HTTP_OK;
    content_length = -1;
    written = 0;
    header_sent = false;
    nb_iovss_cache = 0;
    iovss_cache = NULL;
}

SrsHttpResponseWriter::~SrsHttpResponseWriter()
{
    srs_freep(hdr);
    srs_freepa(iovss_cache);
}

int SrsHttpResponseWriter::final_request()
{
    // write the header data in memory.
    if (!header_wrote) {
        write_header(SRS_CONSTS_HTTP_OK);
    }

    // complete the chunked encoding.
    if (content_length == -1) {
        std::stringstream ss;
        ss << 0 << SRS_HTTP_CRLF << SRS_HTTP_CRLF;
        std::string ch = ss.str();
        return skt->write((void*)ch.data(), (int)ch.length(), NULL);
    }

    // flush when send with content length
    return write(NULL, 0);
}

SrsHttpHeader* SrsHttpResponseWriter::header()
{
    return hdr;
}

int SrsHttpResponseWriter::write(char* data, int size)
{
    int ret = ERROR_SUCCESS;

    // write the header data in memory.
    if (!header_wrote) {
        write_header(SRS_CONSTS_HTTP_OK);
    }

    // whatever header is wrote, we should try to send header.
    if ((ret = send_header(data, size)) != ERROR_SUCCESS) {
        srs_error("http: send header failed. ret=%d", ret);
        return ret;
    }

    // check the bytes send and content length.
    written += size;
    if (content_length != -1 && written > content_length) {
        ret = ERROR_HTTP_CONTENT_LENGTH;
        srs_error("http: exceed content length. ret=%d", ret);
        return ret;
    }

    // ignore NULL content.
    if (!data) {
        return ret;
    }

    // directly send with content length
    if (content_length != -1) {
        return skt->write((void*)data, size, NULL);
    }

    // send in chunked encoding.
    int nb_size = snprintf(header_cache, SRS_HTTP_HEADER_CACHE_SIZE, "%x", size);

    iovec iovs[4];
    iovs[0].iov_base = (char*)header_cache;
    iovs[0].iov_len = (int)nb_size;
    iovs[1].iov_base = (char*)SRS_HTTP_CRLF;
    iovs[1].iov_len = 2;
    iovs[2].iov_base = (char*)data;
    iovs[2].iov_len = size;
    iovs[3].iov_base = (char*)SRS_HTTP_CRLF;
    iovs[3].iov_len = 2;

    ssize_t nwrite;
    if ((ret = skt->writev(iovs, 4, &nwrite)) != ERROR_SUCCESS) {
        return ret;
    }

    return ret;
}

int SrsHttpResponseWriter::writev(iovec* iov, int iovcnt, ssize_t* pnwrite)
{
    int ret = ERROR_SUCCESS;

    // when header not ready, or not chunked, send one by one.
    if (!header_wrote || content_length != -1) {
        ssize_t nwrite = 0;
        for (int i = 0; i < iovcnt; i++) {
            iovec* piovc = iov + i;
            nwrite += piovc->iov_len;
            if ((ret = write((char*)piovc->iov_base, (int)piovc->iov_len)) != ERROR_SUCCESS) {
                return ret;
            }
        }

        if (pnwrite) {
            *pnwrite = nwrite;
        }

        return ret;
    }

    // ignore NULL content.
    if (iovcnt <= 0) {
        return ret;
    }

    // send in chunked encoding.
    int nb_iovss = 3 + iovcnt;
    iovec* iovss = iovss_cache;
    if (nb_iovss_cache < nb_iovss) {
        srs_freepa(iovss_cache);
        nb_iovss_cache = nb_iovss;
        iovss = iovss_cache = new iovec[nb_iovss];
    }

    // send in chunked encoding.

    // chunk size.
    int size = 0;
    for (int i = 0; i < iovcnt; i++) {
        iovec* data_iov = iov + i;
        size += data_iov->iov_len;
    }
    written += size;

    // chunk header
    int nb_size = snprintf(header_cache, SRS_HTTP_HEADER_CACHE_SIZE, "%x", size);
    iovec* iovs = iovss;
    iovs[0].iov_base = (char*)header_cache;
    iovs[0].iov_len = (int)nb_size;
    iovs++;

    // chunk header eof.
    iovs[0].iov_base = (char*)SRS_HTTP_CRLF;
    iovs[0].iov_len = 2;
    iovs++;

    // chunk body.
    for (int i = 0; i < iovcnt; i++) {
        iovec* data_iov = iov + i;
        iovs[0].iov_base = (char*)data_iov->iov_base;
        iovs[0].iov_len = (int)data_iov->iov_len;
        iovs++;
    }

    // chunk body eof.
    iovs[0].iov_base = (char*)SRS_HTTP_CRLF;
    iovs[0].iov_len = 2;
    iovs++;

    // sendout all ioves.
    ssize_t nwrite;
    if ((ret = srs_write_large_iovs(skt, iovss, nb_iovss, &nwrite)) != ERROR_SUCCESS) {
        return ret;
    }

    if (pnwrite) {
        *pnwrite = nwrite;
    }

    return ret;
}

void SrsHttpResponseWriter::write_header(int code)
{
    if (header_wrote) {
        srs_warn("http: multiple write_header calls, code=%d", code);
        return;
    }

    header_wrote = true;
    status = code;

    // parse the content length from header.
    content_length = hdr->content_length();
}

int SrsHttpResponseWriter::send_header(char* data, int size)
{
    int ret = ERROR_SUCCESS;

    if (header_sent) {
        return ret;
    }
    header_sent = true;

    std::stringstream ss;

    // status_line
    ss << "HTTP/1.1 " << status << " "
        << srs_generate_http_status_text(status) << SRS_HTTP_CRLF;

    // detect content type
    if (srs_go_http_body_allowd(status)) {
        if (hdr->content_type().empty()) {
            hdr->set_content_type(srs_go_http_detect(data, size));
        }
    }

    // set server if not set.
    if (hdr->get("Server").empty()) {
        hdr->set("Server", RTMP_SIG_SRS_SERVER);
    }

    // chunked encoding
    if (content_length == -1) {
        hdr->set("Transfer-Encoding", "chunked");
    }

    // keep alive to make vlc happy.
    hdr->set("Connection", "Keep-Alive");

    // write headers
    hdr->write(ss);

    // header_eof
    ss << SRS_HTTP_CRLF;

    std::string buf = ss.str();
    return skt->write((void*)buf.c_str(), buf.length(), NULL);
}

SrsHttpResponseReader::SrsHttpResponseReader(SrsHttpMessage* msg, SrsStSocket* io)
{
    skt = io;
    owner = msg;
    is_eof = false;
    nb_total_read = 0;
    nb_left_chunk = 0;
    buffer = NULL;
}

SrsHttpResponseReader::~SrsHttpResponseReader()
{
}

int SrsHttpResponseReader::initialize(SrsFastBuffer* body)
{
    int ret = ERROR_SUCCESS;

    nb_chunk = 0;
    nb_left_chunk = 0;
    nb_total_read = 0;
    buffer = body;

    return ret;
}

bool SrsHttpResponseReader::eof()
{
    return is_eof;
}

int SrsHttpResponseReader::read(char* data, int nb_data, int* nb_read)
{
    int ret = ERROR_SUCCESS;

    if (is_eof) {
        ret = ERROR_HTTP_RESPONSE_EOF;
        srs_error("http: response EOF. ret=%d", ret);
        return ret;
    }

    // chunked encoding.
    if (owner->is_chunked()) {
        return read_chunked(data, nb_data, nb_read);
    }

    // read by specified content-length
    if (owner->content_length() != -1) {
        int max = (int)owner->content_length() - (int)nb_total_read;
        if (max <= 0) {
            is_eof = true;
            return ret;
        }

        // change the max to read.
        nb_data = srs_min(nb_data, max);
        return read_specified(data, nb_data, nb_read);
    }

    // infinite chunked mode, directly read.
    if (owner->is_infinite_chunked()) {
        srs_assert(!owner->is_chunked() && owner->content_length() == -1);
        return read_specified(data, nb_data, nb_read);
    }

    // infinite chunked mode, but user not set it,
    // we think there is no data left.
    is_eof = true;

    return ret;
}

int SrsHttpResponseReader::read_chunked(char* data, int nb_data, int* nb_read)
{
    int ret = ERROR_SUCCESS;

    // when no bytes left in chunk,
    // parse the chunk length first.
    if (nb_left_chunk <= 0) {
        char* at = NULL;
        int length = 0;
        while (!at) {
            // find the CRLF of chunk header end.
            char* start = buffer->bytes();
            char* end = start + buffer->size();
            for (char* p = start; p < end - 1; p++) {
                if (p[0] == SRS_HTTP_CR && p[1] == SRS_HTTP_LF) {
                    // invalid chunk, ignore.
                    if (p == start) {
                        ret = ERROR_HTTP_INVALID_CHUNK_HEADER;
                        srs_error("chunk header start with CRLF. ret=%d", ret);
                        return ret;
                    }
                    length = (int)(p - start + 2);
                    at = buffer->read_slice(length);
                    break;
                }
            }

            // got at, ok.
            if (at) {
                break;
            }

            // when empty, only grow 1bytes, but the buffer will cache more.
            if ((ret = buffer->grow(skt, buffer->size() + 1)) != ERROR_SUCCESS) {
                if (!srs_is_client_gracefully_close(ret)) {
                    srs_error("read body from server failed. ret=%d", ret);
                }
                return ret;
            }
        }
        srs_assert(length >= 3);

        // it's ok to set the pos and pos+1 to NULL.
        at[length - 1] = 0;
        at[length - 2] = 0;

        // size is the bytes size, excludes the chunk header and end CRLF.
        int ilength = (int)::strtol(at, NULL, 16);
        if (ilength < 0) {
            ret = ERROR_HTTP_INVALID_CHUNK_HEADER;
            srs_error("chunk header negative, length=%d. ret=%d", ilength, ret);
            return ret;
        }

        // all bytes in chunk is left now.
        nb_chunk = nb_left_chunk = ilength;
    }

    if (nb_chunk <= 0) {
        // for the last chunk, eof.
        is_eof = true;
    } else {
        // for not the last chunk, there must always exists bytes.
        // left bytes in chunk, read some.
        srs_assert(nb_left_chunk);

        int nb_bytes = srs_min(nb_left_chunk, nb_data);
        ret = read_specified(data, nb_bytes, &nb_bytes);

        // the nb_bytes used for output already read size of bytes.
        if (nb_read) {
            *nb_read = nb_bytes;
        }
        nb_left_chunk -= nb_bytes;
        srs_info("http: read %d bytes of chunk", nb_bytes);

        // error or still left bytes in chunk, ignore and read in future.
        if (nb_left_chunk > 0 || (ret != ERROR_SUCCESS)) {
            return ret;
        }
        srs_info("http: read total chunk %dB", nb_chunk);
    }

    // for both the last or not, the CRLF of chunk payload end.
    if ((ret = buffer->grow(skt, 2)) != ERROR_SUCCESS) {
        if (!srs_is_client_gracefully_close(ret)) {
            srs_error("read EOF of chunk from server failed. ret=%d", ret);
        }
        return ret;
    }
    buffer->read_slice(2);

    return ret;
}

int SrsHttpResponseReader::read_specified(char* data, int nb_data, int* nb_read)
{
    int ret = ERROR_SUCCESS;

    if (buffer->size() <= 0) {
        // when empty, only grow 1bytes, but the buffer will cache more.
        if ((ret = buffer->grow(skt, 1)) != ERROR_SUCCESS) {
            if (!srs_is_client_gracefully_close(ret)) {
                srs_error("read body from server failed. ret=%d", ret);
            }
            return ret;
        }
    }

    int nb_bytes = srs_min(nb_data, buffer->size());

    // read data to buffer.
    srs_assert(nb_bytes);
    char* p = buffer->read_slice(nb_bytes);
    memcpy(data, p, nb_bytes);
    if (nb_read) {
        *nb_read = nb_bytes;
    }

    // increase the total read to determine whether EOF.
    nb_total_read += nb_bytes;

    // for not chunked and specified content length.
    if (!owner->is_chunked() && owner->content_length() != -1) {
        // when read completed, eof.
        if (nb_total_read >= (int)owner->content_length()) {
            is_eof = true;
        }
    }

    return ret;
}

SrsHttpMessage::SrsHttpMessage(SrsStSocket* io, SrsConnection* c) : ISrsHttpMessage()
{
    conn = c;
    chunked = false;
    infinite_chunked = false;
    keep_alive = true;
    _uri = new SrsHttpUri();
    _body = new SrsHttpResponseReader(this, io);
    _http_ts_send_buffer = new char[SRS_HTTP_TS_SEND_BUFFER_SIZE];
    jsonp = false;
}

SrsHttpMessage::~SrsHttpMessage()
{
    srs_freep(_body);
    srs_freep(_uri);
    srs_freepa(_http_ts_send_buffer);
}

int SrsHttpMessage::update(string url, http_parser* header, SrsFastBuffer* body, vector<SrsHttpHeaderField>& headers)
{
    int ret = ERROR_SUCCESS;

    _url = url;
    _header = *header;
    _headers = headers;

    // whether chunked.
    std::string transfer_encoding = get_request_header("Transfer-Encoding");
    chunked = (transfer_encoding == "chunked");

    // whether keep alive.
    keep_alive = http_should_keep_alive(header);

    // set the buffer.
    if ((ret = _body->initialize(body)) != ERROR_SUCCESS) {
        return ret;
    }

    // parse uri from url.
    std::string host = get_request_header("Host");

    // use server public ip when no host specified.
    // to make telnet happy.
    if (host.empty()) {
        host= srs_get_public_internet_address();
    }

    // parse uri to schema/server:port/path?query
    std::string uri = "http://" + host + _url;
    if ((ret = _uri->initialize(uri)) != ERROR_SUCCESS) {
        return ret;
    }

    // must format as key=value&...&keyN=valueN
    std::string q = _uri->get_query();
    size_t pos = string::npos;
    while (!q.empty()) {
        std::string k = q;
        if ((pos = q.find("=")) != string::npos) {
            k = q.substr(0, pos);
            q = q.substr(pos + 1);
        } else {
            q = "";
        }

        std::string v = q;
        if ((pos = q.find("&")) != string::npos) {
            v = q.substr(0, pos);
            q = q.substr(pos + 1);
        } else {
            q = "";
        }

        _query[k] = v;
    }

    // parse ext.
    _ext = _uri->get_path();
    if ((pos = _ext.rfind(".")) != string::npos) {
        _ext = _ext.substr(pos);
    } else {
        _ext = "";
    }

    // parse jsonp request message.
    if (!query_get("callback").empty()) {
        jsonp = true;
    }
    if (jsonp) {
        jsonp_method = query_get("method");
    }

    return ret;
}

SrsConnection* SrsHttpMessage::connection()
{
    return conn;
}

u_int8_t SrsHttpMessage::method()
{
    if (jsonp && !jsonp_method.empty()) {
        if (jsonp_method == "GET") {
            return SRS_CONSTS_HTTP_GET;
        } else if (jsonp_method == "PUT") {
            return SRS_CONSTS_HTTP_PUT;
        } else if (jsonp_method == "POST") {
            return SRS_CONSTS_HTTP_POST;
        } else if (jsonp_method == "DELETE") {
            return SRS_CONSTS_HTTP_DELETE;
        }
    }

    return (u_int8_t)_header.method;
}

u_int16_t SrsHttpMessage::status_code()
{
    return (u_int16_t)_header.status_code;
}

string SrsHttpMessage::method_str()
{
    if (jsonp && !jsonp_method.empty()) {
        return jsonp_method;
    }

    if (is_http_get()) {
        return "GET";
    }
    if (is_http_put()) {
        return "PUT";
    }
    if (is_http_post()) {
        return "POST";
    }
    if (is_http_delete()) {
        return "DELETE";
    }
    if (is_http_options()) {
        return "OPTIONS";
    }

    return "OTHER";
}

bool SrsHttpMessage::is_http_get()
{
    return method() == SRS_CONSTS_HTTP_GET;
}

bool SrsHttpMessage::is_http_put()
{
    return method() == SRS_CONSTS_HTTP_PUT;
}

bool SrsHttpMessage::is_http_post()
{
    return method() == SRS_CONSTS_HTTP_POST;
}

bool SrsHttpMessage::is_http_delete()
{
    return method() == SRS_CONSTS_HTTP_DELETE;
}

bool SrsHttpMessage::is_http_options()
{
    return _header.method == SRS_CONSTS_HTTP_OPTIONS;
}

bool SrsHttpMessage::is_chunked()
{
    return chunked;
}

bool SrsHttpMessage::is_keep_alive()
{
    return keep_alive;
}

bool SrsHttpMessage::is_infinite_chunked()
{
    return infinite_chunked;
}

string SrsHttpMessage::uri()
{
    std::string uri = _uri->get_schema();
    if (uri.empty()) {
        uri += "http";
    }
    uri += "://";

    uri += host();
    uri += path();

    return uri;
}

string SrsHttpMessage::url()
{
    return _uri->get_url();
}

string SrsHttpMessage::host()
{
    return _uri->get_host();
}

string SrsHttpMessage::path()
{
    return _uri->get_path();
}

string SrsHttpMessage::query()
{
    return _uri->get_query();
}

string SrsHttpMessage::ext()
{
    return _ext;
}

int SrsHttpMessage::parse_rest_id(string pattern)
{
    string p = _uri->get_path();
    if (p.length() <= pattern.length()) {
        return -1;
    }

    string id = p.substr((int)pattern.length());
    if (!id.empty()) {
        return ::atoi(id.c_str());
    }

    return -1;
}

int SrsHttpMessage::parse_rest_str(std::string pattern, std::string& req)
{
    int ret = ERROR_SUCCESS;

    string p = _uri->get_path();
    if (p.length() <= pattern.length()) {
        return -1;
    }

    req = p.substr((int)(pattern.length() - 1));
    if (req.empty()) {
        return -1;
    }

    return ret;
}

int SrsHttpMessage::enter_infinite_chunked()
{
    int ret = ERROR_SUCCESS;

    if (infinite_chunked) {
        return ret;
    }

    if (is_chunked() || content_length() != -1) {
        ret = ERROR_HTTP_DATA_INVALID;
        srs_error("infinite chunkted not supported in specified codec. ret=%d", ret);
        return ret;
    }

    infinite_chunked = true;

    return ret;
}

int SrsHttpMessage::body_read_all(string& body)
{
    int ret = ERROR_SUCCESS;

    // cache to read.
    char* buf = new char[SRS_HTTP_READ_CACHE_BYTES];
    SrsAutoFreeA(char, buf);

    // whatever, read util EOF.
    while (!_body->eof()) {
        int nb_read = 0;
        if ((ret = _body->read(buf, SRS_HTTP_READ_CACHE_BYTES, &nb_read)) != ERROR_SUCCESS) {
            return ret;
        }

        if (nb_read > 0) {
            body.append(buf, nb_read);
        }
    }

    return ret;
}

ISrsHttpResponseReader* SrsHttpMessage::body_reader()
{
    return _body;
}

int64_t SrsHttpMessage::content_length()
{
    return _header.content_length;
}

string SrsHttpMessage::query_get(string key)
{
    std::string v;

    if (_query.find(key) != _query.end()) {
        v = _query[key];
    }

    return v;
}

int SrsHttpMessage::request_header_count()
{
    return (int)_headers.size();
}

string SrsHttpMessage::request_header_key_at(int index)
{
    srs_assert(index < request_header_count());
    SrsHttpHeaderField item = _headers[index];
    return item.first;
}

string SrsHttpMessage::request_header_value_at(int index)
{
    srs_assert(index < request_header_count());
    SrsHttpHeaderField item = _headers[index];
    return item.second;
}

string SrsHttpMessage::get_request_header(string name)
{
    std::vector<SrsHttpHeaderField>::iterator it;

    for (it = _headers.begin(); it != _headers.end(); ++it) {
        SrsHttpHeaderField& elem = *it;
        std::string key = elem.first;
        std::string value = elem.second;
        if (key == name) {
            return value;
        }
    }

    return "";
}

SrsRequest* SrsHttpMessage::to_request(string vhost)
{
    SrsRequest* req = new SrsRequest();

    req->app = _uri->get_path();
    size_t pos = string::npos;
    if ((pos = req->app.rfind("/")) != string::npos) {
        req->stream = req->app.substr(pos + 1);
        req->app = req->app.substr(0, pos);
    }
    if ((pos = req->stream.rfind(".")) != string::npos) {
        req->stream = req->stream.substr(0, pos);
    }

    req->tcUrl = "rtmp://" + vhost + req->app;
    req->pageUrl = get_request_header("Referer");
    req->objectEncoding = 0;

    srs_discovery_tc_url(req->tcUrl,
                         req->schema, req->host, req->vhost, req->app, req->port,
                         req->param);
    req->strip();

    return req;
}

bool SrsHttpMessage::is_jsonp()
{
    return jsonp;
}

SrsHttpParser::SrsHttpParser()
{
    buffer = new SrsFastBuffer();
}

SrsHttpParser::~SrsHttpParser()
{
    srs_freep(buffer);
}

int SrsHttpParser::initialize(enum http_parser_type type)
{
    int ret = ERROR_SUCCESS;

    memset(&settings, 0, sizeof(settings));
    settings.on_message_begin = on_message_begin;
    settings.on_url = on_url;
    settings.on_header_field = on_header_field;
    settings.on_header_value = on_header_value;
    settings.on_headers_complete = on_headers_complete;
    settings.on_body = on_body;
    settings.on_message_complete = on_message_complete;

    http_parser_init(&parser, type);
    // callback object ptr.
    parser.data = (void*)this;

    return ret;
}

int SrsHttpParser::parse_message(SrsStSocket* skt, SrsConnection* conn, ISrsHttpMessage** ppmsg)
{
    *ppmsg = NULL;

    int ret = ERROR_SUCCESS;

    // reset request data.
    field_name = "";
    field_value = "";
    expect_field_name = true;
    state = SrsHttpParseStateInit;
    header = http_parser();
    url = "";
    headers.clear();
    header_parsed = 0;

    // do parse
    if ((ret = parse_message_imp(skt)) != ERROR_SUCCESS) {
        if (!srs_is_client_gracefully_close(ret)) {
            srs_error("parse http msg failed. ret=%d", ret);
        }
        return ret;
    }

    // create msg
    SrsHttpMessage* msg = new SrsHttpMessage(skt, conn);

    // initalize http msg, parse url.
    if ((ret = msg->update(url, &header, buffer, headers)) != ERROR_SUCCESS) {
        srs_error("initialize http msg failed. ret=%d", ret);
        srs_freep(msg);
        return ret;
    }

    // parse ok, return the msg.
    *ppmsg = msg;

    return ret;
}

int SrsHttpParser::parse_message_imp(SrsStSocket* skt)
{
    int ret = ERROR_SUCCESS;

    while (true) {
        ssize_t nparsed = 0;

        // when got entire http header, parse it.
        // @see https://github.com/ossrs/srs/issues/400
        char* start = buffer->bytes();
        char* end = start + buffer->size();
        for (char* p = start; p <= end - 4; p++) {
            // SRS_HTTP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A
            if (p[0] == SRS_CONSTS_CR && p[1] == SRS_CONSTS_LF && p[2] == SRS_CONSTS_CR && p[3] == SRS_CONSTS_LF) {
                nparsed = http_parser_execute(&parser, &settings, buffer->bytes(), buffer->size());
                srs_info("buffer=%d, nparsed=%d, header=%d", buffer->size(), (int)nparsed, header_parsed);
                break;
            }
        }

        // consume the parsed bytes.
        if (nparsed && header_parsed) {
            buffer->read_slice(header_parsed);
        }

        // ok atleast header completed,
        // never wait for body completed, for maybe chunked.
        if (state == SrsHttpParseStateHeaderComplete || state == SrsHttpParseStateMessageComplete) {
            break;
        }

        // when nothing parsed, read more to parse.
        if (nparsed == 0) {
            // when requires more, only grow 1bytes, but the buffer will cache more.
            if ((ret = buffer->grow(skt, buffer->size() + 1)) != ERROR_SUCCESS) {
                if (!srs_is_client_gracefully_close(ret)) {
                    srs_error("read body from server failed. ret=%d", ret);
                }
                return ret;
            }
        }
    }

    // parse last header.
    if (!field_name.empty() && !field_value.empty()) {
        headers.push_back(std::make_pair(field_name, field_value));
    }

    return ret;
}

int SrsHttpParser::on_message_begin(http_parser* parser)
{
    SrsHttpParser* obj = (SrsHttpParser*)parser->data;
    srs_assert(obj);

    obj->state = SrsHttpParseStateStart;

    srs_info("***MESSAGE BEGIN***");

    return 0;
}

int SrsHttpParser::on_headers_complete(http_parser* parser)
{
    SrsHttpParser* obj = (SrsHttpParser*)parser->data;
    srs_assert(obj);

    obj->header = *parser;
    // save the parser when header parse completed.
    obj->state = SrsHttpParseStateHeaderComplete;
    obj->header_parsed = (int)parser->nread;

    srs_info("***HEADERS COMPLETE***");

    // see http_parser.c:1570, return 1 to skip body.
    return 0;
}

int SrsHttpParser::on_message_complete(http_parser* parser)
{
    SrsHttpParser* obj = (SrsHttpParser*)parser->data;
    srs_assert(obj);

    // save the parser when body parse completed.
    obj->state = SrsHttpParseStateMessageComplete;

    srs_info("***MESSAGE COMPLETE***\n");

    return 0;
}

int SrsHttpParser::on_url(http_parser* parser, const char* at, size_t length)
{
    SrsHttpParser* obj = (SrsHttpParser*)parser->data;
    srs_assert(obj);

    if (length > 0) {
        obj->url.append(at, (int)length);
    }

    srs_info("Method: %d, Url: %.*s", parser->method, (int)length, at);

    return 0;
}

int SrsHttpParser::on_header_field(http_parser* parser, const char* at, size_t length)
{
    SrsHttpParser* obj = (SrsHttpParser*)parser->data;
    srs_assert(obj);

    // field value=>name, reap the field.
    if (!obj->expect_field_name) {
        obj->headers.push_back(std::make_pair(obj->field_name, obj->field_value));

        // reset the field name when parsed.
        obj->field_name = "";
        obj->field_value = "";
    }
    obj->expect_field_name = true;

    if (length > 0) {
        obj->field_name.append(at, (int)length);
    }

    srs_info("Header field(%d bytes): %.*s", (int)length, (int)length, at);
    return 0;
}

int SrsHttpParser::on_header_value(http_parser* parser, const char* at, size_t length)
{
    SrsHttpParser* obj = (SrsHttpParser*)parser->data;
    srs_assert(obj);

    if (length > 0) {
        obj->field_value.append(at, (int)length);
    }
    obj->expect_field_name = false;

    srs_info("Header value(%d bytes): %.*s", (int)length, (int)length, at);
    return 0;
}

int SrsHttpParser::on_body(http_parser* parser, const char* at, size_t length)
{
    SrsHttpParser* obj = (SrsHttpParser*)parser->data;
    srs_assert(obj);

    srs_info("Body: %.*s", (int)length, at);

    return 0;
}

SrsHttpUri::SrsHttpUri()
{
    port = SRS_DEFAULT_HTTP_PORT;
}

SrsHttpUri::~SrsHttpUri()
{
}

int SrsHttpUri::initialize(string _url)
{
    int ret = ERROR_SUCCESS;

    url = _url;
    const char* purl = url.c_str();

    http_parser_url hp_u;
    if((ret = http_parser_parse_url(purl, url.length(), 0, &hp_u)) != 0){
        int code = ret;
        ret = ERROR_HTTP_PARSE_URI;

        srs_error("parse url %s failed, code=%d, ret=%d", purl, code, ret);
        return ret;
    }

    std::string field = get_uri_field(url, &hp_u, UF_SCHEMA);
    if(!field.empty()){
        schema = field;
    }

    host = get_uri_field(url, &hp_u, UF_HOST);

    field = get_uri_field(url, &hp_u, UF_PORT);
    if(!field.empty()){
        port = atoi(field.c_str());
    }

    path = get_uri_field(url, &hp_u, UF_PATH);
    srs_info("parse url %s success", purl);

    query = get_uri_field(url, &hp_u, UF_QUERY);
    srs_info("parse query %s success", query.c_str());

    return ret;
}

const char* SrsHttpUri::get_url()
{
    return url.data();
}

const char* SrsHttpUri::get_schema()
{
    return schema.data();
}

const char* SrsHttpUri::get_host()
{
    return host.data();
}

int SrsHttpUri::get_port()
{
    return port;
}

const char* SrsHttpUri::get_path()
{
    return path.data();
}

const char* SrsHttpUri::get_query()
{
    return query.data();
}

string SrsHttpUri::get_uri_field(string uri, http_parser_url* hp_u, http_parser_url_fields field)
{
    if((hp_u->field_set & (1 << field)) == 0){
        return "";
    }

    srs_verbose("uri field matched, off=%d, len=%d, value=%.*s",
                hp_u->field_data[field].off,
                hp_u->field_data[field].len,
                hp_u->field_data[field].len,
                uri.c_str() + hp_u->field_data[field].off);

    int offset = hp_u->field_data[field].off;
    int len = hp_u->field_data[field].len;

    return uri.substr(offset, len);
}

SrsHttpConn::SrsHttpConn(IConnectionManager* cm, st_netfd_t fd, ISrsHttpServeMux* m)
    : SrsConnection(cm, fd)
{
    parser = new SrsHttpParser();
    http_mux = m;
}

SrsHttpConn::~SrsHttpConn()
{
    srs_freep(parser);
}

void SrsHttpConn::resample()
{
    // TODO: FIXME: implements it
}

int64_t SrsHttpConn::get_send_bytes_delta()
{
    // TODO: FIXME: implements it
    return 0;
}

int64_t SrsHttpConn::get_recv_bytes_delta()
{
    // TODO: FIXME: implements it
    return 0;
}

void SrsHttpConn::cleanup()
{
    // TODO: FIXME: implements it
}

int SrsHttpConn::do_cycle()
{
    int ret = ERROR_SUCCESS;

    srs_trace("HTTP client ip=%s", ip.c_str());

    // initialize parser
    if ((ret = parser->initialize(HTTP_REQUEST)) != ERROR_SUCCESS) {
        srs_error("http initialize http parser failed. ret=%d", ret);
        return ret;
    }

    // underlayer socket
    SrsStSocket skt(stfd);

    // set the recv timeout, for some clients never disconnect the connection.
    // @see https://github.com/ossrs/srs/issues/398
    skt.set_recv_timeout(SRS_HTTP_RECV_TIMEOUT_US);

    // process http messages.
    while (!disposed) {
        ISrsHttpMessage* req = NULL;

        // get a http message
        if ((ret = parser->parse_message(&skt, this, &req)) != ERROR_SUCCESS) {
            return ret;
        }

        // if SUCCESS, always NOT-NULL.
        srs_assert(req);

        // always free it in this scope.
        SrsAutoFree(ISrsHttpMessage, req);

        // may should discard the body.
        if ((ret = on_got_http_message(req)) != ERROR_SUCCESS) {
            return ret;
        }

        // ok, handle http request.
        SrsHttpResponseWriter writer(&skt);
        if ((ret = process_request(&writer, req)) != ERROR_SUCCESS) {
            return ret;
        }

        // donot keep alive, disconnect it.
        // @see https://github.com/ossrs/srs/issues/399
        if (!req->is_keep_alive()) {
            break;
        }
    }

    return ret;
}

int SrsHttpConn::process_request(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
{
    int ret = ERROR_SUCCESS;

    srs_trace("HTTP %s %s, content-length=%"PRId64"",
        r->method_str().c_str(), r->url().c_str(), r->content_length());

    // use default server mux to serve http request.
    if ((ret = http_mux->serve_http(w, r)) != ERROR_SUCCESS) {
        if (!srs_is_client_gracefully_close(ret)) {
            srs_error("serve http msg failed. ret=%d", ret);
        }
        return ret;
    }

    return ret;
}

SrsResponseOnlyHttpConn::SrsResponseOnlyHttpConn(IConnectionManager* cm, st_netfd_t fd, ISrsHttpServeMux* m)
    : SrsHttpConn(cm, fd, m)
{
}

SrsResponseOnlyHttpConn::~SrsResponseOnlyHttpConn()
{
}

int SrsResponseOnlyHttpConn::on_got_http_message(ISrsHttpMessage* msg)
{
    int ret = ERROR_SUCCESS;

    ISrsHttpResponseReader* br = msg->body_reader();

    // drop all request body.
    while (!br->eof()) {
        char body[4096];
        if ((ret = br->read(body, 4096, NULL)) != ERROR_SUCCESS) {
            return ret;
        }
    }

    return ret;
}

SrsHttpServer::SrsHttpServer(SrsServer* svr)
{
    server = svr;
    http_stream = new SrsHttpStreamServer(svr);
    http_static = new SrsHttpStaticServer(svr);
}

SrsHttpServer::~SrsHttpServer()
{
    srs_freep(http_stream);
    srs_freep(http_static);
}

int SrsHttpServer::initialize()
{
    int ret = ERROR_SUCCESS;

#if defined(SRS_AUTO_HTTP_SERVER) && defined(SRS_AUTO_HTTP_API)
    // for SRS go-sharp to detect the status of HTTP server of SRS HTTP FLV Cluster.
    if ((ret = http_static->mux.handle("/api/v1/versions", new SrsGoApiVersion())) != ERROR_SUCCESS) {
        return ret;
    }
#endif

    if ((ret = http_stream->initialize()) != ERROR_SUCCESS) {
        return ret;
    }

    if ((ret = http_static->initialize()) != ERROR_SUCCESS) {
        return ret;
    }

    return ret;
}

int SrsHttpServer::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
{
    // try http stream first.
    if (http_stream->mux.can_serve(r)) {
        return http_stream->mux.serve_http(w, r);
    }

    return http_static->mux.serve_http(w, r);
}

int SrsHttpServer::http_mount(SrsSource* s, SrsRequest* r)
{
    return http_stream->http_mount(s, r);
}

void SrsHttpServer::http_unmount(SrsSource* s, SrsRequest* r)
{
    http_stream->http_unmount(s, r);
}

int SrsHttpServer::mount_hls(SrsRequest* r)
{
    return http_stream->mount_hls(r);
}

int SrsHttpServer::hls_update_m3u8(SrsRequest* r, std::string m3u8)
{
    return http_stream->hls_update_m3u8(r, m3u8);
}

int SrsHttpServer::hls_update_ts(SrsRequest* r, std::string uri, std::string ts)
{
    return http_stream->hls_update_ts(r, uri, ts);
}

int SrsHttpServer::hls_remove_ts(SrsRequest* r, std::string uri)
{
    return http_stream->hls_remove_ts(r, uri);
}

void SrsHttpServer::unmount_hls(SrsRequest* r)
{
    http_stream->unmount_hls(r);
}

#endif


<?php

/**
 * @file
 * Contains \Drupal\user\Plugin\Validation\Constraint\UserNameUnique.
 */

namespace Drupal\user\Plugin\Validation\Constraint;

use Symfony\Component\Validator\Constraint;

/**
 * Checks if a user name is unique on the site.
 *
 * @Constraint(
 *   id = "UserNameUnique",
 *   label = @Translation("User name unique", context = "Validation"),
 * )
 */
class UserNameUnique extends Constraint {

  public $message = 'The username %value is already taken.';

  /**
   * {@inheritdoc}
   */
  public function validatedBy() {
    return '\Drupal\Core\Validation\Plugin\Validation\Constraint\UniqueFieldValueValidator';
  }
}


zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'

# pasting with tabs doesn't perform completion
zstyle ':completion:*' insert-tab pending

# default to file completion
zstyle ':completion:*' completer _expand _complete _files _correct _approximate

# ls colors
zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}


using namespace SEGSEvents;
extern void register_FriendshipServiceEvents();
namespace
{
    const char *event_names[] =
    {
        "FriendConnectedMessage",
        "SendFriendListMessage",
        "SendNotifyFriendMessage",
        "FriendAddedMessage",
        "FriendRemovedMessage",
    };
}

class FriendshipEventRegistry : public QObject
{
    Q_OBJECT
private slots:
    void creationByName()
    {
        for(const char *ev_name : event_names)
        {
            QVERIFY2(create_by_name(ev_name)==nullptr,"no types registered yet, create_by_name result should be null");
        }
        // TODO: call register_all_events();
        register_FriendshipServiceEvents();
        for(const char *ev_name : event_names)
        {
            QVERIFY2(create_by_name(ev_name) != nullptr,
                     qPrintable(QString("all types registered, create_by_name(%1) result should be non-null").arg(ev_name)));
        }
    }
};

QTEST_MAIN(FriendshipEventRegistry)

#include "FriendshipEventRegistry.moc"


@class DVSlideViewController;

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (strong, nonatomic) DVSlideViewController *viewController;

@end


package lifecycle

import (
	"fmt"
	"net"
	"net/http"
	"strconv"

	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/klog"
	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
	kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
	"k8s.io/kubernetes/pkg/kubelet/util/format"
	"k8s.io/kubernetes/pkg/security/apparmor"
	utilio "k8s.io/utils/io"
)

const (
	maxRespBodyLength = 10 * 1 << 10 // 10KB
)

type HandlerRunner struct {
	httpGetter       kubetypes.HttpGetter
	commandRunner    kubecontainer.ContainerCommandRunner
	containerManager podStatusProvider
}

type podStatusProvider interface {
	GetPodStatus(uid types.UID, name, namespace string) (*kubecontainer.PodStatus, error)
}

func NewHandlerRunner(httpGetter kubetypes.HttpGetter, commandRunner kubecontainer.ContainerCommandRunner, containerManager podStatusProvider) kubecontainer.HandlerRunner {
	return &HandlerRunner{
		httpGetter:       httpGetter,
		commandRunner:    commandRunner,
		containerManager: containerManager,
	}
}

func (hr *HandlerRunner) Run(containerID kubecontainer.ContainerID, pod *v1.Pod, container *v1.Container, handler *v1.Handler) (string, error) {
	switch {
	case handler.Exec != nil:
		var msg string
		// TODO(tallclair): Pass a proper timeout value.
		output, err := hr.commandRunner.RunInContainer(containerID, handler.Exec.Command, 0)
		if err != nil {
			msg = fmt.Sprintf("Exec lifecycle hook (%v) for Container %q in Pod %q failed - error: %v, message: %q", handler.Exec.Command, container.Name, format.Pod(pod), err, string(output))
			klog.V(1).Infof(msg)
		}
		return msg, err
	case handler.HTTPGet != nil:
		msg, err := hr.runHTTPHandler(pod, container, handler)
		if err != nil {
			msg = fmt.Sprintf("Http lifecycle hook (%s) for Container %q in Pod %q failed - error: %v, message: %q", handler.HTTPGet.Path, container.Name, format.Pod(pod), err, msg)
			klog.V(1).Infof(msg)
		}
		return msg, err
	default:
		err := fmt.Errorf("Invalid handler: %v", handler)
		msg := fmt.Sprintf("Cannot run handler: %v", err)
		klog.Errorf(msg)
		return msg, err
	}
}

// resolvePort attempts to turn an IntOrString port reference into a concrete port number.
// If portReference has an int value, it is treated as a literal, and simply returns that value.
// If portReference is a string, an attempt is first made to parse it as an integer.  If that fails,
// an attempt is made to find a port with the same name in the container spec.
// If a port with the same name is found, it's ContainerPort value is returned.  If no matching
// port is found, an error is returned.
func resolvePort(portReference intstr.IntOrString, container *v1.Container) (int, error) {
	if portReference.Type == intstr.Int {
		return portReference.IntValue(), nil
	}
	portName := portReference.StrVal
	port, err := strconv.Atoi(portName)
	if err == nil {
		return port, nil
	}
	for _, portSpec := range container.Ports {
		if portSpec.Name == portName {
			return int(portSpec.ContainerPort), nil
		}
	}
	return -1, fmt.Errorf("couldn't find port: %v in %v", portReference, container)
}

func (hr *HandlerRunner) runHTTPHandler(pod *v1.Pod, container *v1.Container, handler *v1.Handler) (string, error) {
	host := handler.HTTPGet.Host
	if len(host) == 0 {
		status, err := hr.containerManager.GetPodStatus(pod.UID, pod.Name, pod.Namespace)
		if err != nil {
			klog.Errorf("Unable to get pod info, event handlers may be invalid.")
			return "", err
		}
		if len(status.IPs) == 0 {
			return "", fmt.Errorf("failed to find networking container: %v", status)
		}
		host = status.IPs[0]
	}
	var port int
	if handler.HTTPGet.Port.Type == intstr.String && len(handler.HTTPGet.Port.StrVal) == 0 {
		port = 80
	} else {
		var err error
		port, err = resolvePort(handler.HTTPGet.Port, container)
		if err != nil {
			return "", err
		}
	}
	url := fmt.Sprintf("http://%s/%s", net.JoinHostPort(host, strconv.Itoa(port)), handler.HTTPGet.Path)
	resp, err := hr.httpGetter.Get(url)
	return getHttpRespBody(resp), err
}

func getHttpRespBody(resp *http.Response) string {
	if resp == nil {
		return ""
	}
	defer resp.Body.Close()
	bytes, err := utilio.ReadAtMost(resp.Body, maxRespBodyLength)
	if err == nil || err == utilio.ErrLimitReached {
		return string(bytes)
	}
	return ""
}

func NewAppArmorAdmitHandler(validator apparmor.Validator) PodAdmitHandler {
	return &appArmorAdmitHandler{
		Validator: validator,
	}
}

type appArmorAdmitHandler struct {
	apparmor.Validator
}

func (a *appArmorAdmitHandler) Admit(attrs *PodAdmitAttributes) PodAdmitResult {
	// If the pod is already running or terminated, no need to recheck AppArmor.
	if attrs.Pod.Status.Phase != v1.PodPending {
		return PodAdmitResult{Admit: true}
	}

	err := a.Validate(attrs.Pod)
	if err == nil {
		return PodAdmitResult{Admit: true}
	}
	return PodAdmitResult{
		Admit:   false,
		Reason:  "AppArmor",
		Message: fmt.Sprintf("Cannot enforce AppArmor: %v", err),
	}
}

func NewNoNewPrivsAdmitHandler(runtime kubecontainer.Runtime) PodAdmitHandler {
	return &noNewPrivsAdmitHandler{
		Runtime: runtime,
	}
}

type noNewPrivsAdmitHandler struct {
	kubecontainer.Runtime
}

func (a *noNewPrivsAdmitHandler) Admit(attrs *PodAdmitAttributes) PodAdmitResult {
	// If the pod is already running or terminated, no need to recheck NoNewPrivs.
	if attrs.Pod.Status.Phase != v1.PodPending {
		return PodAdmitResult{Admit: true}
	}

	// If the containers in a pod do not require no-new-privs, admit it.
	if !noNewPrivsRequired(attrs.Pod) {
		return PodAdmitResult{Admit: true}
	}

	// Always admit runtimes except docker.
	if a.Runtime.Type() != kubetypes.DockerContainerRuntime {
		return PodAdmitResult{Admit: true}
	}

	// Make sure docker api version is valid.
	rversion, err := a.Runtime.APIVersion()
	if err != nil {
		return PodAdmitResult{
			Admit:   false,
			Reason:  "NoNewPrivs",
			Message: fmt.Sprintf("Cannot enforce NoNewPrivs: %v", err),
		}
	}
	v, err := rversion.Compare("1.23.0")
	if err != nil {
		return PodAdmitResult{
			Admit:   false,
			Reason:  "NoNewPrivs",
			Message: fmt.Sprintf("Cannot enforce NoNewPrivs: %v", err),
		}
	}
	// If the version is less than 1.23 it will return -1 above.
	if v == -1 {
		return PodAdmitResult{
			Admit:   false,
			Reason:  "NoNewPrivs",
			Message: fmt.Sprintf("Cannot enforce NoNewPrivs: docker runtime API version %q must be greater than or equal to 1.23", rversion.String()),
		}
	}

	return PodAdmitResult{Admit: true}
}

func noNewPrivsRequired(pod *v1.Pod) bool {
	// Iterate over pod containers and check if we added no-new-privs.
	for _, c := range pod.Spec.Containers {
		if c.SecurityContext != nil && c.SecurityContext.AllowPrivilegeEscalation != nil && !*c.SecurityContext.AllowPrivilegeEscalation {
			return true
		}
	}
	return false
}

func NewProcMountAdmitHandler(runtime kubecontainer.Runtime) PodAdmitHandler {
	return &procMountAdmitHandler{
		Runtime: runtime,
	}
}

type procMountAdmitHandler struct {
	kubecontainer.Runtime
}

func (a *procMountAdmitHandler) Admit(attrs *PodAdmitAttributes) PodAdmitResult {
	// If the pod is already running or terminated, no need to recheck NoNewPrivs.
	if attrs.Pod.Status.Phase != v1.PodPending {
		return PodAdmitResult{Admit: true}
	}

	// If the containers in a pod only need the default ProcMountType, admit it.
	if procMountIsDefault(attrs.Pod) {
		return PodAdmitResult{Admit: true}
	}

	// Always admit runtimes except docker.
	if a.Runtime.Type() != kubetypes.DockerContainerRuntime {
		return PodAdmitResult{Admit: true}
	}

	// Make sure docker api version is valid.
	// Merged in https://github.com/moby/moby/pull/36644
	rversion, err := a.Runtime.APIVersion()
	if err != nil {
		return PodAdmitResult{
			Admit:   false,
			Reason:  "ProcMount",
			Message: fmt.Sprintf("Cannot enforce ProcMount: %v", err),
		}
	}
	v, err := rversion.Compare("1.38.0")
	if err != nil {
		return PodAdmitResult{
			Admit:   false,
			Reason:  "ProcMount",
			Message: fmt.Sprintf("Cannot enforce ProcMount: %v", err),
		}
	}
	// If the version is less than 1.38 it will return -1 above.
	if v == -1 {
		return PodAdmitResult{
			Admit:   false,
			Reason:  "ProcMount",
			Message: fmt.Sprintf("Cannot enforce ProcMount: docker runtime API version %q must be greater than or equal to 1.38", rversion.String()),
		}
	}

	return PodAdmitResult{Admit: true}
}

func procMountIsDefault(pod *v1.Pod) bool {
	// Iterate over pod containers and check if we are using the DefaultProcMountType
	// for all containers.
	for _, c := range pod.Spec.Containers {
		if c.SecurityContext != nil {
			if c.SecurityContext.ProcMount != nil && *c.SecurityContext.ProcMount != v1.DefaultProcMount {
				return false
			}
		}
	}

	return true
}


require "stylesheet_flipper/view_helpers"

module StylesheetFlipper
  class Railtie < Rails::Railtie
    initializer "stylesheet_flipper.view_helpers" do
      ActionView::Base.send :include, StylesheetFlipper::ViewHelpers
    end
    initializer "stylesheet_flipper.initialize_rails", :group => :all do |app|
      app.assets.register_bundle_processor 'text/css', :stylesheet_flipper do |context, data|
        if context.logical_path.include?('-flipped')
          R2.r2 data
        else
          data
        end
      end
    end
  end
end


require 'test_helper'

class EncounterImporterTest < Minitest::Test

  def setup
    collection_fixtures('providers', '_id')
  end

  def test_encounter_importing
    doc = Nokogiri::XML(File.new('test/fixtures/NISTExampleC32.xml'))
    doc.root.add_namespace_definition('cda', 'urn:hl7-org:v3')
    pi = HealthDataStandards::Import::C32::PatientImporter.instance
    patient = pi.parse_c32(doc)

    encounter = patient.encounters[0]
    assert encounter.codes['CPT'].include? '99241'
    assert_equal encounter.performer.title, "Dr."
    assert_equal 'Kildare', encounter.performer.family_name
    assert_equal encounter.facility.name, 'Good Health Clinic'
    assert encounter.reason.codes['SNOMED-CT'].include? '308292007'
    assert_equal encounter.admit_type['code'], 'xyzzy'
    assert_equal encounter.admit_type['codeSystem'], 'CPT'
    assert_equal 'HL7 Healthcare Service Location', encounter.facility.code['codeSystem']
    assert_equal Time.gm(2000, 4, 7).to_i, encounter.facility.start_time
    assert_equal '1117-1', encounter.facility.code['code']
  end
end


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<TITLE>
edu.uci.ics.jung.algorithms.matrix Class Hierarchy (jung2 2.0.1 API)
</TITLE>

<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../../stylesheet.css" TITLE="Style">

      Overview
      Package
      Class
      Use
    Tree
      Deprecated
      Index
      Help

 PREV
 NEXT

  FRAMES
 NO FRAMES

  All Classes

Hierarchy For Package edu.uci.ics.jung.algorithms.matrix

Package Hierarchies:
All Packages

Class Hierarchy

java.lang.Object

edu.uci.ics.jung.algorithms.matrix.GraphMatrixOperations
edu.uci.ics.jung.algorithms.matrix.RealMatrixElementOperations<E> (implements edu.uci.ics.jung.algorithms.matrix.MatrixElementOperations<E>)

Interface Hierarchy

edu.uci.ics.jung.algorithms.matrix.MatrixElementOperations<E>

      Overview
      Package
      Class
      Use
    Tree
      Deprecated
      Index
      Help

 PREV
 NEXT

  FRAMES
 NO FRAMES

  All Classes

Copyright © 2010 null. All Rights Reserved.


<!doctype html>

    <meta charset="UTF-8">
    <link href="https://cdn.bootcss.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet">

window.hdjs = {};
window.hdjs.base = '../';
window.hdjs.uploader = 'php/uploader.php?';
window.hdjs.filesLists = 'php/filesLists.php?';


[![Version](https://img.shields.io/cocoapods/v/SwiftPages.svg?style=flat)](http://cocoapods.org/pods/SwiftPages)
[![License](https://img.shields.io/cocoapods/l/SwiftPages.svg?style=flat)](http://cocoapods.org/pods/SwiftPages)
[![Platform](https://img.shields.io/cocoapods/p/SwiftPages.svg?style=flat)](http://cocoapods.org/pods/SwiftPages)

Features

---

- A simple yet beautifully architected solution for management of paged-style view controllers.
- Dynamic loading of view controllers, allowing handling of high amounts of data without compromising memory.
- Highly customisable, all items have clean API’s to change them to any appearance or size.
- Can be sized and positioned anywhere within a view controller.
- Made for iPhone and iPad.
- Extensively documented code for quick understanding.

Installation

---

### CocoaPods

SwiftPages is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following line to your Podfile:

```ruby
pod "SwiftPages"
```

### Manual

Just Include the SwiftPages.swift file found on the demo in your project, and you’re good to go!

Usage

---

Using **SwiftPages** in your project is very simple and straightforward.

### Create a SwiftPages Instance

First create your SwiftPages instance, there are two ways to do it, as an **IBOoutlet** of a view of type SwiftPages from the storyboard, or programmatically:

**As an IBOoutlet of a view of type SwiftPages from the storyboard**

Place a UIView in your view controller and assign its constraints, make its class be of type SwiftPages. Then control drag to your view controller as an IBOutlet.

**As a fully programmatic SwiftPages view.**

Declare it in the viewDidLoad function of your view controller and set the desired position and size:
```swift
let swiftPagesView : SwiftPages!
swiftPagesView = SwiftPages(frame: CGRectMake(0, 0, self.view.frame.width, self.view.frame.height))
```
Then, after the initialization (described below), add it as a subview on your view controller:
```swift
self.view.addSubview(swiftPagesView)
```

### Initialization
SwiftPages can be initialized in one of two ways:

**Initialize with images as buttons on the top bar:**

First create an array of strings, the strings will be the Storyboard ID's of the view controllers you would like to include:
```swift
var VCIDs : [String] = ["FirstVC", "SecondVC", "ThirdVC", "FourthVC", "FifthVC"]
```
Then create an array of UIImages which will correlate in order to the VC ID's array created above, it also has to have the same number of items as the aforementioned array:
```swift
var buttonImages : [UIImage] = [UIImage(named:"HomeIcon.png")!,
                                        UIImage(named:"LocationIcon.png")!,
                                        UIImage(named:"CollectionIcon.png")!,
                                        UIImage(named:"ListIcon.png")!,
                                        UIImage(named:"StarIcon.png")!]
```
Finally, use the `initializeWithVCIDsArrayAndButtonImagesArray` function with the two arrays created:
```swift
swiftPagesView.initializeWithVCIDsArrayAndButtonImagesArray(VCIDs, buttonImagesArray: buttonImages)
```

**Initialize with text on buttons:**

First, alike with the image initialization, create an array of strings, the strings will be the Storyboard ID's of the view controllers you would like to include:
```swift
var VCIDs : [String] = ["FirstVC", "SecondVC", "ThirdVC", "FourthVC", "FifthVC"]
```
Then create an array of titles which will correlate in order to the VC ID's array created above, it must have the same number of items as the aforementioned array:
```swift
var buttonTitles : [String] = ["Home", "Places", "Photos", "List", "Tags"]
```
Finally, use the `initializeWithVCIDsArrayAndButtonTitlesArray` function with the two arrays created:
```swift
swiftPagesView.initializeWithVCIDsArrayAndButtonTitlesArray(VCIDs, buttonTitlesArray: buttonTitles)
```

Customisation

---

Once you have your `SwiftPages` instance you can customize the appearance of all item's using the class API's, to view the API list look for the `API's` Mark on the SwiftPages class. Below is a brief customization sample:
```swift
swiftPagesView.enableAeroEffectInTopBar(true)
swiftPagesView.setButtonsTextColor(UIColor.whiteColor())
swiftPagesView.setAnimatedBarColor(UIColor.whiteColor())
```

Example

---

You can find a full example on usage and customization on the Xcode project attached to this repository.

License

---

The MIT License (MIT)

**Copyright (c) 2015 Gabriel Alvarado (gabrielle.alva@gmail.com)**

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


import unittest

from webkitpy.common.system.systemhost_mock import MockSystemHost

from webkitpy.layout_tests.port.base import Port
from webkitpy.layout_tests.port.driver import Driver, DriverOutput
from webkitpy.layout_tests.port import browser_test, browser_test_driver
from webkitpy.layout_tests.port.server_process_mock import MockServerProcess

from webkitpy.layout_tests.port.port_testcase import TestWebKitPort

from webkitpy.tool.mocktool import MockOptions

class BrowserTestDriverTest(unittest.TestCase):
    def test_read_stdin_path(self):
        port = TestWebKitPort()
        driver = browser_test_driver.BrowserTestDriver(port, 0, pixel_tests=True)
        driver._server_process = MockServerProcess(lines=[
            'StdinPath: /foo/bar', '#EOF'])
        content_block = driver._read_block(0)
        self.assertEqual(content_block.stdin_path, '/foo/bar')
        driver._stdin_directory = None


<!doctype html>

		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

		<title>Articulating Design Decisions</title>

		<link rel="stylesheet" href="css/reveal.css">
		<link rel="stylesheet" href="css/theme/gaslight.css">

		<link rel="stylesheet" href="lib/css/zenburn.css">

Articulating Design Decisions

							Brought to you by the good designers of Gaslight.

							teamgaslight.com

Table of Contents

 A Maturing Industry

 Great Designers are Great Communicators

 Understanding Relationships

 Reducing Cognitive Load

 Listening Is Understanding

 The Right Frame of Mind

 The Response: Strategy and Tactics

 The Response: Common Messages

 The Ideal Response: Getting Agreement

 Meeting Adjourned: The After-Party

 Recovering from Disaster

 For Nondesigners

 Designing for Vision

Our Goal

Information is freer than ever — but that means that there's more to dig through to find gems

The Design Squad™, in the interest of ongoing education, took on the task of reading and synthesizing content and then bringing it together.

Our Goal

Then obviously we needed to share it with everyone else too.

The Book Selection

Since it's been on the docket for a while and everyone could benefit from amping up their consulting skills, we chose to read Articulating Design Decisions by Tom Greever

Chapter 1

A Maturing Industry

Design: The New Hotness

Design, once seen as niche and auxiliary, has come front-and-center in a world where people use more and more software products and come to expect them to look and work well.

Design: The New Hotness

Good design is very clearly tied to product success.

Design: The New Hotness

It would then follow that designers, those agents of design, would also be the new hotness, right?

Design[ers]: The Reality

UX is a young discipline that's still being figured out.

Designers are practiced in justifying design to designers, less so with those outside the discipline.

Design is as much about subjective personal preferences as it is about logically-made, research-backed decisions.

Chapter 2

Great Designers Are Great Communicators

Everyone's a Critic

Non-Designers are immersed in designed experiences and can tell what looks good, but can't express why.

Design is "special" in that people uninvolved can have an opinion on the "how" of the work, not just the "what".

Design House of Horrors

The CEO Button

Home Page Syndrome

Using Your Words

Most issues are grounded in miscommunication or misunderstandings.

"Most issues" being 99.9% of the problems.

Using Your Words

Words are powerful! They are the tools you use to steer people in the right direction!

The key is to understand what message you want to communicate and the response you want.

Using Your Words

Being able to articulate your design choices gains the trust of your clients and keeps you from getting steamrolled by...

Imparting intelligence.

Demonstrating intentionality.

Showing respect.

Making a Successful Design

A successful design will...

Solve a problem.

Be easy for users.

Be supported by everyone.

Makings of a Successful Design

To find the right solution, you need a clearly defined problem.

Makings of a Successful Design

Set goals and key progress indicators to establish what success looks like. These can be drawn from what's important to your stakeholders.

Makings of a Successful Design

You must be consciously aware of each decision made and why.

Ask "what problem am I trying to solve with this?" and then answer it. Write it down to get in the habit!

Makings of a Successful Design

Practice describing your designs without visual aides to become more precise in how you clarify your designs and thinking.

Makings of a Successful Design

Making sure a design actually resonates with users is grounded in intentionality. "How does this affect the user?"

It's entirely legitimate to make your best guesses and then try them out.

Makings of a Successful Design

Practice writing stories about these design changes within the context of how they affect the user.

Makings of a Successful Design

The most sicknasty design doesn't get you anywhere if you can't sell people on it.

Even worse, people will continue to suggest other alternatives if they're not convinced that you're right.

Makings of a Successful Design

You need to get clients and other team members on your level!

Shared understanding of what you're trying to achieve and where you're headed helps achieve this.

Makings of a Successful Design

To properly share your design savvy with others on your team takes a little additional legwork.

It's easy to land on what looks like the right decision, but leave no stone unturned — finding these other solutions and knowing why they don't work allows you to summon this information later if they're pitched as alternatives.

Makings of a Successful Design

Being right is satisfying, but knowing why and being thoughtful are more important than being able to design the perfect solution every time.

Chapter 3

Understanding Relationships

First, Improving Communication

The single most important thing you can do to improve communication is to improve relationships.

Relationships & Stakeholder

Uxers are so good at putting the user first but often fail to do the same for the stakeholders, the people who have influence over the project.

Applying the same principles we use to put the users first should be applied to the people we work with, that way we can create a better product together

Relationships & Stakeholder

In order to approach them the right way we need to:

See them as human

Create shared experiences

Develop empathy

Ask good questions

Identifying influencers

Building good relationships

See them as human

There are always things that are influencing people’s behaviors that we don’t know about and there will always be things that we simply can’t predict.

See them as human

 A person’s attitudes and responses to your work might have more to do with the things outside of what you’re showing them.

Create shared experiences

When we don’t have anything in common with another person, it’s nearly impossible to talk to them.

Create shared experiences

Finding ways to create connections with other people is an important step toward understanding them.

Connections can be made easily through simple questions (non work questions!).

Develop empathy

Having empathy for stakeholders allows you to understand from their perspective.

Develop empathy

It simply means that your priority for communicating with them has shifted from a position of defense to one of solidarity.

Ask good questions

You should learn to view things from the perspective of your stakeholders in the same way that you would with users of your application

By asking questions.

Identifying Influencers

Every project has a variety of people who influence its outcome, the three main types you need to understand are:

Team Influencers

Executive Influencers

External Influencers

Build Good Relationships

Communication is much easier in good relationships.

Good relationships take work.

Take the time to do the simple things that will help you to improve your relationships and, as a byproduct, your communication with each other

Chapter 4

Reducing Cognitive Load

Reducing Cognitive Load

Reducing the cognitive load not only for the stakeholders but our team and for ourselves so we can have a

Succesful

Productive

Valuable  Meeting

But how??

Remove Distractions!

A lot of people are easily distracted by things that simply do not matter to the goal of the meeting.

Remove Distractions!

Getting to know people can help identify what is distracting to them, so you can remove those things from the conversation.

Anticipate Reactions

When we combine what we know about the infleuncers of the project with the values they carry in their role, we can make some pretty good guesses about how they’ll respond to our designs

Anticipate Reactions

So! Using this information we should curate the flow of our design discussion.

Create a Support Network

Getting other people to support your decisions is about showing that you’re not alone in your ideas.

& Finally

The Dress Rehearsal

Now that you understand your stakeholders, have removed the distractions, anticipated their reactions, and gathered a group of people to back you up, it’s time to:

Make a List

Practice Out loud

Prep Everyone

Now, Let's Have

A Succesful Meeting

Reducing Cognitive Load for us and our Stakeholders allows everyone to focus on the decisions at hand creating more productive conversations.

Productivity Rules!!

 Chapter 5

 Listening is Understanding

 No man ever listened himself out of a job.

 ―Calvin Coolidge

 Implicit Activities

						 Be empathetic. Hear what your stakeholders are saying and try to understand the meaning of what's being said from their perspective.

 Let them talk

 Hear what isn't being said

 Uncover the real problem

 The art of the pause

 Let them Talk

 Give your stakeholders the space they need to fully describe their ideas.

 Three main benfits:

 They will make themselves more clear

 It gives them confidence that they were understood

 It demonstrates that you value what they're saying

 Trust is Everything

 Showing that you can let someone express their ideas freely will help to build trust.

 They will be more likely to agree with you if you can relate to what they've said.

 Hear What isn't Being Said

						There is subtext to every bit of feedback. The better we can decode these messages, the better we can correct our course of action.

 Uncover the Real Problem

 People naturally jump to solutions. It's our job to identify the problems behind those solutions.

 Ask the 5 Whys

 The Art of the Pause

 The right word may be effective, but no word was ever as effective as a rightly timed pause.

 ―Mark Twain

 The Three Purposes of the Pause

 Give them a chance to expand on, or correct, what they've just said.

 Let their statements sink in. Take a few seconds to check yourself and form an appropiate response.

							Nonverbally communicate that what was just said is worth taking the time to seriously consider and ponder over for a moment.

 Be aware of your body language.

 Explicit Activities

 Verbally demonstrate that you're listening and outwardly show that you're engaged in the conversation

 Take notes

 Ask questions

 Repeat or rephrase what's being said

 Write Everything Down

 You're not going to remember everything that your stakeolders say or suggest—you're just not.

 Notes prevent you from having the same conversation again—create a paper trail.

 Notes free you to focus on being articulate.

 Notes build trust with your stakeholders.

 Notes keep the meeting on track.

 Taking Better Notes

 Your notes should be:

 Accessible - even during the meeting

 Organized - related to UI elements or agenda items

 Specific - who suggested what?

 Definitive - have you reached a decison or is there follow-up work that needs to be done?

 Actionable - if there's no action, it's not useful

 Referenced - add links, URLs, screenshots, ect.

 Forward-looking - make room for follow-up discussions for the next meeting.

 Ask Questions

 So much of listening is just getting the other person to talk.

 Helpful Questions

 What problem are you trying to solve?

 What are the advantages of doing it this way?

 What do you suggest?

 How will this affect our goals?

 Where have you seen this before?

 Repeat or Rephrase

 Without a shared vocabulary, there will inevitably be misunderstanding.

 The begining of wisdom is the definition of terms.

 ―Socrates

 Rephrase:

 Convert "Likes" to "Works"

 Focus on effectiveness

 Ask clarifying questions – "Why don't you think this works?"

 Move from discussing preferences to describing functionality

 Repeat:

 "What I Hear You Saying..."

 Translate what's being said into what will become our common ground.

 Bridge the language gap by showing:

 You're listening to them

 You understand what they said

 You can express their ideas in our own words that are more helpful in the design decision-making process

 Chapter 6

 The Right Frame of Mind

Thank. Repeat. Prepare.

 First learn the meaning of what you say, and then speak.

 ―Epictetus

 Give Up Control

 You're going to need approval from others.

 Don't take feedback personally.

 Your work is not your own—you need help from others.

 Check Your Ego at the Door

 See the value in what the other person is saying.

 You're not the only one with good ideas

 You don't have all the best solutions

 Your way isn't the only way to accomplish the goals

 Check Your Ego at the Door

 Removing your ego makes you less defensive and therefore better prepared to respond appropriately.

 Lead with a YES

 We're all in this together. We're headed towards the same goals and with the same level of passion for the product.

 Be collaborative

 Give ideas permission to succeed, even if they might seem impossible

 Keep the conversation open-ended

 Empower people to share their thoughts, ideas and be part of the solution

 Build trust and confidence with your stakeholders

 Be Charming

 Have confidence

 Just be yourself

 Don't take yourself so seriously

 Orient yourself towards others

 Change Your Vocabulary

							 "You're wrong"

Stay positive and always lead with a "yes"

							 "From a design perspective..."

 "The reason we did it this way..."

							"Like" and "Don't like"

 Focus on what works and doesn't work

							 Too much jargon

 Stay within the vernacular

 Make a Transition

 The response before the response.

 Thank

 Repeat

 Prepare

 Chapter 10

 Meeting Adjourned: The After-Party

 The single biggest problem in communication is the illusion that it has taken place.

 ―George Bernard Shaw

 The time after the meeting is crucial. It's prime time to make sure no disasterous design decisions are made. Some things you'll need to do:

							Stick around and chat with people

							Follow up quickly with your notes

							Apply filters and remove the fluff

							Seek out individuals who can help you

							Make decisions when there is ambiguity

 The Meeting After the Meeting

 The hallway after a meeting is where the real feelings come out.

 The Meeting After the Meeting

 This is the time where decisions can be solidified and people can share their thoughts more openly. Often participants can feel too timid to bring something up in a meeting because they may feel like their opinion isn't as influential or as solid as someone else's. However, they may feel more comfortable opening up after the meeting.

 Follow up Fast

 Recorded follow ups show that you value the people involved, their time, and their ideas.

 Follow up Fast

 The follow up should be written preferably within an hour of the meeting, or at least within a day. It should include:

							A word of thanks to the participants

							A list of what was discussed

							Action items and next steps

 Follow up Fast

 Don't be afraid to delegate what people are doing what tasks. Be specific. Ask direct questions. Keep it brief.

 Apply Filters

 Cut out unnecessary information so the team can stay focused.

 Apply Filters

 Sometimes people bring up ideas just for the sake of innovation instead of concentrating on objectives. Here's how to assess a person with wild ideas:

							What are the person's intentions?

							What is everyone's opinions of the person?

							Do other people agree or disagree?

							Is this person influential enough to matter?

							Is this person likely to bring it up again?

 Apply Filters

 It's not about ignoring people, but learning to discern whether comments do or don't align with the project's objectives.

 Apply Filters

 "If they aren't influential, no one agrees with them, and they aren't likely to bring it up again, it's a safe bet you can just move on and never mention it again."

 Apply Filters

 Incorporating everyone's opinions is a dangerous path. Fine tune your judgement to leave out what clouds the objectives.

 Seek Out Individuals

 Be open to communication after the meeting.

 Seek Out Individuals

 If there's someone you might benefit from talking to, find them immediately after the meeting. The purpose of these conversations is to give people the space to share their unfiltered thoughts outside the pressure of an organized setting.

 Do Something, Even if it's Wrong

 Since many meetings end with ambiguity, it's better to do something rather than nothing.

 Do Something, Even if it's Wrong

 "It's better to do something (even if it's wrong) and give your team the opportunity to speak out for or against your choice rather than deal with stale decisions and a stagnant design process. Sometimes, you just need to decide and tell everyone else what you're going to do and get them to speak up."

 Do Something, Even if it's Wrong

						Take the lead and make some kind of rough draft in order to combat decision paralysis. It'll at least get people's attention.

 Remember these things when the meeting is over:

							The time after the meeting is when you can hear people's unfiltered thoughts

							Follow up quickly in order to communicate urgency, value, and decisiveness

							Filter out unnecessary points from your notes that don't need follow up

							Be open to communicating after the meeting

							The only way to move forward in times of ambiguity is to make some kind of decision, even if it's wrong

 Chapter 11

 Recovering from Disaster

 In every difficult situation is potential value. Believe this; then begin looking for it.

 ―Norman Vincent Peale

						Sometimes, no matter how hard we try, have to roll with design decisions we disagree with.

How is This Possible?

						The first step in addressing disaster is to understand why it happened and how it could have been avoided. A few causes for disaster:

							They have a specific need that isn't being met

							They want to know they're being heard

							There is a misunderstanding

							Your designs are not the best solution

							They are completely unreasonable

How is This Possible?

They have a specific need that isn't being met

						Sometimes one need is there because the stakeholder has another underlying need that isn't being addressed.

How is This Possible?

They want to know they're being heard

						Sometimes clients insist on a change because they don't think they're being heard or valued.

How is This Possible?

There is a misunderstanding

						Miscommunications come often and are a sure-fire way to disaster.

How is This Possible?

Your designs are not the best solution

						Stakeholders are leaders for a reason and know the domain best, so they may be right.

						SIT DOWN, BE HUMBLE

How is This Possible?

They are completely unreasonable

						Usually when we think someone's unreasonable, we just fail to see things from their perspective. However, inherently unreasonable people do exist.

Making Changes You Disagree With

						Some tactics for addressing decisions that you feel might hinder the user experience:

							Make it subtle

							Make it an option

							Carefully consider placement

							The hidden menu

							Plan a space

Making Changes You Disagree With

Make it subtle

						Find a middle ground between what a stakeholder wants and what's cohesive for the UX.

Making Changes You Disagree With

Make it an option

						If it's viable for your product, you could limit it's audience.

Making Changes You Disagree With

Carefully consider placement

						If it's viable for your product, you could limit the amount of views it exists in.

Making Changes You Disagree With

The hidden menu

						Sometimes elements could be carefully tucked away in a less accessible location.

Making Changes You Disagree With

Plan a space

						Plan an area in the layout that could easily accommodate temporary changes.

Making Lemonade

Making Lemonade

						Usually it's not one person's bad idea that will ruin a design. It's often poor execution of that possible bad idea that has the power to actually do damage.

Making Lemonade

						Think of decisions that you disagree with as constraints. Use those constraints to actually improve the product instead of plopping them there exactly as suggested.

 "One person's suggestions is a gold mine of other ideas waiting to be excavated."

Making Lemonade

						Take a seemingly unfortunate decision and dig deeper. Being open to one change may reveal something else.

 "Occasionally, having a stakeholder insist on a change can lead you down a path to improving the app in a way that you never expected, solving problems you might not have uncovered otherwise."

The Bank Account of Trust

							Deposits: When your design is praised

							Withdrawls: When a client disagrees with your design

						Stakeholder relationships depend on this bank account of trust. Learn which battles are worth fighting. You have to constantly balance the needs of users and the requirements of stakeholders.

When You're Wrong

						When you're wrong you can either:

							Own up to your decisions

							Deny the criticism

							Absolve yourself of any involvement

When You're Wrong

							Being wrong can feel like a let down of trust, but it's actually an opportunity to build trust.

							Own up to your mistakes always. Say "I was wrong" and then go fix the problem.

							Communicate a sense of urgency and willingness to go above and beyond when fixing the issue.

							Don't obsess over why it happened. It's not nearly as important as fixing the problem.

When You're Wrong

						How to know when you're wrong:

							The problem still exists

							Users don't get it

							Everyone is against you

Painting a Duck

 Half of the world is composed of people who have something to say and can't, and the other half who have nothing to say and keep on saying it.

 ―Robert Frost

Painting a Duck

						People have the tendency to spend a disproportionate amount of time "bike-shedding," which is the act of wasting time on trivial details instead of more pressing but harder to grasp issues.

Painting a Duck

						Sometimes the solution for a stubborn and unreasonable stakeholder is to "paint a duck," or offer some carefully curated alternatives that you know they won't pick, just to point them in the right direction and focus them on the objectives of the project.

Managing Expectations

 "Your ability to properly set, adjust, and communicate expectations is more important than your ability to crank out killer designs on a daily basis."

Managing Expectations

						Often projects fail because expectations weren't clearly communicated, not because of a lack of quality of work.

Managing Expectations

						Without the support of your team, you won't succeed.

Managing Expectations

 "The way you communicate with and manage relationships with stakeholders is critical to your success as a designer."

 Chapter 12

 For the Non-Designers

 What we do see depends mainly on what we look for ... In the same field the farmer will notice the crop, the geologists the fossils, botanists the flowers, artists the colouring, sportsmen the cover for the game. Though we may all look at the same things, it does not all follow that we should see them.

 ―Sir John Lubbock

 There are non-designers who are interested in learning to talk about design. They value good working relationships and realize that clear communication is key, because miscommunication can lead to

			missed expectations, which lead to

			disappointment and distrust.

 Ten Tips for Working with Designers

 Focus on what works

 Don't provide solutions

 Ask lots of questions

 Don't claim to be the user

 Let us explain our decisions

 Ten Tips for Working with Designers

 Empower us to make decisions

 Use helpful language

 Ask if there is data

 Be prepared

 Give us what we need to be successful

 Design Project Checklist

 Shared understanding is vital to the success of a project. Areas to focus on include:

 Management, vision and goals

 Users or customers

 Workflow and communication

 Access to information and people

 Design and technical requirements

 A Seat at the Table

 Design is becoming increasingly more valued

 The most successful products are ones that are well designed and provide a superior UX released by organizations that have design-centric leadership

 Getting there is as simple as building better relationships with your designers and empowering them to make decisions

 Chapter 13

 Designing for Vision

 An artist is not paid for his labor but for his vision.

 ―James McNeill Whistler

 Recognizing Our Power

 Recognizing Our Power

 Images make the unreal real

 Having the skills to think and execute visually gets decision makers excited about our ideas

			Designing for vision gives us a creative outlet

			It creates a conversation with other people
		</ class="fragment">

			It brings people together

			It builds credibility

			It lives beyond us

 Practicing Creativity

 Designing for vision requires us to step away from our projects and dream a little

 Find inspiration creating something new requires inspiration, and it's all around us

 See UX everywhere allow the UX of non-digital things to inform your designs

 Use a different canvas find something that allows you to create without worrying about delivering

 Ideate and iterate force yourself to think of different ideas and then refine them

 Making it Happen

 Designing for vision isn't usually part of our job description, so finding the value in it is often hard

 Making it Happen

 Find a different routine

 It's important to find different time, space, activity and materials to help you relax, free your mind and create.

 Making Stuff Up

 Making Stuff Up

 When it comes down to it, designing for vision is about making things up, expressing them in a tangible way and using visuals to create excitement about the future

 Don't limit yourself

 Start from scratch

 Don't obsess over the details

 Make lots of different versions

 Making Stuff Up

 Even if our ideas fall flat, they still create value for us, as designers, in learning to communicate about design and build momentum to be successful

 Taking Your Ideas to the Right People

 Relationships are everything; invest in them

 More Than Pixels

 Talking about our design is hard because it is an extension of our experiences, regardless of how hard we try to remove ourselves

 Your designs do not speak for themselves

 Design is always changing, but being a better communicator is something that we can always have.

Questions?

						teamgaslight.com


//-----------------------------------------------------------------------
// <copyright file="ExportCreativeActivityFixture.cs" company="Rare Crowds Inc">
// Copyright 2012-2013 Rare Crowds, Inc.
//
//   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.
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using Activities;
using ActivityTestUtilities;
using ConfigManager;
using DataAccessLayer;
using DeliveryNetworkUtilities;
using EntityTestUtilities;
using EntityUtilities;
using Google.Api.Ads.Common.Util;
using Google.Api.Ads.Dfp.Lib;
using GoogleDfpActivities;
using GoogleDfpClient;
using GoogleDfpUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
using Rhino.Mocks.Constraints;
using TestUtilities;
using Dfp = Google.Api.Ads.Dfp.v201206;

namespace GoogleDfpIntegrationTests
{
    /// Tests for ExportCreativeActivity
    [TestClass]
    public class ExportCreativeActivityFixture : DfpActivityFixtureBase<ExportCreativeActivity>
    {
        /// Gets the bytes of a 300x250 test GIF
        private byte[] TestImageBytes
        {
            get { return EmbeddedResourceHelper.GetEmbeddedResourceAsByteArray(this.GetType(), "Resources.test.gif"); }
        }

        /// Initialize per-test object(s)/settings
        [TestInitialize]
        public override void TestInitialize()
        {
            base.TestInitialize();
        }

        /// Test exporting an image creative
        [TestMethod]
        public void ExportImageCreative()
        {
            var companyEntity = TestNetwork.AdvertiserCompanyEntity;
            var creativeEntity = this.CreateTestImageAdCreative();
            this.AddEntitiesToMockRepository(companyEntity, creativeEntity);

            var request = new ActivityRequest
            {
                Task = GoogleDfpActivityTasks.ExportCreative,
                Values =
                {
                    { EntityActivityValues.AuthUserId, Guid.NewGuid().ToString("N") },
                    { EntityActivityValues.CompanyEntityId, companyEntity.ExternalEntityId.ToString() },
                    { EntityActivityValues.CreativeEntityId, creativeEntity.ExternalEntityId.ToString() },
                }
            };

            var activity = this.CreateActivity();
            var result = activity.Run(request);

            // Validate result
            ActivityTestHelpers.AssertValidSuccessResult(result);
            ActivityTestHelpers.AssertResultHasValues(
                result,
                EntityActivityValues.CreativeEntityId,
                GoogleDfpActivityValues.CreativeId);

            // Verify creative was created correctly in DFP
            long creativeId;
            Assert.IsTrue(long.TryParse(result.Values[GoogleDfpActivityValues.CreativeId], out creativeId));
            var creative = this.DfpClient.GetCreatives(new[] { creativeId }).FirstOrDefault() as Dfp.ImageCreative;
            Assert.IsNotNull(creative);
            Assert.AreEqual(creativeId, creative.id);
            Assert.AreEqual<string>(creativeEntity.ExternalName, creative.name);
            Assert.AreEqual(TestNetwork.AdvertiserId, creative.advertiserId);
            Assert.IsNotNull(creative.previewUrl);
            Assert.IsFalse(creative.size.isAspectRatio);
            Assert.AreEqual(300, creative.size.width);
            Assert.AreEqual(250, creative.size.height);
            Assert.AreEqual(creativeEntity.GetClickUrl(), creative.destinationUrl);
        }

        /// Test exporting third party tag creative
        [TestMethod]
        [Ignore]
        public void ExportThirdPartyTagCreative()
        {
            Assert.Fail();
        }

        /// Creates a test creative entity for a 300x250 image ad
        /// <returns>The creative entity</returns>
        private CreativeEntity CreateTestImageAdCreative()
        {
            return EntityTestHelpers.CreateTestImageAdCreativeEntity(
                new EntityId(),
                "Test Creative - " + this.UniqueId,
                300,
                250,
                "http://www.rarecrowds.com/",
                this.TestImageBytes);
        }
    }
}


programinit()

#include <testd2.h>
#include <initgeneral.h>

#include <win.h>
#include <gen.h>

function main() {
	printl("testd says 'Hello World!'");
	//CREATE LABELLED COMMON
	mv.labelledcommon[1]=new win_common;

//	perform("initgeneral");
	call initgeneral();
 asm(" int $03");
	win.srcfile="";
	win.datafile="";
	win.orec="";
	win.wlocked="";
	win.reset="";
	win.valid="";

	call testd2();
	return 0;
}

debugprogramexit()


<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>color: Not compatible 👼</title>
    <link rel="shortcut icon" type="image/png" href="../../../../../favicon.png" />
    <link href="../../../../../bootstrap.min.css" rel="stylesheet">
    <link href="../../../../../bootstrap-custom.css" rel="stylesheet">
    <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">

             Coq bench

clean / released

8.8.2 / color - 1.4.0

            « Up

              color

                1.4.0
                Not compatible 👼

📅  (2022-10-08 09:30:10 UTC)

Context

# Packages matching: installed
# Name              # Installed # Synopsis
base-bigarray       base
base-threads        base
base-unix           base
camlp5              7.14        Preprocessor-pretty-printer of OCaml
conf-findutils      1           Virtual package relying on findutils
conf-perl           2           Virtual package relying on perl
coq                 8.8.2       Formal proof management system
num                 1.4         The legacy Num library for arbitrary-precision integer and rational arithmetic
ocaml               4.07.1      The OCaml compiler (virtual package)
ocaml-base-compiler 4.07.1      Official release 4.07.1
ocaml-config        1           OCaml Switch Configuration
ocamlfind           1.9.5       A library manager for OCaml
# opam file:
opam-version: "2.0"
maintainer: "frederic.blanqui@inria.fr"
authors: [
  "Frédéric Blanqui"
  "Adam Koprowski"
  "Sébastien Hinderer"
  "Pierre-Yves Strub"
  "Sidi Ould Biha"
  "Solange Coupet-Grimal"
  "William Delobel"
  "Hans Zantema"
  "Stéphane Leroux"
  "Léo Ducas"
  "Johannes Waldmann"
  "Qiand Wang"
  "Lianyi Zhang"
  "Sorin Stratulat"
]
license: "CeCILL"
homepage: "http://color.inria.fr/"
bug-reports: "color@inria.fr"
build: [
  [make "-j%{jobs}%"]
]
install: [make "-f" "Makefile.coq" "install"]
depends: [
  "ocaml"
  "coq" {>= "8.7" & < "8.8~"}
  "coq-bignums" {>= "8.7" & < "8.8~"}
]
tags: [
  "date:2017-11-10"
  "logpath:CoLoR"
  "category:Computer Science/Algorithms/Correctness proofs of algorithms"
  "category:Computer Science/Data Types and Data Structures"
  "category:Computer Science/Lambda Calculi"
  "category:Mathematics/Algebra"
  "category:Mathematics/Combinatorics and Graph Theory"
  "category:Mathematics/Logic/Type theory"
  "category:Miscellaneous/Extracted Programs/Type checking unification and normalization"
  "keyword:rewriting"
  "keyword:termination"
  "keyword:lambda calculus"
  "keyword:list"
  "keyword:multiset"
  "keyword:polynomial"
  "keyword:vectors"
  "keyword:matrices"
  "keyword:FSet"
  "keyword:FMap"
  "keyword:term"
  "keyword:context"
  "keyword:substitution"
  "keyword:universal algebra"
  "keyword:varyadic term"
  "keyword:string"
  "keyword:alpha-equivalence"
  "keyword:de Bruijn indices"
  "keyword:simple types"
  "keyword:matching"
  "keyword:unification"
  "keyword:relation"
  "keyword:ordering"
  "keyword:quasi-ordering"
  "keyword:lexicographic ordering"
  "keyword:ring"
  "keyword:semiring"
  "keyword:well-foundedness"
  "keyword:noetherian"
  "keyword:finitely branching"
  "keyword:dependent choice"
  "keyword:infinite sequences"
  "keyword:non-termination"
  "keyword:loop"
  "keyword:graph"
  "keyword:path"
  "keyword:transitive closure"
  "keyword:strongly connected component"
  "keyword:topological ordering"
  "keyword:rpo"
  "keyword:horpo"
  "keyword:dependency pair"
  "keyword:dependency graph"
  "keyword:semantic labeling"
  "keyword:reducibility"
  "keyword:Girard"
  "keyword:fixpoint theorem"
  "keyword:Tarski"
  "keyword:pigeon-hole principle"
  "keyword:Ramsey theorem"
]
synopsis: "A library on rewriting theory and termination"
url {
  src: "http://files.inria.fr/blanqui/color/color.1.4.0.tar.gz"
  checksum: "md5=012e9be1fee95f5bea00cd91133302c1"
}

Lint

Command

true

Return code

0

Dry install 🏜

Dry install with the current Coq version:

Command

opam install -y --show-action coq-color.1.4.0 coq.8.8.2

Return code

5120

Output

[NOTE] Package coq is already installed (current version is 8.8.2).
The following dependencies couldn't be met:
  - coq-color -> coq < 8.8~ -> ocaml < 4.06.0
      base of this switch (use `--unlock-base' to force)
Your request can't be satisfied:
  - No available version of coq satisfies the constraints
No solution found, exiting

Dry install without Coq/switch base, to test if the problem was incompatibility with the current Coq/OCaml version:

Command

opam remove -y coq; opam install -y --show-action --unlock-base coq-color.1.4.0

Return code

0

Install dependencies

Command

true

Return code

0

Duration

0 s

Install 🚀

Command

true

Return code

0

Duration

0 s

Installation size

No files were installed.

Uninstall 🧹

Command

true

Return code

0

Missing removes

                none

Wrong removes

                none

          Sources are on GitHub © Guillaume Claret 🐣


<?php

namespace Mr\ChatBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class MrChatBundle extends Bundle
{
}


require 'spec_helper'

describe "Product Taxons", :type => :feature do
  stub_authorization!

  after do
    Capybara.ignore_hidden_elements = true
  end

  before do
    Capybara.ignore_hidden_elements = false
  end

  context "managing taxons" do
    def selected_taxons
      find("#product_taxon_ids").value.split(',').map(&:to_i).uniq
    end

    it "should allow an admin to manage taxons", :js => true do
      taxon_1 = create(:taxon)
      taxon_2 = create(:taxon, :name => 'Clothing')
      product = create(:product)
      product.taxons << taxon_1

      visit spree.admin_path
      click_link "Products"
      within("table.index") do
        click_icon :edit
      end

      expect(find(".select2-search-choice").text).to eq(taxon_1.name)
      expect(selected_taxons).to match_array([taxon_1.id])

      select2_search "Clothing", :from => "Taxons"
      click_button "Update"
      expect(selected_taxons).to match_array([taxon_1.id, taxon_2.id])

      # Regression test for #2139
      sleep(1)
      expect(first(".select2-search-choice", text: taxon_1.name)).to be_present
      expect(first(".select2-search-choice", text: taxon_2.name)).to be_present
    end
  end
end


package internal

import (
	"strconv"

	"github.com/kataras/iris/v12/context"

	"golang.org/x/text/feature/plural"
	"golang.org/x/text/message"
	"golang.org/x/text/message/catalog"
)

// PluralCounter if completes by an input argument of a message to render,
// then the plural renderer will resolve the plural count
// and any variables' counts. This is useful when the data is not a type of Map or integers.
type PluralCounter interface {
	// PluralCount returns the plural count of the message.
	// If returns -1 then this is not a valid plural message.
	PluralCount() int
	// VarCount should return the variable count, based on the variable name.
	VarCount(name string) int
}

// PluralMessage holds the registered Form and the corresponding Renderer.
// It is used on the `Message.AddPlural` method.
type PluralMessage struct {
	Form     PluralForm
	Renderer Renderer
}

type independentPluralRenderer struct {
	key     string
	printer *message.Printer
}

func newIndependentPluralRenderer(c *Catalog, loc *Locale, key string, msgs ...catalog.Message) (Renderer, error) {
	builder := catalog.NewBuilder(catalog.Fallback(c.Locales[0].tag))
	if err := builder.Set(loc.tag, key, msgs...); err != nil {
		return nil, err
	}
	printer := message.NewPrinter(loc.tag, message.Catalog(builder))
	return &independentPluralRenderer{key, printer}, nil
}

func (m *independentPluralRenderer) Render(args ...interface{}) (string, error) {
	return m.printer.Sprintf(m.key, args...), nil
}

// A PluralFormDecoder should report and return whether
// a specific "key" is a plural one. This function
// can be implemented and set on the `Options` to customize
// the plural forms and their behavior in general.
//
// See the `DefaultPluralFormDecoder` package-level
// variable for the default implementation one.
type PluralFormDecoder func(loc context.Locale, key string) (PluralForm, bool)

// DefaultPluralFormDecoder is the default `PluralFormDecoder`.
// Supprots "zero", "one", "two", "other", "=x", "<x", ">x".
var DefaultPluralFormDecoder = func(_ context.Locale, key string) (PluralForm, bool) {
	if isDefaultPluralForm(key) {
		return pluralForm(key), true
	}

	return nil, false
}

func isDefaultPluralForm(s string) bool {
	switch s {
	case "zero", "one", "two", "other":
		return true
	default:
		if len(s) > 1 {
			ch := s[0]
			if ch == '=' || ch == '<' || ch == '>' {
				if isDigit(s[1]) {
					return true
				}
			}
		}

		return false
	}
}

// A PluralForm is responsible to decode
// locale keys to plural forms and match plural forms
// based on the given pluralCount.
//
// See `pluralForm` package-level type for a default implementation.
type PluralForm interface {
	String() string
	// the string is a verified plural case's raw string value.
	// Field for priority on which order to register the plural cases.
	Less(next PluralForm) bool
	MatchPlural(pluralCount int) bool
}

type pluralForm string

func (f pluralForm) String() string {
	return string(f)
}

func (f pluralForm) Less(next PluralForm) bool {
	form1 := f.String()
	form2 := next.String()

	// Order by
	// - equals,
	// - less than
	// - greater than
	// - "zero", "one", "two"
	// - rest is last "other".
	dig1, typ1, hasDig1 := formAtoi(form1)
	if typ1 == eq {
		return true
	}

	dig2, typ2, hasDig2 := formAtoi(form2)
	if typ2 == eq {
		return false
	}

	// digits smaller, number.
	if hasDig1 {
		return !hasDig2 || dig1 < dig2
	}

	if hasDig2 {
		return false
	}

	if form1 == "other" {
		return false // other go to last.
	}

	if form2 == "other" {
		return true
	}

	if form1 == "zero" {
		return true
	}

	if form2 == "zero" {
		return false
	}

	if form1 == "one" {
		return true
	}

	if form2 == "one" {
		return false
	}

	if form1 == "two" {
		return true
	}

	if form2 == "two" {
		return false
	}

	return false
}

func (f pluralForm) MatchPlural(pluralCount int) bool {
	switch f {
	case "other":
		return true
	case "=0", "zero":
		return pluralCount == 0
	case "=1", "one":
		return pluralCount == 1
	case "=2", "two":
		return pluralCount == 2
	default:
		// <5 or =5

		n, typ, ok := formAtoi(string(f))
		if !ok {
			return false
		}

		switch typ {
		case eq:
			return n == pluralCount
		case lt:
			return pluralCount < n
		case gt:
			return pluralCount > n
		default:
			return false
		}
	}
}

func makeSelectfVars(text string, vars []Var, insidePlural bool) ([]catalog.Message, []Var) {
	newVars := sortVars(text, vars)
	newVars = removeVarsDuplicates(newVars)
	msgs := selectfVars(newVars, insidePlural)
	return msgs, newVars
}

func selectfVars(vars []Var, insidePlural bool) []catalog.Message {
	msgs := make([]catalog.Message, 0, len(vars))
	for _, variable := range vars {
		argth := variable.Argth
		if insidePlural {
			argth++
		}

		msg := catalog.Var(variable.Name, plural.Selectf(argth, variable.Format, variable.Cases...))
		// fmt.Printf("%s:%d | cases | %#+v\n", variable.Name, variable.Argth, variable.Cases)
		msgs = append(msgs, msg)
	}

	return msgs
}

const (
	eq uint8 = iota + 1
	lt
	gt
)

func formType(ch byte) uint8 {
	switch ch {
	case '=':
		return eq
	case '<':
		return lt
	case '>':
		return gt
	}

	return 0
}

func formAtoi(form string) (int, uint8, bool) {
	if len(form) < 2 {
		return -1, 0, false
	}

	typ := formType(form[0])
	if typ == 0 {
		return -1, 0, false
	}

	dig, err := strconv.Atoi(form[1:])
	if err != nil {
		return -1, 0, false
	}
	return dig, typ, true
}

func isDigit(ch byte) bool {
	return '0' <= ch && ch <= '9'
}


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
	<!-- [concole] -->
	<appender name="myConsole" class="org.apache.log4j.ConsoleAppender">
		<param name="encoding" value="GBK" />
		<param name="target" value="System.out" />
		<param name="threshold" value="info" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%-5p %c{2} - %m%n" />
		</layout>
	</appender>

	<!-- [error] -->
	<appender name="ERROR-APPENDER" class="org.apache.log4j.DailyRollingFileAppender">
		<param name="File" value="/data/logs/sqe/error/error.log" />
		<param name="Append" value="true" />
		<param name="encoding" value="GBK" />
		<param name="threshold" value="error" />
		<param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%d %-5p %c{2} - %m%n" />
		</layout>
	</appender>

	<!-- [info] -->
	<appender name="INFO-APPENDER" class="org.apache.log4j.DailyRollingFileAppender">
		<param name="File" value="/data/logs/sqe/info/info.log" />
		<param name="Append" value="true" />
		<param name="encoding" value="GBK" />
		<param name="threshold" value="info" />
		<param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%d %-5p %c{2} - %m%n" />
		</layout>
	</appender>

	<!-- Root Logger -->
	<root>
		<level value="${rootLevel}"></level>
		<appender-ref ref="INFO-APPENDER" />
		<appender-ref ref="myConsole" />
		<appender-ref ref="ERROR-APPENDER" />
	</root>
</log4j:configuration>


/**
 * Prevajalnik za programski jezik PREV.
 * <p>
 * Celotna izvorna koda prevajalnika za programski jezik PREV je zbrana v paketu {@link compiler} in njegovih podpaketih.
 *
 * @author sliva
 */
package compiler;