<commit_before>const selectors = require('../../../../selectors')

describe('Company Collections Filter', () => {
  before(() => {
    cy.visit('/companies?sortby=collectionTest')
    cy.get(selectors.entityCollection.entities)
      .children()
      .should('have.length', 9)
    cy.get(selectors.entityCollection.collection).should(
      'contain',
      '100,172 companies'
    )
  })

  beforeEach(() => {
    cy.server()
    cy.route('/companies?*').as('filterResults')
  })

  it('should filter by name', () => {
    cy.get(selectors.filter.name)
      .type('FilterByCompany')
      .type('{enter}')

    cy.get(selectors.entityCollection.entities)
      .children()
      .should('have.length', 1)
    cy.get(selectors.entityCollection.collection).should(
      'contain',
      '1 company matching FilterByCompany'
    )
    cy.get(selectors.entityCollection.collectionRowMessage).should(
      'contain',
      'You can now download this company'
    )
    cy.get(selectors.entityCollection.collectionRowButton).should('be.visible')
  })

  it('should filter by active status', () => {
    cy.get(selectors.filter.statusActive).click()

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain(
        '?sortby=collectionTest&custom=true&name=FilterByCompany&archived=false'
      )
    })

    cy.get(selectors.entityCollection.entities)
      .children()
      .should('have.length', 1)
  })

  it('should filter by inactive status', () => {
    cy.get(selectors.filter.statusInactive).click()

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain(
        '?sortby=collectionTest&custom=true&name=FilterByCompany&archived=false&archived=true'
      )
    })

    cy.get(selectors.entityCollection.entities)
      .children()
      .should('have.length', 1)
  })

  it('should filter by region', () => {
    cy.get(selectors.filter.firstUkRegion).click()

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain(
        'uk_region=934cd12a-6095-e211-a939-e4115bead28a'
      )
    })

    cy.get(selectors.entityCollection.entities)
      .children()
      .should('have.length', 1)
  })

  it('should filter by last interaction date', () => {
    cy.get(selectors.filter.firstInteractionDate).click()

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain('interaction_between=0')
    })

    cy.get(selectors.entityCollection.entities)
      .children()
      .should('have.length', 1)
  })

  it('should filter by sector', () => {
    const sector = selectors.filter.sector
    const { typeahead } = selectors.filter
    cy.get(typeahead(sector).selectedOption)
      .click()
      .get(typeahead(sector).textInput)
      .type('Advanced Engineering')
      .get(typeahead(sector).options)
      .should('have.length', 1)
      .get(typeahead(sector).textInput)
      .type('{enter}')
      .type('{esc}')

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain(
        'sector_descends=af959812-6095-e211-a939-e4115bead28a'
      )
    })
  })

  it('should filter by country', () => {
    const country = selectors.filter.country
    const { typeahead } = selectors.filter

    cy.get(typeahead(country).selectedOption)
      .click()
      .get(typeahead(country).textInput)
      .type('United Kingdom')
      .get(typeahead(country).options)
      .should('have.length', 1)
      .get(typeahead(country).textInput)
      .type('{enter}')
      .type('{esc}')

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain('country=80756b9a-5d95-e211-a939-e4115bead28a')
    })
  })

  it('should filter by currently exporting to', () => {
    const exportingTo = selectors.filter.exportingTo
    const { typeahead } = selectors.filter

    cy.get(typeahead(exportingTo).selectedOption)
      .click()
      .get(typeahead(exportingTo).textInput)
      .type('Australia')
      .get(typeahead(exportingTo).options)
      .should('have.length', 1)
      .get(typeahead(exportingTo).textInput)
      .type('{enter}')
      .type('{esc}')

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain(
        'export_to_countries=9f5f66a0-5d95-e211-a939-e4115bead28a'
      )
    })
  })

  it('should filter by future countries of interest', () => {
    const interestedIn = selectors.filter.interestedIn
    const { typeahead } = selectors.filter

    cy.get(typeahead(interestedIn).selectedOption)
      .click()
      .get(typeahead(interestedIn).textInput)
      .type('Bahamas')
      .get(typeahead(interestedIn).options)
      .should('have.length', 1)
      .get(typeahead(interestedIn).textInput)
      .type('{enter}')
      .type('{esc}')

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain(
        'future_interest_countries=a25f66a0-5d95-e211-a939-e4115bead28a'
      )
    })
  })

  it('should remove all filters', () => {
    cy.get(selectors.entityCollection.collectionRemoveAllFilter).click()
    cy.get(selectors.entityCollection.collection).should(
      'contain',
      '100,172 companies'
    )
  })

  it('should filter by Lead ITA and Global Account Manager', () => {
    const leadIta = selectors.filter.leadIta
    const { typeahead } = selectors.filter
    cy.get(typeahead(leadIta).selectedOption)
      .click()
      .get(typeahead(leadIta).textInput)
      .type('Shawn Cohen')
      .get(typeahead(leadIta).options)
      .should('have.length', 63)

    cy.get(typeahead(leadIta).selectedOption)
      .type('{enter}')
      .type('{esc}')

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain(
        'one_list_group_global_account_manager=2c42c516-9898-e211-a939-e4115bead28a'
      )
    })
  })
})
<commit_msg>Added functional tests for UK postcode filter<commit_after>const selectors = require('../../../../selectors')

describe('Company Collections Filter', () => {
  before(() => {
    cy.visit('/companies?sortby=collectionTest')
    cy.get(selectors.entityCollection.entities)
      .children()
      .should('have.length', 9)
    cy.get(selectors.entityCollection.collection).should(
      'contain',
      '100,172 companies'
    )
  })

  beforeEach(() => {
    cy.server()
    cy.route('/companies?*').as('filterResults')
  })

  it('should filter by name', () => {
    cy.get(selectors.filter.name)
      .type('FilterByCompany')
      .type('{enter}')

    cy.get(selectors.entityCollection.entities)
      .children()
      .should('have.length', 1)
    cy.get(selectors.entityCollection.collection).should(
      'contain',
      '1 company matching FilterByCompany'
    )
    cy.get(selectors.entityCollection.collectionRowMessage).should(
      'contain',
      'You can now download this company'
    )
    cy.get(selectors.entityCollection.collectionRowButton).should('be.visible')
  })

  it('should filter by active status', () => {
    cy.get(selectors.filter.statusActive).click()

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain(
        '?sortby=collectionTest&custom=true&name=FilterByCompany&archived=false'
      )
    })

    cy.get(selectors.entityCollection.entities)
      .children()
      .should('have.length', 1)
  })

  it('should filter by inactive status', () => {
    cy.get(selectors.filter.statusInactive).click()

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain(
        '?sortby=collectionTest&custom=true&name=FilterByCompany&archived=false&archived=true'
      )
    })

    cy.get(selectors.entityCollection.entities)
      .children()
      .should('have.length', 1)
  })

  it('should filter by region', () => {
    cy.get(selectors.filter.firstUkRegion).click()

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain(
        'uk_region=934cd12a-6095-e211-a939-e4115bead28a'
      )
    })

    cy.get(selectors.entityCollection.entities)
      .children()
      .should('have.length', 1)
  })

  it('should filter by last interaction date', () => {
    cy.get(selectors.filter.firstInteractionDate).click()

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain('interaction_between=0')
    })

    cy.get(selectors.entityCollection.entities)
      .children()
      .should('have.length', 1)
  })

  it('should filter by sector', () => {
    const sector = selectors.filter.sector
    const { typeahead } = selectors.filter
    cy.get(typeahead(sector).selectedOption)
      .click()
      .get(typeahead(sector).textInput)
      .type('Advanced Engineering')
      .get(typeahead(sector).options)
      .should('have.length', 1)
      .get(typeahead(sector).textInput)
      .type('{enter}')
      .type('{esc}')

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain(
        'sector_descends=af959812-6095-e211-a939-e4115bead28a'
      )
    })
  })

  it('should filter by country', () => {
    const country = selectors.filter.country
    const { typeahead } = selectors.filter

    cy.get(typeahead(country).selectedOption)
      .click()
      .get(typeahead(country).textInput)
      .type('United Kingdom')
      .get(typeahead(country).options)
      .should('have.length', 1)
      .get(typeahead(country).textInput)
      .type('{enter}')
      .type('{esc}')

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain('country=80756b9a-5d95-e211-a939-e4115bead28a')
    })
  })

  it('should filter by currently exporting to', () => {
    const exportingTo = selectors.filter.exportingTo
    const { typeahead } = selectors.filter

    cy.get(typeahead(exportingTo).selectedOption)
      .click()
      .get(typeahead(exportingTo).textInput)
      .type('Australia')
      .get(typeahead(exportingTo).options)
      .should('have.length', 1)
      .get(typeahead(exportingTo).textInput)
      .type('{enter}')
      .type('{esc}')

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain(
        'export_to_countries=9f5f66a0-5d95-e211-a939-e4115bead28a'
      )
    })
  })

  it('should filter by future countries of interest', () => {
    const interestedIn = selectors.filter.interestedIn
    const { typeahead } = selectors.filter

    cy.get(typeahead(interestedIn).selectedOption)
      .click()
      .get(typeahead(interestedIn).textInput)
      .type('Bahamas')
      .get(typeahead(interestedIn).options)
      .should('have.length', 1)
      .get(typeahead(interestedIn).textInput)
      .type('{enter}')
      .type('{esc}')

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain(
        'future_interest_countries=a25f66a0-5d95-e211-a939-e4115bead28a'
      )
    })
  })

  it('should remove all filters', () => {
    cy.get(selectors.entityCollection.collectionRemoveAllFilter).click()
    cy.get(selectors.entityCollection.collection).should(
      'contain',
      '100,172 companies'
    )
  })

  it('should filter by Lead ITA and Global Account Manager', () => {
    const leadIta = selectors.filter.leadIta
    const { typeahead } = selectors.filter
    cy.get(typeahead(leadIta).selectedOption)
      .click()
      .get(typeahead(leadIta).textInput)
      .type('Shawn Cohen')
      .get(typeahead(leadIta).options)
      .should('have.length', 63)

    cy.get(typeahead(leadIta).selectedOption)
      .type('{enter}')
      .type('{esc}')

    cy.wait('@filterResults').then((xhr) => {
      expect(xhr.url).to.contain(
        'one_list_group_global_account_manager=2c42c516-9898-e211-a939-e4115bead28a'
      )
    })
  })

  it('should filter by UK postcode', () => {
    const POSTCODE = 'LE12'
    cy.contains('UK postcode')
      .closest('.c-form-group')
      .within(() =>
        cy.get('input')
          .type(POSTCODE)
          .blur()
      )

    cy.wait('@filterResults').then(xhr => {
      expect(xhr.url).to.contain(`uk_postcode=${POSTCODE}`)
    })
  })
})
<|endoftext|>


<commit_before>/*
	curl-to-py
	by Zheuxan Yang
  Modified from https://github.com/mholt/curl-to-go/blob/gh-pages/resources/js/curl-to-go.js

	https://github.com/zheuxany/curl-to-py

	A simple utility to convert curl commands into py code.
*/

function curlToPy(curl) {
    var promo = "// Generated by curl-to-py: https://zhexuany.github.io/curl-to-py";

    // List of curl flags that are boolean typed; this helps with parsing
    // a command like `curl -abc value` to know whether 'value' belongs to '-c'
    // or is just a positional argument instead.
    var boolOptions = ['#', 'progress-bar', '-', 'next', '0', 'http1.0', 'http1.1', 'http2',
        'no-npn', 'no-alpn', '1', 'tlsv1', '2', 'sslv2', '3', 'sslv3', '4', 'ipv4', '6', 'ipv6',
        'a', 'append', 'anyauth', 'B', 'use-ascii', 'basic', 'compressed', 'create-dirs',
        'crlf', 'digest', 'disable-eprt', 'disable-epsv', 'environment', 'cert-status',
        'false-start', 'f', 'fail', 'ftp-create-dirs', 'ftp-pasv', 'ftp-skip-pasv-ip',
        'ftp-pret', 'ftp-ssl-ccc', 'ftp-ssl-control', 'g', 'globoff', 'G', 'get',
        'ignore-content-length', 'i', 'include', 'I', 'head', 'j', 'junk-session-cookies',
        'J', 'remote-header-name', 'k', 'insecure', 'l', 'list-only', 'L', 'location',
        'location-trusted', 'metalink', 'n', 'netrc', 'N', 'no-buffer', 'netrc-file',
        'netrc-optional', 'negotiate', 'no-keepalive', 'no-sessionid', 'ntlm', 'O',
        'remote-name', 'oauth2-bearer', 'p', 'proxy-tunnel', 'path-as-is', 'post301', 'post302',
        'post303', 'proxy-anyauth', 'proxy-basic', 'proxy-digest', 'proxy-negotiate',
        'proxy-ntlm', 'q', 'raw', 'remote-name-all', 's', 'silent', 'sasl-ir', 'S', 'show-error',
        'ssl', 'ssl-reqd', 'ssl-allow-beast', 'ssl-no-revoke', 'socks5-gssapi-nec', 'tcp-nodelay',
        'tlsv1.0', 'tlsv1.1', 'tlsv1.2', 'tr-encoding', 'trace-time', 'v', 'verbose', 'xattr',
        'h', 'help', 'M', 'manual', 'V', 'version'
    ];

    if (!curl.trim())
        return "empty input";
    var cmd = parseCommand(curl, {
        boolFlags: boolOptions
    });

    if (cmd._[0] != "curl")
        throw "Not a curl command";

    var req = extractRelevantPieces(cmd);

    if (req.headers.length == 0 && !req.data.ascii && !req.data.files && !req.basicauth) {
        return promo + "\n" + renderSimple(req.method, req.url);
    }
    return promo + "\n\n" + renderComplex(req);

    // renderSimple renders a simple HTTP request using requests convenience methods
    function renderSimple(method, url) {
        if (method == "GET")
            return 'requests.get(' + url + ')\n';
        else if (method == "POST")
            return 'requests.post(' + url + ', data=None)\n';
        else if (method == "HEAD")
            return 'requests.head(' + url + ')\n';
        else
            return 'not supported yet';
    }

    // renderComplex renders py code that requires making a http.Request.
    function renderComplex(req) {
        var py = "";
        headers = "headers = {\n";
        for (var name in req.headers) {
            headers += '    \'' + name + '\': \'' + req.headers[name] + '\',\n';
        }
        headers += "}\n";
        data = "data = data\n";
        return py + "\n" + headers + "\n" + data;
    }

    // getHeaders generate a dict which contains header name and header value
    function getHeaders(cmd) {
        var result = {};
        var colonIndex;
        var header;
        var headerName;
        var headerValue;

        if (cmd.H) {
            for (var i = 0; i < cmd.H.length; i++) {
                header = cmd.H[i];
                console.log(header);
                colonIndex = header.indexOf(':');
                headerName = header.substring(0, colonIndex);
                headerValue = header.substring(colonIndex + 1).trim();
                result[headerName] = headerValue;
            }
        }
        if (cmd.header) {
            for (i = 0; i < cmd.H.length; i++) {
                header = cmd.header[i];
                colonIndex = header.indexOf(':');
                headerName = header.substring(0, colonIndex);
                headerValue = header.substring(colonIndex + 1).trim();
                result[headerName] = headerValue;
            }
        }
        return result;
    }

    // extractRelevantPieces returns an object with relevant pieces
    // extracted from cmd, the parsed command. This accounts for
    // multiple flags that do the same thing and return structured
    // data that makes it easy to spit out py code.
    function extractRelevantPieces(cmd) {
        var relevant = {
            url: "",
            method: "",
            headers: {},
            data: {}
        };

        // prefer --url over unnamed parameter, if it exists; keep first one only
        if (cmd.url && cmd.url.length > 0)
            relevant.url = cmd.url[0];
        else if (cmd._.length > 1)
            relevant.url = cmd._[1]; // position 1 because index 0 is the curl command itself

        // gather the headers together
        relevant.headers = getHeaders(cmd);
        // set method to HEAD?
        if (cmd.I || cmd.head)
            relevant.method = "HEAD";

        // between -X and --request, prefer the long form I guess
        if (cmd.request && cmd.request.length > 0)
            relevant.method = cmd.request[cmd.request.length - 1].toUpperCase();
        else if (cmd.X && cmd.X.length > 0)
            relevant.method = cmd.X[cmd.X.length - 1].toUpperCase(); // if multiple, use last (according to curl docs)

        // join multiple request body data, if any
        var dataAscii = [];
        var dataFiles = [];
        var loadData = function(d) {
            if (!relevant.method)
                relevant.method = "POST";

            // curl adds a default Content-Typ header if not set explicitly
            var hasContentType = false;
            for (var i = 0; i < relevant.headers.length; i++) {
                if (relevant.headers[i].indexOf("Content-Type") == 0) {
                    hasContentType = true;
                    break;
                }
            }
            if (!hasContentType)
                relevant.headers["Content-Type"] = "application/x-www-form-urlencoded";

            for (var i = 0; i < d.length; i++) {
                if (d[i].length > 0 && d[i][0] == "@")
                    dataFiles.push(d[i].substr(1));
                else
                    dataAscii.push(d[i]);
            }
        };
        if (cmd.d)
            loadData(cmd.d);
        if (cmd.data)
            loadData(cmd.data);
        if (dataAscii.length > 0)
            relevant.data.ascii = dataAscii.join("&");
        if (dataFiles.length > 0)
            relevant.data.files = dataFiles;

        // between -u and --user, choose the long form...
        var basicAuthString = "";
        if (cmd.user && cmd.user.length > 0)
            basicAuthString = cmd.user[cmd.user.length - 1];
        else if (cmd.u && cmd.u.length > 0)
            basicAuthString = cmd.u[cmd.u.length - 1];
        var basicAuthSplit = basicAuthString.indexOf(":");
        if (basicAuthSplit > -1) {
            relevant.basicauth = {
                user: basicAuthString.substr(0, basicAuthSplit),
                pass: basicAuthString.substr(basicAuthSplit + 1)
            };
        } else {
            relevant.basicAuth = {
                user: basicAuthString,
                pass: "<PASSWORD>"
            };
        }

        // default to GET if nothing else specified
        if (!relevant.method)
            relevant.method = "GET";

        return relevant;
    }

    function toTitleCase(str) {
        return str.replace(/\w*/g, function(txt) {
            return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
        });
    }
}

function parseCommand(input, options) {
    if (typeof options === 'undefined') {
        options = {};
    }

    var result = {
            _: []
        }, // what we return
        cursor = 0, // iterator position
        token = ""; // current token (word or quoted string) being built

    // trim leading $ or # that may have been left in
    input = input.trim();
    if (input.length > 2 && (input[0] == '$' || input[0] == '#') && whitespace(input[1]))
        input = input.substr(1).trim();

    for (cursor = 0; cursor < input.length; cursor++) {
        skipWhitespace();
        if (input[cursor] == "-") {
            flagSet();
        } else {
            unflagged();
        }
    }

    return result;

    // isLongFalg return true is input length is larger than cursor and
    // come with a dash
    function isLongFalg() {
        return cursor < input.length - 1 && input[cursor + 1] == "-";
    }

    // flagSet handles flags and it assumes the current cursor
    // points to a first dash.
    function flagSet() {
        // long flag form?
        if (isLongFalg()) {
            return longFlag();
        }

        // if not, parse short flag form
        return shortFlag();
    }

    // longFlag consumes a "--long-flag" sequence and
    // stores it in result.
    function longFlag() {
        cursor += 2; // skip leading dashes
        var flagName = nextString("=");
        if (boolFlag(flagName))
            result[flagName] = true;
        else {
            if (typeof result[flagName] == 'undefined') {
                result[flagName] = [];
            }
            if (Array.isArray(result[flagName])) {
                result[flagName].push(nextString());
            }
        }
    }

    function shortFlag() {
        cursor++; // skip leading dash
        while (cursor < input.length && !whitespace(input[cursor])) {
            var flagName = input[cursor];
            if (typeof result[flagName] == 'undefined') {
                result[flagName] = [];
            }
            cursor++; // skip the flag name
            if (boolFlag(flagName))
                result[flagName] = true;
            else if (Array.isArray(result[flagName]))
                result[flagName].push(nextString());
        }
    }

    // unflagged consumes the next string as an unflagged value,
    // storing it in the result.
    function unflagged() {
        result._.push(nextString());
    }

    // boolFlag returns whether a flag is known to be boolean type
    function boolFlag(flag) {
        if (Array.isArray(options.boolFlags)) {
            for (var i = 0; i < options.boolFlags.length; i++) {
                if (options.boolFlags[i] == flag)
                    return true;
            }
        }
        return false;
    }

    // nextString skips any leading whitespace and consumes the next
    // space-delimited string value and returns it. If endChar is set,
    // it will be used to determine the end of the string. Normally just
    // unescaped whitespace is the end of the string, but endChar can
    // be used to specify another end-of-string. This function honors \
    // as an escape character and does not include it in the value, except
    // in the special case of the \$ sequence, the backslash is retained
    // so other code can decide whether to treat as an env var or not.
    function nextString(endChar) {
        skipWhitespace();

        var str = "";

        var quoted = false,
            quoteCh = "",
            escaped = false;

        for (; cursor < input.length; cursor++) {
            if (quoted) {
                if (input[cursor] == quoteCh && !escaped) {
                    quoted = false;
                    continue;
                }
            }
            if (!quoted) {
                if (!escaped) {
                    if (whitespace(input[cursor])) {
                        return str;
                    }
                    if (input[cursor] == '"' || input[cursor] == "'") {
                        quoted = true;
                        quoteCh = input[cursor];
                        cursor++;
                    }
                    if (endChar && input[cursor] == endChar) {
                        cursor++; // skip the endChar
                        return str;
                    }
                }
            }
            if (!escaped && input[cursor] == "\\") {
                escaped = true;
                // skip the backslash unless the next character is $
                if (!(cursor < input.length - 1 && input[cursor + 1] == '$'))
                    continue;
            }

            str += input[cursor];
            escaped = false;
        }

        return str;
    }

    // skipWhitespace skips whitespace between tokens, taking into account escaped whitespace.
    function skipWhitespace() {
        for (; cursor < input.length; cursor++) {
            while (input[cursor] == "\\" && (cursor < input.length - 1 && whitespace(input[cursor + 1])))
                cursor++;
            if (!whitespace(input[cursor]))
                break;
        }
    }

    // whitespace returns true if ch is a whitespace character.
    function whitespace(ch) {
        return ch == " " || ch == "\t" || ch == "\n" || ch == "\r";
    }
}
<commit_msg>fixed adding default header if there is not any<commit_after>/*
	curl-to-py
	by Zheuxan Yang
  Modified from https://github.com/mholt/curl-to-go/blob/gh-pages/resources/js/curl-to-go.js

	https://github.com/zheuxany/curl-to-py

	A simple utility to convert curl commands into py code.
*/

function curlToPy(curl) {
    var promo = "// Generated by curl-to-py: https://zhexuany.github.io/curl-to-py";

    // List of curl flags that are boolean typed; this helps with parsing
    // a command like `curl -abc value` to know whether 'value' belongs to '-c'
    // or is just a positional argument instead.
    var boolOptions = ['#', 'progress-bar', '-', 'next', '0', 'http1.0', 'http1.1', 'http2',
        'no-npn', 'no-alpn', '1', 'tlsv1', '2', 'sslv2', '3', 'sslv3', '4', 'ipv4', '6', 'ipv6',
        'a', 'append', 'anyauth', 'B', 'use-ascii', 'basic', 'compressed', 'create-dirs',
        'crlf', 'digest', 'disable-eprt', 'disable-epsv', 'environment', 'cert-status',
        'false-start', 'f', 'fail', 'ftp-create-dirs', 'ftp-pasv', 'ftp-skip-pasv-ip',
        'ftp-pret', 'ftp-ssl-ccc', 'ftp-ssl-control', 'g', 'globoff', 'G', 'get',
        'ignore-content-length', 'i', 'include', 'I', 'head', 'j', 'junk-session-cookies',
        'J', 'remote-header-name', 'k', 'insecure', 'l', 'list-only', 'L', 'location',
        'location-trusted', 'metalink', 'n', 'netrc', 'N', 'no-buffer', 'netrc-file',
        'netrc-optional', 'negotiate', 'no-keepalive', 'no-sessionid', 'ntlm', 'O',
        'remote-name', 'oauth2-bearer', 'p', 'proxy-tunnel', 'path-as-is', 'post301', 'post302',
        'post303', 'proxy-anyauth', 'proxy-basic', 'proxy-digest', 'proxy-negotiate',
        'proxy-ntlm', 'q', 'raw', 'remote-name-all', 's', 'silent', 'sasl-ir', 'S', 'show-error',
        'ssl', 'ssl-reqd', 'ssl-allow-beast', 'ssl-no-revoke', 'socks5-gssapi-nec', 'tcp-nodelay',
        'tlsv1.0', 'tlsv1.1', 'tlsv1.2', 'tr-encoding', 'trace-time', 'v', 'verbose', 'xattr',
        'h', 'help', 'M', 'manual', 'V', 'version'
    ];

    if (!curl.trim())
        return "empty input";
    var cmd = parseCommand(curl, {
        boolFlags: boolOptions
    });

    if (cmd._[0] != "curl")
        throw "Not a curl command";

    var req = extractRelevantPieces(cmd);

    if (req.headers.length == 0 && !req.data.ascii && !req.data.files && !req.basicauth) {
        return promo + "\n" + renderSimple(req.method, req.url);
    }
    return promo + "\n\n" + renderComplex(req);

    // renderSimple renders a simple HTTP request using requests convenience methods
    function renderSimple(method, url) {
        if (method == "GET")
            return 'requests.get(' + url + ')\n';
        else if (method == "POST")
            return 'requests.post(' + url + ', data=None)\n';
        else if (method == "HEAD")
            return 'requests.head(' + url + ')\n';
        else
            return 'not supported yet';
    }

    // renderComplex renders py code that requires making a http.Request.
    function renderComplex(req) {
        var py = "";
        headers = "headers = {\n";
        for (var name in req.headers) {
            headers += '    \'' + name + '\': \'' + req.headers[name] + '\',\n';
        }
        headers += "}\n";
        data = "data = data\n";
        return py + "\n" + headers + "\n" + data;
    }

    // getHeaders generate a dict which contains header name and header value
    function getHeaders(cmd) {
        var result = {};
        var colonIndex;
        var header;
        var headerName;
        var headerValue;

        if (cmd.H) {
            for (var i = 0; i < cmd.H.length; i++) {
                header = cmd.H[i];
                console.log(header);
                colonIndex = header.indexOf(':');
                headerName = header.substring(0, colonIndex);
                headerValue = header.substring(colonIndex + 1).trim();
                result[headerName] = headerValue;
            }
        }
        if (cmd.header) {
            for (i = 0; i < cmd.H.length; i++) {
                header = cmd.header[i];
                colonIndex = header.indexOf(':');
                headerName = header.substring(0, colonIndex);
                headerValue = header.substring(colonIndex + 1).trim();
                result[headerName] = headerValue;
            }
        }
        return result;
    }

    // extractRelevantPieces returns an object with relevant pieces
    // extracted from cmd, the parsed command. This accounts for
    // multiple flags that do the same thing and return structured
    // data that makes it easy to spit out py code.
    function extractRelevantPieces(cmd) {
        var relevant = {
            url: "",
            method: "",
            headers: {},
            data: {}
        };

        // prefer --url over unnamed parameter, if it exists; keep first one only
        if (cmd.url && cmd.url.length > 0)
            relevant.url = cmd.url[0];
        else if (cmd._.length > 1)
            relevant.url = cmd._[1]; // position 1 because index 0 is the curl command itself

        // gather the headers together
        relevant.headers = getHeaders(cmd);
        // set method to HEAD?
        if (cmd.I || cmd.head)
            relevant.method = "HEAD";

        // between -X and --request, prefer the long form I guess
        if (cmd.request && cmd.request.length > 0)
            relevant.method = cmd.request[cmd.request.length - 1].toUpperCase();
        else if (cmd.X && cmd.X.length > 0)
            relevant.method = cmd.X[cmd.X.length - 1].toUpperCase(); // if multiple, use last (according to curl docs)

        // join multiple request body data, if any
        var dataAscii = [];
        var dataFiles = [];
        var loadData = function(d) {
            if (!relevant.method)
                relevant.method = "POST";

            // curl adds a default Content-Typ header if not set explicitly
            if (relevant.headers["Content-Type"] != "") {
                hasContentType = true;
            } else {
                relevant.headers["Content-Type"] = "application/x-www-form-urlencoded";
            }

            for (var i = 0; i < d.length; i++) {
                if (d[i].length > 0 && d[i][0] == "@")
                    dataFiles.push(d[i].substr(1));
                else
                    dataAscii.push(d[i]);
            }
        };
        if (cmd.d)
            loadData(cmd.d);
        if (cmd.data)
            loadData(cmd.data);
        if (dataAscii.length > 0)
            relevant.data.ascii = dataAscii.join("&");
        if (dataFiles.length > 0)
            relevant.data.files = dataFiles;

        // between -u and --user, choose the long form...
        var basicAuthString = "";
        if (cmd.user && cmd.user.length > 0)
            basicAuthString = cmd.user[cmd.user.length - 1];
        else if (cmd.u && cmd.u.length > 0)
            basicAuthString = cmd.u[cmd.u.length - 1];
        var basicAuthSplit = basicAuthString.indexOf(":");
        if (basicAuthSplit > -1) {
            relevant.basicauth = {
                user: basicAuthString.substr(0, basicAuthSplit),
                pass: basicAuthString.substr(basicAuthSplit + 1)
            };
        } else {
            relevant.basicAuth = {
                user: basicAuthString,
                pass: "<PASSWORD>"
            };
        }

        // default to GET if nothing else specified
        if (!relevant.method)
            relevant.method = "GET";

        return relevant;
    }

    function toTitleCase(str) {
        return str.replace(/\w*/g, function(txt) {
            return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
        });
    }
}

function parseCommand(input, options) {
    if (typeof options === 'undefined') {
        options = {};
    }

    var result = {
            _: []
        }, // what we return
        cursor = 0, // iterator position
        token = ""; // current token (word or quoted string) being built

    // trim leading $ or # that may have been left in
    input = input.trim();
    if (input.length > 2 && (input[0] == '$' || input[0] == '#') && whitespace(input[1]))
        input = input.substr(1).trim();

    for (cursor = 0; cursor < input.length; cursor++) {
        skipWhitespace();
        if (input[cursor] == "-") {
            flagSet();
        } else {
            unflagged();
        }
    }

    return result;

    // isLongFalg return true is input length is larger than cursor and
    // come with a dash
    function isLongFalg() {
        return cursor < input.length - 1 && input[cursor + 1] == "-";
    }

    // flagSet handles flags and it assumes the current cursor
    // points to a first dash.
    function flagSet() {
        // long flag form?
        if (isLongFalg()) {
            return longFlag();
        }

        // if not, parse short flag form
        return shortFlag();
    }

    // longFlag consumes a "--long-flag" sequence and
    // stores it in result.
    function longFlag() {
        cursor += 2; // skip leading dashes
        var flagName = nextString("=");
        if (boolFlag(flagName))
            result[flagName] = true;
        else {
            if (typeof result[flagName] == 'undefined') {
                result[flagName] = [];
            }
            if (Array.isArray(result[flagName])) {
                result[flagName].push(nextString());
            }
        }
    }

    function shortFlag() {
        cursor++; // skip leading dash
        while (cursor < input.length && !whitespace(input[cursor])) {
            var flagName = input[cursor];
            if (typeof result[flagName] == 'undefined') {
                result[flagName] = [];
            }
            cursor++; // skip the flag name
            if (boolFlag(flagName))
                result[flagName] = true;
            else if (Array.isArray(result[flagName]))
                result[flagName].push(nextString());
        }
    }

    // unflagged consumes the next string as an unflagged value,
    // storing it in the result.
    function unflagged() {
        result._.push(nextString());
    }

    // boolFlag returns whether a flag is known to be boolean type
    function boolFlag(flag) {
        if (Array.isArray(options.boolFlags)) {
            for (var i = 0; i < options.boolFlags.length; i++) {
                if (options.boolFlags[i] == flag)
                    return true;
            }
        }
        return false;
    }

    // nextString skips any leading whitespace and consumes the next
    // space-delimited string value and returns it. If endChar is set,
    // it will be used to determine the end of the string. Normally just
    // unescaped whitespace is the end of the string, but endChar can
    // be used to specify another end-of-string. This function honors \
    // as an escape character and does not include it in the value, except
    // in the special case of the \$ sequence, the backslash is retained
    // so other code can decide whether to treat as an env var or not.
    function nextString(endChar) {
        skipWhitespace();

        var str = "";

        var quoted = false,
            quoteCh = "",
            escaped = false;

        for (; cursor < input.length; cursor++) {
            if (quoted) {
                if (input[cursor] == quoteCh && !escaped) {
                    quoted = false;
                    continue;
                }
            }
            if (!quoted) {
                if (!escaped) {
                    if (whitespace(input[cursor])) {
                        return str;
                    }
                    if (input[cursor] == '"' || input[cursor] == "'") {
                        quoted = true;
                        quoteCh = input[cursor];
                        cursor++;
                    }
                    if (endChar && input[cursor] == endChar) {
                        cursor++; // skip the endChar
                        return str;
                    }
                }
            }
            if (!escaped && input[cursor] == "\\") {
                escaped = true;
                // skip the backslash unless the next character is $
                if (!(cursor < input.length - 1 && input[cursor + 1] == '$'))
                    continue;
            }

            str += input[cursor];
            escaped = false;
        }

        return str;
    }

    // skipWhitespace skips whitespace between tokens, taking into account escaped whitespace.
    function skipWhitespace() {
        for (; cursor < input.length; cursor++) {
            while (input[cursor] == "\\" && (cursor < input.length - 1 && whitespace(input[cursor + 1])))
                cursor++;
            if (!whitespace(input[cursor]))
                break;
        }
    }

    // whitespace returns true if ch is a whitespace character.
    function whitespace(ch) {
        return ch == " " || ch == "\t" || ch == "\n" || ch == "\r";
    }
}
<|endoftext|>


<commit_before>var strings = {
  // Titles
  "import-button-title-plain"    : "Import a text file from your system",
  "import-button-title-textile"  : "Import a Textile file from your system",
  "import-button-title-markdown" : "Import a Markdown file from your system",
  // Menus
  "export-text-plain"    : "Text file",
  "export-text-textile"  : "Textile file",
  "export-text-markdown" : "Markdown file"
}

$(document).ready(function()
{
  var renderMode = "textile";
  $('#language-textile').append(" ✓");

  // jQuery uniform controls (http://pixelmatrixdesign.com/uniform)
  $("select, input:checkbox, input:radio, input:file").uniform();

  // Tooltips (http://onehackoranother.com/projects/jquery/tipsy)
  $('#import-button').tipsy({opacity: 1, trigger: 'manual'});
  $('#import-button').bind('mouseenter', function (e) {
     var allMenus = $('.opener');
     // Check if there is a menu opened
     if (allMenus.filter('.open').length != 0) {
       // Hide all opened menus but add a class to enable linked menus
       allMenus.each(function() {
         hideWindow($(this));
         $(this).addClass('menu-link');
       });
     }
     $(this).tipsy("show");
  });
  $('#import-button').bind('mouseleave', function (e) {
     $(this).tipsy("hide");
  });

  // Hide all opened menus when clicking anywhere
  $(document).click( function(e) {
     var allMenus = $('.opener');
     allMenus.each(function() {
       hideWindow($(this));
     });
  });

  var converter = new Showdown.converter();

  // Editor
  var editor = CodeMirror.fromTextArea('code', {
    parserfile: ["javascripts/modes/markdown.js", "javascripts/modes/textile.js"],
    stylesheet: "stylesheets/modes/default.css",
    basefiles: ["javascripts/codemirror/codemirror_base.js"],
    textWrapping: true,
    indentUnit: 4,
    parserConfig: {'strictErrors': true},
    iframeClass: "editor",
    height: '100%',
    initCallback: init
  });

  function render(val) {
    switch(renderMode)
    {
      case "plain":
        val = val.replace(/\r\n|\r|\n/g,"
"); // Newlines
        val = val.replace(/  /g, "  "); // Whitespaces
        $('#paper').html("

" + val);
        $('#import-button').attr("title", strings['import-button-title-plain']);
        $('#export-text').text(strings['export-text-plain']);
        break;

      case "textile":
        editor.setParser('TextileParser');
        $('#paper').html(textile(val));
        $('#import-button').attr("title", strings['import-button-title-textile']);
        $('#export-text').text(strings['export-text-textile']);
        break;

      case "markdown":
        editor.setParser('MarkdownParser');
        $('#paper').html(converter.makeHtml(val));
        $('#import-button').attr("title", strings['import-button-title-markdown']);
        $('#export-text').text(strings['export-text-markdown']);
        break;

      case "latex":
        break;
    }
  }

  // Switch
  $('#switch').iphoneSwitch("on",
    function() {
      $('.editor').hide();
      $('#preview').show();
      render(editor.getCode());
      $('#preview').css('top', '0px');
      $('#preview').focus();
    },
    function() {
      $('#preview').hide();
      $('.editor').show();
      $('.editor').focus();
    }, editor.win.document,
    {
      switch_path: 'images/switch.png'
    }
  );

  // Manage click events
  $('.language').click(function() {
    $('.language').each(function() {
      $(this).text($(this).text().replace(' ✓',''));
    })
    $(this).append(" ✓");

    switch(this.id)
    {
      case "language-plain":
        renderMode = "plain";
        break;
      case "language-textile":
        renderMode = "textile";
        break;
      case "language-markdown":
        renderMode = "markdown";
        break;
      case "language-latex":
        renderMode = "latex";
        break;
    }
    render(editor.getCode());
  });

  $('.editor').hide();
  function init() {
    render($('#code').val());

    // Show & hide toolbar
    $('#toolbar-area').mouseover(function() {
       $('#toolbar').slideDown('fast');
    });
    $(editor.win.document).click(function() {
       setTimeout(function() { $('#toolbar').slideUp('fast'); }, 500);
    });
    $('#preview').click(function() {
       setTimeout(function() { $('#toolbar').slideUp('fast'); }, 500);
    });
  }
});<commit_msg>Save scroll position of the preview mode<commit_after>var strings = {
  // Titles
  "import-button-title-plain"    : "Import a text file from your system",
  "import-button-title-textile"  : "Import a Textile file from your system",
  "import-button-title-markdown" : "Import a Markdown file from your system",
  // Menus
  "export-text-plain"    : "Text file",
  "export-text-textile"  : "Textile file",
  "export-text-markdown" : "Markdown file"
}

$(document).ready(function()
{
  var renderMode = "textile";
  var scrollPos = 0;
  $('#language-textile').append(" ✓");

  // jQuery uniform controls (http://pixelmatrixdesign.com/uniform)
  $("select, input:checkbox, input:radio, input:file").uniform();

  // Tooltips (http://onehackoranother.com/projects/jquery/tipsy)
  $('#import-button').tipsy({opacity: 1, trigger: 'manual'});
  $('#import-button').bind('mouseenter', function (e) {
     var allMenus = $('.opener');
     // Check if there is a menu opened
     if (allMenus.filter('.open').length != 0) {
       // Hide all opened menus but add a class to enable linked menus
       allMenus.each(function() {
         hideWindow($(this));
         $(this).addClass('menu-link');
       });
     }
     $(this).tipsy("show");
  });
  $('#import-button').bind('mouseleave', function (e) {
     $(this).tipsy("hide");
  });

  // Hide all opened menus when clicking anywhere
  $(document).click( function(e) {
     var allMenus = $('.opener');
     allMenus.each(function() {
       hideWindow($(this));
     });
  });

  var converter = new Showdown.converter();

  // Editor
  var editor = CodeMirror.fromTextArea('code', {
    parserfile: ["javascripts/modes/markdown.js", "javascripts/modes/textile.js"],
    stylesheet: "stylesheets/modes/default.css",
    basefiles: ["javascripts/codemirror/codemirror_base.js"],
    textWrapping: true,
    indentUnit: 4,
    parserConfig: {'strictErrors': true},
    iframeClass: "editor",
    height: '100%',
    initCallback: init
  });

  function render(val) {
    switch(renderMode)
    {
      case "plain":
        val = val.replace(/\r\n|\r|\n/g,"
"); // Newlines
        val = val.replace(/  /g, "  "); // Whitespaces
        $('#paper').html("

" + val);
        $('#import-button').attr("title", strings['import-button-title-plain']);
        $('#export-text').text(strings['export-text-plain']);
        break;

      case "textile":
        editor.setParser('TextileParser');
        $('#paper').html(textile(val));
        $('#import-button').attr("title", strings['import-button-title-textile']);
        $('#export-text').text(strings['export-text-textile']);
        break;

      case "markdown":
        editor.setParser('MarkdownParser');
        $('#paper').html(converter.makeHtml(val));
        $('#import-button').attr("title", strings['import-button-title-markdown']);
        $('#export-text').text(strings['export-text-markdown']);
        break;

      case "latex":
        break;
    }
  }

  // Switch
  $('#switch').iphoneSwitch("on",
    function() {
      $('.editor').hide();
      $('#preview').show();
      render(editor.getCode());
      $('#preview').css('top', '0px');
      $('#preview').focus();
      $('#preview').attr({ scrollTop: scrollPos });
    },
    function() {
      scrollPos = $('#preview').attr('scrollTop');

      $('#preview').hide();
      $('.editor').show();
      $('.editor').focus();
    }, editor.win.document,
    {
      switch_path: 'images/switch.png'
    }
  );

  // Manage click events
  $('.language').click(function() {
    $('.language').each(function() {
      $(this).text($(this).text().replace(' ✓',''));
    })
    $(this).append(" ✓");

    switch(this.id)
    {
      case "language-plain":
        renderMode = "plain";
        break;
      case "language-textile":
        renderMode = "textile";
        break;
      case "language-markdown":
        renderMode = "markdown";
        break;
      case "language-latex":
        renderMode = "latex";
        break;
    }
    render(editor.getCode());
  });

  $('.editor').hide();
  function init() {
    render($('#code').val());

    // Show & hide toolbar
    $('#toolbar-area').mouseover(function() {
       $('#toolbar').slideDown('fast');
    });
    $(editor.win.document).click(function() {
       setTimeout(function() { $('#toolbar').slideUp('fast'); }, 500);
    });
    $('#preview').click(function() {
       setTimeout(function() { $('#toolbar').slideUp('fast'); }, 500);
    });
  }
});<|endoftext|>


<commit_before>
// 3rd
const debug = require('debug')('app:services:discord')
const assert = require('better-assert')
// 1st
const Client = require('../discord/client')
const config = require('../config')
const pre = require('../presenters')

//
// TODO: DRY up these functions.
// TODO: Avoid the #staff-channel lookup on every function call.
//

////////////////////////////////////////////////////////////

function makeClient () {
  return new Client({botToken: config.DISCORD_BOT_TOKEN})
}

////////////////////////////////////////////////////////////

// nuker and spambot are users
exports.broadcastManualNuke = async ({nuker, spambot}) => {
  assert(nuker)
  assert(spambot)
  pre.presentUser(nuker)
  pre.presentUser(spambot)

  const client = makeClient()

  // Find the #staff-only channel
  const channel = await client.listGuildChannels(config.DISCORD_GUILD_ID)
    .then((cs) => cs.find((c) => c.name === 'staff-only'))

  if (!channel) {
    console.error(`Could not find a #staff-only channel for broadcast.`)
    return
  }

  const content = `@here :hammer: ${nuker.uname} nuked ${config.HOST}${spambot.url} :radioactive:`

  console.log(content)

  // Broadcast
  await client.createMessage(channel.id, { content })
}

////////////////////////////////////////////////////////////

// nuker and spambot are users
exports.broadcastManualUnnuke = async ({nuker, spambot}) => {
  assert(nuker)
  assert(spambot)
  pre.presentUser(nuker)
  pre.presentUser(spambot)

  const client = makeClient()

  // Find the #staff-only channel
  const channel = await client.listGuildChannels(config.DISCORD_GUILD_ID)
    .then((cs) => cs.find((c) => c.name === 'staff-only'))

  if (!channel) {
    console.error(`Could not find a #staff-only channel for broadcast.`)
    return
  }

  const content = `@here :white_check_mark: ${nuker.uname} UN-nuked ${config.HOST}${spambot.url}`

  // Broadcast
  await client.createMessage(channel.id, { content })
}

////////////////////////////////////////////////////////////

// Info is an object of arbitrary data about the analysis
// to be sent along with the broadcast for debugging purposes.
exports.broadcastAutoNuke = async (user, postId, info) => {
  assert(user)
  assert(Number.isInteger(postId))

  // Need url
  pre.presentUser(user)

  if (!config.IS_DISCORD_CONFIGURED) {
    console.error(`
      Called services.discord.js#broadcastAutoNuke but Discord
      is not configured.
    `)
    return
  }

  const client = makeClient()

  // Find the #staff-only channel
  const channel = await client.listGuildChannels(config.DISCORD_GUILD_ID)
    .then((cs) => cs.find((c) => c.name === 'staff-only'))

  if (!channel) {
    console.error(`Could not find a #staff-only channel for broadcast.`)
    return
  }

  const content = `@here :robot: User ${config.HOST}${user.url} was auto-nuked for this post: ${config.HOST}/posts/${postId} :radioactive:

\`\`\`
${JSON.stringify(info, null, 2)}
\`\`\`
  `.trim()

  // Broadcast
  await client.createMessage(channel.id, { content })
}

////////////////////////////////////////////////////////////

exports.broadcastUserJoin = async (user) => {
  // Need url
  pre.presentUser(user)

  if (!config.IS_DISCORD_CONFIGURED) {
    console.error(`
      Called services.discord.js#broadcastUserJoin but Discord
      is not configured.
    `)
    return
  }

  const client = makeClient()

  // Find the #staff-only channel
  const channel = await client.listGuildChannels(config.DISCORD_GUILD_ID)
    .then((cs) => cs.find((c) => c.name === 'staff-only'))

  if (!channel) {
    console.error(`Could not find a #staff-only channel for broadcast.`)
    return
  }

  // Broadcast
  await client.createMessage(channel.id, {
    content: `@here :baby: A new user joined: ${config.HOST}${user.url}`
  })
}

////////////////////////////////////////////////////////////

exports.broadcastIntroTopic = async (user, topic) => {
  // Need url
  pre.presentUser(user)
  pre.presentTopic(topic)

  const client = makeClient()

  const channel = await client.listGuildChannels(config.DISCORD_GUILD_ID)
    .then((cs) => cs.find((c) => c.name === 'general'))

  if (!channel) {
    console.error(`Could not find a #general channel for broadcast.`)
    return
  }

  // Broadcast
  await client.createMessage(channel.id, {
    content: `Howdy, :wave: ${user.uname} created an Introduce Yourself thread: ${config.HOST}${topic.url}. Please help us welcome them!`
  })
}
<commit_msg>Update guildbot messages<commit_after>
// 3rd
const debug = require('debug')('app:services:discord')
const assert = require('better-assert')
// 1st
const Client = require('../discord/client')
const config = require('../config')
const pre = require('../presenters')

//
// TODO: DRY up these functions.
// TODO: Avoid the #staff-channel lookup on every function call.
//

////////////////////////////////////////////////////////////

function makeClient () {
  return new Client({botToken: config.DISCORD_BOT_TOKEN})
}

////////////////////////////////////////////////////////////

// nuker and spambot are users
exports.broadcastManualNuke = async ({nuker, spambot}) => {
  assert(nuker)
  assert(spambot)
  pre.presentUser(nuker)
  pre.presentUser(spambot)

  const client = makeClient()

  // Find the #staff-only channel
  const channel = await client.listGuildChannels(config.DISCORD_GUILD_ID)
    .then((cs) => cs.find((c) => c.name === 'staff-only'))

  if (!channel) {
    console.error(`Could not find a #staff-only channel for broadcast.`)
    return
  }

  const content = `@here :hammer: **${nuker.uname}** nuked ${config.HOST}${spambot.url} :radioactive:`

  console.log(content)

  // Broadcast
  await client.createMessage(channel.id, { content })
}

////////////////////////////////////////////////////////////

// nuker and spambot are users
exports.broadcastManualUnnuke = async ({nuker, spambot}) => {
  assert(nuker)
  assert(spambot)
  pre.presentUser(nuker)
  pre.presentUser(spambot)

  const client = makeClient()

  // Find the #staff-only channel
  const channel = await client.listGuildChannels(config.DISCORD_GUILD_ID)
    .then((cs) => cs.find((c) => c.name === 'staff-only'))

  if (!channel) {
    console.error(`Could not find a #staff-only channel for broadcast.`)
    return
  }

  const content = `@here :white_check_mark: **${nuker.uname}** UN-nuked ${config.HOST}${spambot.url}`

  // Broadcast
  await client.createMessage(channel.id, { content })
}

////////////////////////////////////////////////////////////

// Info is an object of arbitrary data about the analysis
// to be sent along with the broadcast for debugging purposes.
exports.broadcastAutoNuke = async (user, postId, info) => {
  assert(user)
  assert(Number.isInteger(postId))

  // Need url
  pre.presentUser(user)

  if (!config.IS_DISCORD_CONFIGURED) {
    console.error(`
      Called services.discord.js#broadcastAutoNuke but Discord
      is not configured.
    `)
    return
  }

  const client = makeClient()

  // Find the #staff-only channel
  const channel = await client.listGuildChannels(config.DISCORD_GUILD_ID)
    .then((cs) => cs.find((c) => c.name === 'staff-only'))

  if (!channel) {
    console.error(`Could not find a #staff-only channel for broadcast.`)
    return
  }

  const content = `@here :robot: User ${config.HOST}${user.url} was auto-nuked for this post: ${config.HOST}/posts/${postId} :radioactive:

\`\`\`
${JSON.stringify(info, null, 2)}
\`\`\`
  `.trim()

  // Broadcast
  await client.createMessage(channel.id, { content })
}

////////////////////////////////////////////////////////////

exports.broadcastUserJoin = async (user) => {
  // Need url
  pre.presentUser(user)

  if (!config.IS_DISCORD_CONFIGURED) {
    console.error(`
      Called services.discord.js#broadcastUserJoin but Discord
      is not configured.
    `)
    return
  }

  const client = makeClient()

  // Find the #staff-only channel
  const channel = await client.listGuildChannels(config.DISCORD_GUILD_ID)
    .then((cs) => cs.find((c) => c.name === 'staff-only'))

  if (!channel) {
    console.error(`Could not find a #staff-only channel for broadcast.`)
    return
  }

  // Broadcast
  await client.createMessage(channel.id, {
    content: `@here :baby: A new user joined: ${config.HOST}${user.url}`
  })
}

////////////////////////////////////////////////////////////

exports.broadcastIntroTopic = async (user, topic) => {
  // Need url
  pre.presentUser(user)
  pre.presentTopic(topic)

  const client = makeClient()

  const channel = await client.listGuildChannels(config.DISCORD_GUILD_ID)
    .then((cs) => cs.find((c) => c.name === 'general'))

  if (!channel) {
    console.error(`Could not find a #general channel for broadcast.`)
    return
  }

  // Broadcast
  await client.createMessage(channel.id, {
    content: `Howdy, :wave: **${user.uname}** created an Introduce Yourself thread: ${config.HOST}${topic.url}. Please help us welcome them!`
  })
}
<|endoftext|>


<commit_before>import Component from '@ember/component';
import { action } from '@ember/object';

export default class CesiumButton extends Component {
  tagName = '';

  @action toggle() {
    if (this.enabled) {
      this.onDisable();
    } else {
      this.onEnable();
    }
  }
}
<commit_msg>CesiumButton: Convert to Glimmer component<commit_after>import { action } from '@ember/object';

import Component from '@glimmer/component';

export default class CesiumButton extends Component {
  @action toggle() {
    if (this.args.enabled) {
      this.args.onDisable();
    } else {
      this.args.onEnable();
    }
  }
}
<|endoftext|>


<commit_before>var $ = require('jquery');
var m = require('mithril');
var $osf = require('js/osfHelpers');
var LogText = require('js/logTextParser');

var xhrconfig = function (xhr) {
    xhr.withCredentials = true;
    xhr.setRequestHeader('Content-Type', 'application/vnd.api+json');
    xhr.setRequestHeader('Accept', 'application/vnd.api+json; ext=bulk');

};

var LogWrap = {
    controller: function(args){
        var self = this;
        self.userId = args.userId;
        self.activityLogs = m.prop();
        self.eventFilter = false;
        self.dateEnd = new Date();
        self.today = new Date();
        self.page = 1;

        self.getLogs = function(init) {
            var query = {
                'embed': ['nodes', 'user', 'linked_node', 'template_node'],
                'page': self.page
            };
            if (self.eventFilter) {
                query['filter[action]'] = self.eventFilter;
            }
            if (init) {
                query['aggregate'] = 1;
            } else {
                var save = Number(self.dateEnd);
                query['filter[date][lte]'] = self.dateEnd.toISOString();
                self.dateEnd.setMonth(self.dateEnd.getMonth() - 1);
                query['filter[date][gte]'] = self.dateEnd.toISOString();
                self.dateEnd = new Date(save);
            }
            var url = $osf.apiV2Url('users/' + self.userId + '/node_logs/', { query : query});
            var promise = m.request({method : 'GET', url : url, config : xhrconfig});
            promise.then(function(result){
                result.data.map(function(log){
                    log.attributes.formattableDate = new $osf.FormattableDate(log.attributes.date);
                });
                if (!init) {self.activityLogs(result.data)}
                if (init) {
                    self.totalEvents = result.links.meta.total;
                    self.eventNumbers = result.links.meta.aggregates;
                    self.lastDay = new Date(result.data[0].attributes.date);
                    self.dateEnd = self.lastDay;
                    self.firstDay = new Date(result.links.meta.last_log_date);
                }
                self.lastPage = (result.links.meta.total / result.links.meta.per_page | 0) + 1;
            });
            return promise;
        };
        self.getLogs(true);
        self.getLogs();
    },
    view: function(ctrl, args){
        var fileEvents = (ctrl.eventNumbers.files/ctrl.totalEvents)*100 | 0;
        var commentEvents = (ctrl.eventNumbers.comments/ctrl.totalEvents)*100 | 0;
        var wikiEvents = (ctrl.eventNumbers.wiki/ctrl.totalEvents)*100 | 0;
        var nodeEvents = (ctrl.eventNumbers.nodes/ctrl.totalEvents)*100 | 0;
        var otherEvents = 100 - (fileEvents + commentEvents + wikiEvents + nodeEvents);
        var addSlider = function(ele, isInitialized){
            if (!isInitialized) {
                $
                $("#recentActivitySlider").slider({
                    min: Number(ctrl.firstDay),
                    max: Number(ctrl.today),
                    value: Number(ctrl.dateEnd),
                    range: true,
                    stop: function (event, ui) {
                        ctrl.page = 1;
                        ctrl.dateEnd = new Date(ui.value);
                        ctrl.getLogs();
                    }
                });
            }
            else {
                $( "#recentActivitySlider" ).slider( "value", Number(ctrl.dateEnd), Number(ctrl.dateEnd) - 2.628e+9);
            }
        };
        return m('.panel.panel-default', [
            m('.panel-heading', 'Recent Activity'),
            m('.panel-body',
            m('.fb-activity-list.m-t-md', [
                m('#recentActivitySlider', {style: {margin: '10px'}, config: addSlider}),
                m('.progress', [
                    m('.progress-bar' + (ctrl.eventFilter === 'file' ? '.active.progress-bar-striped' : ''), {style: {width: fileEvents+'%'}},
                        m('a', {onclick: function(){
                            ctrl.eventFilter = ctrl.eventFilter === 'file' ? false : 'file';
                            ctrl.page = 1;
                            ctrl.getLogs();
                        }}, 'Files')
                    ),
                    m('.progress-bar.progress-bar-warning' + (ctrl.eventFilter === 'project' ? '.active.progress-bar-striped' : ''), {style: {width: nodeEvents+'%'}},
                        m('a', {onclick: function(){
                            ctrl.eventFilter = ctrl.eventFilter === 'project' ? false : 'project';
                            ctrl.page = 1;
                            ctrl.getLogs();
                        }}, 'Nodes')
                    ),
                    m('.progress-bar.progress-bar-info' + (ctrl.eventFilter === 'comment' ? '.active.progress-bar-striped' : ''), {style: {width: commentEvents+'%'}},
                        m('a', {onclick: function(){
                            ctrl.eventFilter = ctrl.eventFilter === 'comment' ? false : 'comment';
                            ctrl.page = 1;
                            ctrl.getLogs();
                        }}, 'Comments')
                    ),
                    m('.progress-bar.progress-bar-danger' + (ctrl.eventFilter === 'wiki' ? '.active.progress-bar-striped' : ''), {style: {width: wikiEvents+'%'}},
                        m('a', {onclick: function(){
                            ctrl.eventFilter = ctrl.eventFilter === 'wiki' ? false : 'wiki';
                            ctrl.page = 1;
                            ctrl.getLogs();
                        }}, 'Wiki')
                    ),
                    m('.progress-bar.progress-bar-success', {style: {width: otherEvents+'%'}}, 'Other')
                ]),
                ctrl.activityLogs() ? ctrl.activityLogs().map(function(item){

                    return m('.fb-activity-item', [
                        m('span.text-muted.m-r-xs', item.attributes.formattableDate.local),
                        m.component(LogText,item)
                    ]);
                }) : '',
                m('.btn-group', [
                    ctrl.page > 1 ? m('button.btn.btn-info', {onclick: function(){
                        ctrl.page--;
                        ctrl.getLogs()
                    }}, 'Previous') : '',
                    ctrl.lastPage > ctrl.page ? m('button.btn.btn-info', {onclick: function(){
                        ctrl.page++;
                        ctrl.getLogs()
                    }}, 'Next') : ''
                ])
            ]))
        ]);
    }
};

$(document).ready(function() {
    m.mount(document.getElementById('recentActivityWidget'), m.component(LogWrap, {userId: window.contextVars.userId}));
});
<commit_msg>Slider now has range that works<commit_after>var $ = require('jquery');
var m = require('mithril');
var $osf = require('js/osfHelpers');
var LogText = require('js/logTextParser');

var xhrconfig = function (xhr) {
    xhr.withCredentials = true;
    xhr.setRequestHeader('Content-Type', 'application/vnd.api+json');
    xhr.setRequestHeader('Accept', 'application/vnd.api+json; ext=bulk');

};

var LogWrap = {
    controller: function(args){
        var self = this;
        self.userId = args.userId;
        self.activityLogs = m.prop();
        self.eventFilter = false;
        self.dateEnd = new Date();
        self.dateBegin = new Date();
        self.today = new Date();
        self.page = 1;

        self.getLogs = function(init) {
            var query = {
                'embed': ['nodes', 'user', 'linked_node', 'template_node'],
                'page': self.page
            };
            if (self.eventFilter) {
                query['filter[action]'] = self.eventFilter;
            }
            if (init) {
                query['aggregate'] = 1;
            } else {
                query['filter[date][lte]'] = self.dateEnd.toISOString();
                query['filter[date][gte]'] = self.dateBegin.toISOString();
            }
            var url = $osf.apiV2Url('users/' + self.userId + '/node_logs/', { query : query});
            var promise = m.request({method : 'GET', url : url, config : xhrconfig});
            promise.then(function(result){
                result.data.map(function(log){
                    log.attributes.formattableDate = new $osf.FormattableDate(log.attributes.date);
                });
                if (!init) {self.activityLogs(result.data)}
                if (init) {
                    self.totalEvents = result.links.meta.total;
                    self.eventNumbers = result.links.meta.aggregates;
                    self.lastDay = new Date(result.data[0].attributes.date);
                    self.dateEnd = self.lastDay;
                    self.lastDay.setMonth(self.lastDay.getMonth() - 1);
                    self.dateBegin = self.lastDay;
                    self.firstDay = new Date(result.links.meta.last_log_date);
                }
                self.lastPage = (result.links.meta.total / result.links.meta.per_page | 0) + 1;
            });
            return promise;
        };
        self.getLogs(true);
        self.getLogs();
    },
    view: function(ctrl, args){
        var fileEvents = (ctrl.eventNumbers.files/ctrl.totalEvents)*100 | 0;
        var commentEvents = (ctrl.eventNumbers.comments/ctrl.totalEvents)*100 | 0;
        var wikiEvents = (ctrl.eventNumbers.wiki/ctrl.totalEvents)*100 | 0;
        var nodeEvents = (ctrl.eventNumbers.nodes/ctrl.totalEvents)*100 | 0;
        var otherEvents = 100 - (fileEvents + commentEvents + wikiEvents + nodeEvents);
        var addSlider = function(ele, isInitialized){
            if (!isInitialized) {
                $("#recentActivitySlider").slider({
                    min: Number(ctrl.firstDay),
                    max: Number(ctrl.today),
                    values: [Number(ctrl.dateBegin), Number(ctrl.dateEnd)],
                    range: true,
                    stop: function (event, ui) {
                        ctrl.page = 1;
                        ctrl.dateBegin = new Date(ui.values[0]);
                        ctrl.dateEnd = new Date(ui.values[1]);
                        ctrl.getLogs();
                    }
                });
            }
            else {
                $( "#recentActivitySlider" ).slider( 'option', "values", [Number(ctrl.dateBegin),  Number(ctrl.dateEnd)]);
            }
        };
        return m('.panel.panel-default', [
            m('.panel-heading', 'Recent Activity'),
            m('.panel-body',
            m('.fb-activity-list.m-t-md', [
                m('#recentActivitySlider', {style: {margin: '10px'}, config: addSlider}),
                m('.progress', [
                    m('.progress-bar' + (ctrl.eventFilter === 'file' ? '.active.progress-bar-striped' : ''), {style: {width: fileEvents+'%'}},
                        m('a', {onclick: function(){
                            ctrl.eventFilter = ctrl.eventFilter === 'file' ? false : 'file';
                            ctrl.page = 1;
                            ctrl.getLogs();
                        }}, 'Files')
                    ),
                    m('.progress-bar.progress-bar-warning' + (ctrl.eventFilter === 'project' ? '.active.progress-bar-striped' : ''), {style: {width: nodeEvents+'%'}},
                        m('a', {onclick: function(){
                            ctrl.eventFilter = ctrl.eventFilter === 'project' ? false : 'project';
                            ctrl.page = 1;
                            ctrl.getLogs();
                        }}, 'Nodes')
                    ),
                    m('.progress-bar.progress-bar-info' + (ctrl.eventFilter === 'comment' ? '.active.progress-bar-striped' : ''), {style: {width: commentEvents+'%'}},
                        m('a', {onclick: function(){
                            ctrl.eventFilter = ctrl.eventFilter === 'comment' ? false : 'comment';
                            ctrl.page = 1;
                            ctrl.getLogs();
                        }}, 'Comments')
                    ),
                    m('.progress-bar.progress-bar-danger' + (ctrl.eventFilter === 'wiki' ? '.active.progress-bar-striped' : ''), {style: {width: wikiEvents+'%'}},
                        m('a', {onclick: function(){
                            ctrl.eventFilter = ctrl.eventFilter === 'wiki' ? false : 'wiki';
                            ctrl.page = 1;
                            ctrl.getLogs();
                        }}, 'Wiki')
                    ),
                    m('.progress-bar.progress-bar-success', {style: {width: otherEvents+'%'}}, 'Other')
                ]),
                ctrl.activityLogs() ? ctrl.activityLogs().map(function(item){

                    return m('.fb-activity-item', [
                        m('span.text-muted.m-r-xs', item.attributes.formattableDate.local),
                        m.component(LogText,item)
                    ]);
                }) : '',
                m('.btn-group', [
                    ctrl.page > 1 ? m('button.btn.btn-info', {onclick: function(){
                        ctrl.page--;
                        ctrl.getLogs()
                    }}, 'Previous') : '',
                    ctrl.lastPage > ctrl.page ? m('button.btn.btn-info', {onclick: function(){
                        ctrl.page++;
                        ctrl.getLogs()
                    }}, 'Next') : ''
                ])
            ]))
        ]);
    }
};

$(document).ready(function() {
    m.mount(document.getElementById('recentActivityWidget'), m.component(LogWrap, {userId: window.contextVars.userId}));
});
<|endoftext|>


<commit_before>'use strict';
angular.module('arethusa.core').constant('CONF_ROUTE', {
  controller: 'ConfEditorCtrl',
  templateUrl: 'templates/conf_editor.html',
  resolve: {
    load: function ($http, configurator) {
      var url = './static/configs/conf_editor/1.json';
      return $http.get(url).then(function (res) {
        configurator.defineConfiguration(res.data, url);
      });
    }
  }
});
<commit_msg>Fix minification errors in confEditor<commit_after>'use strict';
angular.module('arethusa.core').constant('CONF_ROUTE', {
  controller: 'ConfEditorCtrl',
  templateUrl: 'templates/conf_editor.html',
  resolve: {
    load: ['$http', 'configurator', function ($http, configurator) {
      var url = './static/configs/conf_editor/1.json';
      return $http.get(url).then(function (res) {
        configurator.defineConfiguration(res.data, url);
      });
    }]
  }
});
<|endoftext|>


<commit_before>import SPELLS from 'common/SPELLS';

export default function isAtonement(event) {
  return [SPELLS.ATONEMENT_HEAL_NON_CRIT.id, SPELLS.ATONEMENT_HEAL_CRIT.id].indexOf(event.ability.guid) > -1;
}
<commit_msg>Update isAtonement.js<commit_after>import SPELLS from 'common/SPELLS';

export default function isAtonement(event) {
  return [SPELLS.ATONEMENT_HEAL_NON_CRIT.id, SPELLS.ATONEMENT_HEAL_CRIT.id].indexOf(event.ability.guid) !== -1;
}
<|endoftext|>


<commit_before>var handlebars = require('handlebars');
var helpers = require('helper-lib');

var plugin = function() {
  'use strict';

  var compile = function(src, options, callback) {
    var tmpl;
    try {
      tmpl = handlebars.compile(src, options);
    } catch(ex) {
      callback(ex, null);
    }
    callback(null, tmpl);
  };

  var render = function(tmpl, options, callback) {
    var content;
    try {
      if(typeof tmpl === 'string') {
        tmpl = handlebars.compile(tmpl, options);
      }
      content = tmpl(options);
    } catch (ex) {
      callback(ex, null);
    }
    callback(null, content);
  };

  var registerFunctions = function() {
    helpers.register(handlebars);
  };

  var registerPartial = function(filename, content) {
    var tmpl;
    try {
      if(typeof content === 'string') {
        tmpl = handlebars.compile(content);
      } else {
        tmpl = content;
      }
      handlebars.registerPartial(filename, tmpl);
    } catch (ex) {}
  };

  return {
    compile: compile,
    render: render,
    registerFunctions: registerFunctions,
    registerPartial: registerPartial
  };

};

module.exports = exports = plugin();
<commit_msg>updating to always load the default helper-lib helpers<commit_after>var handlebars = require('handlebars');
var helpers = require('helper-lib');

var plugin = function() {
  'use strict';

  var compile = function(src, options, callback) {
    var tmpl;
    try {
      tmpl = handlebars.compile(src, options);
    } catch(ex) {
      callback(ex, null);
    }
    callback(null, tmpl);
  };

  var render = function(tmpl, options, callback) {
    var content;
    try {
      if(typeof tmpl === 'string') {
        tmpl = handlebars.compile(tmpl, options);
      }
      content = tmpl(options);
    } catch (ex) {
      callback(ex, null);
    }
    callback(null, content);
  };

  var registerFunctions = function() {
  };

  var registerPartial = function(filename, content) {
    var tmpl;
    try {
      if(typeof content === 'string') {
        tmpl = handlebars.compile(content);
      } else {
        tmpl = content;
      }
      handlebars.registerPartial(filename, tmpl);
    } catch (ex) {}
  };

  // register built-in helpers
  helpers.register(handlebars);

  return {
    compile: compile,
    render: render,
    registerFunctions: registerFunctions,
    registerPartial: registerPartial
  };

};

module.exports = exports = plugin();
<|endoftext|>


<commit_before>/**********************************************************************
    Freeciv-web - the web version of Freeciv. http://play.freeciv.org/
    Copyright (C) 2009-2016  The Freeciv-web project

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

***********************************************************************/

/****************************************************************************
 Convert a canvas to a mesh that will always face the user. The height of
 `canvas' should be 16px.
 `width_final' gives the width of the content that will actually be displayed, not of the canvas itself.
 'width_input' I think is the width of the input.
 'height' is the height of the result.
 `transparent' should be true if canvas' content is transparent.
****************************************************************************/
function canvas_to_user_facing_mesh(canvas, width_input, width_final, height, transparent)
{
  // Create a texture out of the canvas
  var texture = new THREE.Texture(canvas);
  texture.needsUpdate = true;

  // Make a material
  var material = new THREE.ShaderMaterial({
    vertexShader: document.getElementById('labels_vertex_shh').textContent,
    fragmentShader: document.getElementById('tex_fragment_shh').textContent,
    uniforms: {
      texture: { value: texture },
      u_scale_factor: { value: width_input / canvas.width }
    }
  });
  material.transparent = transparent;

  // Put it all together
  return new THREE.Mesh(new THREE.PlaneBufferGeometry(width_final, height), material);
}

/****************************************************************************
 Create a city name label
****************************************************************************/
function create_city_label(pcity)
{
  var canvas1 = document.createElement('canvas');
  canvas1.width = 256;
  canvas1.height = 32;
  var ctx = canvas1.getContext('2d');

  var owner_id = pcity.owner;
  if (owner_id == null) return null;
  var owner = players[owner_id];

  // We draw from left to right, updating `width' after each call.
  var width = 0; // Total width of the bar

  // Flag
  var city_gfx = get_city_flag_sprite(pcity);
  ctx.drawImage(sprites[city_gfx.key],
                1, 1, // Remove the 1px black border, it's ugly
                sprites[city_gfx.key].width - 2, sprites[city_gfx.key].height - 2,
                0, 0, 28, 32);
  width += 28;

  // Occupied
  var ptile = city_tile(pcity);
  var punits = tile_units(ptile);
  if (punits.length > 0) {
    // Background
    ctx.fillStyle = 'black';
    ctx.fillRect(width, 0, 16, 32);
    // Stars
    ctx.drawImage(sprites[get_city_occupied_sprite(pcity)], width, 0, 13, 32);
    width += 13;
  }

  // Name and size
  var city_text = pcity.name + "  " + pcity.size;
  ctx.font = 'Bold 25px Arial';
  var txt_measure = ctx.measureText(city_text);
  // Background
  ctx.fillStyle = nations[owner.nation].color;
  ctx.fillRect(width, 0, txt_measure.width + 11 /* padding */, 32);
  // Text
  var dark_bg = false;
  var nation_colors = nations[owner['nation']].color.replace("rgb(", "").replace(")", "").split(",");
  if (parseInt(nation_colors[0]) + parseInt(nation_colors[1]) + parseInt(nation_colors[2]) < 300) dark_bg = true;
  if (dark_bg) {
    ctx.fillStyle = '#EEEEEE';
  } else {
    ctx.fillStyle = '#111111';
  }
  ctx.fillText(city_text, width + 4 /* padding */, 13*2);

  width += txt_measure.width + 11 /* padding */;

  // Production
  var prod_type = get_city_production_type(pcity);
  if (prod_type != null) {
    var tag = prod_type.graphic_str;
    if (tileset[tag] != null) {
      ctx.fillStyle = nations[owner.nation].color;
      ctx.fillRect(width, 0, 36, 32);
      ctx.drawImage(sprites[tag], width, 0, 31, 18*2);
      width += 32;
    }
  }

  return canvas_to_user_facing_mesh(canvas1, width, Math.floor(width * 0.7), 13, false);
}

/****************************************************************************
 Create a unit label
****************************************************************************/
function create_unit_label(punit)
{
  var canvas1 = document.createElement('canvas');
  canvas1.width = 32;
  canvas1.height = 16;
  var context1 = canvas1.getContext('2d');
  context1.font = "Bold 16px Arial";
  context1.fillStyle = "rgba(222,255,0, 1.0)";
  context1.strokeStyle= "black";
  context1.lineWidth = 0.5;

  var text = get_unit_activity_text(punit);
  var width = context1.measureText(text).width;
  context1.strokeText(text, 0, 16);
  context1.fillText(text, 0, 16);

  return canvas_to_user_facing_mesh(canvas1, width, Math.floor(width * 0.8), 13, true);
}

/**********************************************************************
  ...
***********************************************************************/
function get_unit_activity_text(punit)
{
  var activity = punit['activity'];
  var act_tgt  = punit['activity_tgt'];

  /* don't draw activity for enemy units */
  if (client.conn.playing == null || punit['owner'] != client.conn.playing.playerno) {
    return null;
  }

  switch (activity) {
    case ACTIVITY_POLLUTION:
      return "F";

    case ACTIVITY_MINE:
      return "M";

    case ACTIVITY_IRRIGATE:
      return "I";

    case ACTIVITY_FORTIFIED:
      return "F";

    case ACTIVITY_BASE:
      return "B";

    case ACTIVITY_SENTRY:
      return "S";

    case ACTIVITY_PILLAGE:
      return "P";

    case ACTIVITY_GOTO:
      return "G";

    case ACTIVITY_EXPLORE:
      return "X";

    case ACTIVITY_TRANSFORM:
      return "T";

    case ACTIVITY_FORTIFYING:
      return "f";

    case ACTIVITY_GEN_ROAD:
      return "R";

    case ACTIVITY_CONVERT:
      return "C";
  }

  if (unit_has_goto(punit)) {
      return "G";
  }

  if (punit['ai'] == true) {
      return "A";
  }

  return null;
}<commit_msg>Bugfix for long city names.<commit_after>/**********************************************************************
    Freeciv-web - the web version of Freeciv. http://play.freeciv.org/
    Copyright (C) 2009-2016  The Freeciv-web project

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

***********************************************************************/

/****************************************************************************
 Convert a canvas to a mesh that will always face the user. The height of
 `canvas' should be 16px.
 `width_final' gives the width of the content that will actually be displayed, not of the canvas itself.
 'width_input' I think is the width of the input.
 'height' is the height of the result.
 `transparent' should be true if canvas' content is transparent.
****************************************************************************/
function canvas_to_user_facing_mesh(canvas, width_input, width_final, height, transparent)
{
  // Create a texture out of the canvas
  var texture = new THREE.Texture(canvas);
  texture.needsUpdate = true;

  // Make a material
  var material = new THREE.ShaderMaterial({
    vertexShader: document.getElementById('labels_vertex_shh').textContent,
    fragmentShader: document.getElementById('tex_fragment_shh').textContent,
    uniforms: {
      texture: { value: texture },
      u_scale_factor: { value: width_input / canvas.width }
    }
  });
  material.transparent = transparent;

  // Put it all together
  return new THREE.Mesh(new THREE.PlaneBufferGeometry(width_final, height), material);
}

/****************************************************************************
 Create a city name label
****************************************************************************/
function create_city_label(pcity)
{
  var canvas1 = document.createElement('canvas');
  canvas1.width = 256;
  canvas1.height = 32;
  var ctx = canvas1.getContext('2d');

  var owner_id = pcity.owner;
  if (owner_id == null) return null;
  var owner = players[owner_id];

  // We draw from left to right, updating `width' after each call.
  var width = 0; // Total width of the bar

  // Flag
  var city_gfx = get_city_flag_sprite(pcity);
  ctx.drawImage(sprites[city_gfx.key],
                1, 1, // Remove the 1px black border, it's ugly
                sprites[city_gfx.key].width - 2, sprites[city_gfx.key].height - 2,
                0, 0, 28, 32);
  width += 28;

  // Occupied
  var ptile = city_tile(pcity);
  var punits = tile_units(ptile);
  if (punits.length > 0) {
    // Background
    ctx.fillStyle = 'black';
    ctx.fillRect(width, 0, 16, 32);
    // Stars
    ctx.drawImage(sprites[get_city_occupied_sprite(pcity)], width, 0, 13, 32);
    width += 13;
  }

  // Name and size
  var city_text = pcity.name + "  " + pcity.size;
  ctx.font = 'Bold 25px Arial';
  var txt_measure = ctx.measureText(city_text);
  // Background
  ctx.fillStyle = nations[owner.nation].color;
  ctx.fillRect(width, 0, txt_measure.width + 11 /* padding */, 32);
  // Text
  var dark_bg = false;
  var nation_colors = nations[owner['nation']].color.replace("rgb(", "").replace(")", "").split(",");
  if (parseInt(nation_colors[0]) + parseInt(nation_colors[1]) + parseInt(nation_colors[2]) < 300) dark_bg = true;
  if (dark_bg) {
    ctx.fillStyle = '#EEEEEE';
  } else {
    ctx.fillStyle = '#111111';
  }
  ctx.fillText(city_text, width + 4 /* padding */, 13*2);

  width += txt_measure.width + 11 /* padding */;

  // Production
  var prod_type = get_city_production_type(pcity);
  if (prod_type != null) {
    var tag = prod_type.graphic_str;
    if (tileset[tag] != null) {
      ctx.fillStyle = nations[owner.nation].color;
      ctx.fillRect(width, 0, 36, 32);
      ctx.drawImage(sprites[tag], width, 0, 31, 18*2);
      width += 32;
    }
  }

  if (width > 256) width = 256;
  return canvas_to_user_facing_mesh(canvas1, width, Math.floor(width * 0.7), 13, false);
}

/****************************************************************************
 Create a unit label
****************************************************************************/
function create_unit_label(punit)
{
  var canvas1 = document.createElement('canvas');
  canvas1.width = 32;
  canvas1.height = 16;
  var context1 = canvas1.getContext('2d');
  context1.font = "Bold 16px Arial";
  context1.fillStyle = "rgba(222,255,0, 1.0)";
  context1.strokeStyle= "black";
  context1.lineWidth = 0.5;

  var text = get_unit_activity_text(punit);
  var width = context1.measureText(text).width;
  context1.strokeText(text, 0, 16);
  context1.fillText(text, 0, 16);

  return canvas_to_user_facing_mesh(canvas1, width, Math.floor(width * 0.8), 13, true);
}

/**********************************************************************
  ...
***********************************************************************/
function get_unit_activity_text(punit)
{
  var activity = punit['activity'];
  var act_tgt  = punit['activity_tgt'];

  /* don't draw activity for enemy units */
  if (client.conn.playing == null || punit['owner'] != client.conn.playing.playerno) {
    return null;
  }

  switch (activity) {
    case ACTIVITY_POLLUTION:
      return "F";

    case ACTIVITY_MINE:
      return "M";

    case ACTIVITY_IRRIGATE:
      return "I";

    case ACTIVITY_FORTIFIED:
      return "F";

    case ACTIVITY_BASE:
      return "B";

    case ACTIVITY_SENTRY:
      return "S";

    case ACTIVITY_PILLAGE:
      return "P";

    case ACTIVITY_GOTO:
      return "G";

    case ACTIVITY_EXPLORE:
      return "X";

    case ACTIVITY_TRANSFORM:
      return "T";

    case ACTIVITY_FORTIFYING:
      return "f";

    case ACTIVITY_GEN_ROAD:
      return "R";

    case ACTIVITY_CONVERT:
      return "C";
  }

  if (unit_has_goto(punit)) {
      return "G";
  }

  if (punit['ai'] == true) {
      return "A";
  }

  return null;
}<|endoftext|>