<commit_before>// Process definition lists
//
'use strict';

module.exports = function multimd_table_plugin(md) {
    function getLine(state, line) {
        var pos = state.bMarks[line] + state.blkIndent,
            max = state.eMarks[line];

        return state.src.substr(pos, max - pos);
    }

    function escapedSplit(str) {
        var result = [],
            pos = 0,
            max = str.length,
            ch,
            escapes = 0,
            lastPos = 0,
            backTicked = false,
            lastBackTick = 0;

        ch = str.charCodeAt(pos);

        while (pos < max) {
            if (ch === 0x60/* ` */) {
                if (backTicked) {
                    // make \` close code sequence, but not open it;
                    // the reason is: `\` is correct code block
                    backTicked = false;
                    lastBackTick = pos;
                } else if ((escapes & 1) === 0) {
                    backTicked = true;
                    lastBackTick = pos;
                }
            } else if (ch === 0x7c/* | */ && (escapes & 1) === 0 && !backTicked) {
                result.push(str.substring(lastPos, pos));
                lastPos = pos + 1;
            }

            if (ch === 0x5c/* \ */) {
                escapes++;
            } else {
                escapes = 0;
            }

            pos++;

            // If there was an un-closed backtick, go back to just after
            // the last backtick, but as if it was a normal character
            if (pos === max && backTicked) {
                backTicked = false;
                pos = lastBackTick + 1;
            }

            ch = str.charCodeAt(pos);
        }

        result.push(str.substring(lastPos));

        return result;
    }

    function table(state, startLine, endLine, silent) {
        var lineText, i, seperatorLine, nextLine, columns, columnCount, token, aligns, wraps, t, tableLines, tbodyLines;

        // should have at least two lines
        if (startLine + 2 > endLine) { return false; }

        seperatorLine = startLine + 1;
        if (state.sCount[seperatorLine] < state.blkIndent) { return false; }
        if (state.sCount[seperatorLine] - state.blkIndent >= 4) { return false; }
        // if it's indented more than 3 spaces, it should be a code block

        lineText = getLine(state, seperatorLine);
        columns = lineText.split('|');
        if (columns.length === 1 && !/^\||[^\\]\|$/.test(lineText)) { return false; }
        aligns = [];
        wraps = [];
        for (i = 0; i < columns.length; i++) {
            t = columns[i].trim();
            if (!t) {
                // allow empty columns before and after table, but not in between columns;
                // e.g. allow ` |---| `, disallow ` ---||--- `
                if (i === 0 || i === columns.length - 1) {
                    continue;
                } else {
                    return false;
                }
            }

            if (!/^:?(-+|=+|\.+):?\+?$/.test(t)) { return false; }
            if (t.charCodeAt(t.length - 1) === 0x2B/* + */) {
                wraps.push(true);
                t = t.slice(0, -1);
            } else {
                wraps.push(false);
            }
            if (t.charCodeAt(t.length - 1) === 0x3A/* : */) {
                aligns.push(t.charCodeAt(0) === 0x3A/* : */ ? 'center' : 'right');
            } else if (t.charCodeAt(0) === 0x3A/* : */) {
                aligns.push('left');
            } else {
                aligns.push('');
            }
        }

        lineText = getLine(state, startLine).trim();
        if (lineText.indexOf('|') === -1) { return false; }
        if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
        columns = escapedSplit(lineText.replace(/^\||\|$/g, ''));

        // header row will define an amount of columns in the entire table,
        // and align row shouldn't be smaller than that (the rest of the rows can)
        columnCount = columns.length;
        if (columnCount > aligns.length) { return false; }
        if (columns.length === 1 && !/^\||[^\\]\|$/.test(lineText)) { return false; }

        if (silent) { return true; }

        token     = state.push('table_open', 'table', 1);
        token.map = tableLines = [ startLine, 0 ];

        token     = state.push('thead_open', 'thead', 1);
        token.map = [ startLine, startLine + 1 ];

        token     = state.push('tr_open', 'tr', 1);
        token.map = [ startLine, startLine + 1 ];

        for (i = 0; i < columns.length; i++) {
            token          = state.push('th_open', 'th', 1);
            token.map      = [ startLine, startLine + 1 ];
            token.attrs    = [];
            if (aligns[i]) {
                token.attrs.push([ 'style', 'text-align:' + aligns[i] ]);
            }
            if (wraps[i]) {
                token.attrs.push([ 'class', '.export_wrap' ]);
            }

            token          = state.push('inline', '', 0);
            token.content  = columns[i].trim();
            token.map      = [ startLine, startLine + 1 ];
            token.children = [];

            token          = state.push('th_close', 'th', -1);
        }

        token     = state.push('tr_close', 'tr', -1);
        token     = state.push('thead_close', 'thead', -1);

        token     = state.push('tbody_open', 'tbody', 1);
        token.map = tbodyLines = [ startLine + 2, 0 ];

        for (nextLine = seperatorLine + 1; nextLine < endLine; nextLine++) {
            if (state.sCount[nextLine] < state.blkIndent) { break; }

            lineText = getLine(state, nextLine).trim();
            if (lineText.indexOf('|') === -1) { break; }
            if (state.sCount[nextLine] - state.blkIndent >= 4) { break; }
            columns = escapedSplit(lineText.replace(/^\||\|$/g, ''));
            if (columns.length === 1 && !/^\||[^\\]\|$/.test(lineText)) { break; }

            token = state.push('tr_open', 'tr', 1);
            for (i = 0; i < columnCount; i++) {
                token          = state.push('td_open', 'td', 1);
                token.attrs    = [];
                if (aligns[i]) {
                    token.attrs.push([ 'style', 'text-align:' + aligns[i] ]);
                }
                if (wraps[i]) {
                    token.attrs.push([ 'class', '.export_wrap' ]);
                }

                token          = state.push('inline', '', 0);
                token.content  = columns[i] ? columns[i].trim() : '';
                token.children = [];

                token          = state.push('td_close', 'td', -1);
            }
            token = state.push('tr_close', 'tr', -1);
        }
        token = state.push('tbody_close', 'tbody', -1);
        token = state.push('table_close', 'table', -1);

        tableLines[1] = tbodyLines[1] = nextLine;
        state.line = nextLine;
        return true;
    }
    md.block.ruler.at('table', table, { alt: [ 'paragraph', 'reference' ] });
};
<commit_msg>Minor optimized<commit_after>// Process definition lists
//
'use strict';

module.exports = function multimd_table_plugin(md) {
    function getLine(state, line) {
        var pos = state.bMarks[line] + state.blkIndent,
            max = state.eMarks[line];

        return state.src.slice(pos, max);
    }

    function escapedSplit(str) {
        var result = [],
            pos = 0,
            max = str.length,
            ch,
            escapes = 0,
            lastPos = 0,
            backTicked = false,
            lastBackTick = 0;

        ch = str.charCodeAt(pos);

        while (pos < max) {
            if (ch === 0x60/* ` */) {
                if (backTicked) {
                    // make \` close code sequence, but not open it;
                    // the reason is: `\` is correct code block
                    backTicked = false;
                    lastBackTick = pos;
                } else if ((escapes & 1) === 0) {
                    backTicked = true;
                    lastBackTick = pos;
                }
            } else if (ch === 0x7c/* | */ && (escapes & 1) === 0 && !backTicked) {
                result.push(str.slice(lastPos, pos));
                lastPos = pos + 1;
            }

            if (ch === 0x5c/* \ */) {
                escapes++;
            } else {
                escapes = 0;
            }

            pos++;

            // If there was an un-closed backtick, go back to just after
            // the last backtick, but as if it was a normal character
            if (pos === max && backTicked) {
                backTicked = false;
                pos = lastBackTick + 1;
            }

            ch = str.charCodeAt(pos);
        }

        result.push(str.slice(lastPos));

        return result;
    }

    function table(state, startLine, endLine, silent) {
        var lineText, i, seperatorLine, nextLine, columns, columnCount, token,
            aligns, wraps, t, tableLines, tbodyLines;

        // should have at least two lines
        if (startLine + 2 > endLine) { return false; }

        seperatorLine = startLine + 1;
        if (state.sCount[seperatorLine] < state.blkIndent) { return false; }
        if (state.sCount[seperatorLine] - state.blkIndent >= 4) { return false; }
        // if it's indented more than 3 spaces, it should be a code block

        lineText = getLine(state, seperatorLine);
        columns = lineText.split('|');
        if (columns.length === 1 && !/^\||[^\\]\|$/.test(lineText)) { return false; }
        aligns = [];
        wraps = [];
        for (i = 0; i < columns.length; i++) {
            t = columns[i].trim();
            if (!t) {
                // allow empty columns before and after table, but not in between columns;
                // e.g. allow ` |---| `, disallow ` ---||--- `
                if (i === 0 || i === columns.length - 1) {
                    continue;
                } else {
                    return false;
                }
            }

            if (!/^:?(-+|=+|\.+):?\+?$/.test(t)) { return false; }
            if (t.charCodeAt(t.length - 1) === 0x2B/* + */) {
                wraps.push(true);
                t = t.slice(0, -1);
            } else {
                wraps.push(false);
            }
            switch (((t.charCodeAt(0)            === 0x3A/* : */) << 4) +
                     (t.charCodeAt(t.length - 1) === 0x3A/* : */)) {
                case 0x00: aligns.push('');       break;
                case 0x01: aligns.push('right');  break;
                case 0x10: aligns.push('left');   break;
                case 0x11: aligns.push('center'); break;
            }
        }

        lineText = getLine(state, startLine).trim();
        if (lineText.indexOf('|') === -1) { return false; }
        if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
        columns = escapedSplit(lineText.replace(/^\||\|$/g, ''));

        // header row will define an amount of columns in the entire table,
        // and align row shouldn't be smaller than that (the rest of the rows can)
        columnCount = columns.length;
        if (columnCount > aligns.length) { return false; }
        if (columns.length === 1 && !/^\||[^\\]\|$/.test(lineText)) { return false; }

        if (silent) { return true; }

        token     = state.push('table_open', 'table', 1);
        token.map = tableLines = [ startLine, 0 ];

        token     = state.push('thead_open', 'thead', 1);
        token.map = [ startLine, startLine + 1 ];

        token     = state.push('tr_open', 'tr', 1);
        token.map = [ startLine, startLine + 1 ];

        for (i = 0; i < columns.length; i++) {
            token          = state.push('th_open', 'th', 1);
            token.map      = [ startLine, startLine + 1 ];
            token.attrs    = [];
            if (aligns[i]) {
                token.attrs.push([ 'style', 'text-align:' + aligns[i] ]);
            }
            if (wraps[i]) {
                token.attrs.push([ 'class', '.export_wrap' ]);
            }

            token          = state.push('inline', '', 0);
            token.content  = columns[i].trim();
            token.map      = [ startLine, startLine + 1 ];
            token.children = [];

            token          = state.push('th_close', 'th', -1);
        }

        token     = state.push('tr_close', 'tr', -1);
        token     = state.push('thead_close', 'thead', -1);

        token     = state.push('tbody_open', 'tbody', 1);
        token.map = tbodyLines = [ startLine + 2, 0 ];

        for (nextLine = seperatorLine + 1; nextLine < endLine; nextLine++) {
            if (state.sCount[nextLine] < state.blkIndent) { break; }

            lineText = getLine(state, nextLine).trim();
            if (lineText.indexOf('|') === -1) { break; }
            if (state.sCount[nextLine] - state.blkIndent >= 4) { break; }
            columns = escapedSplit(lineText.replace(/^\||\|$/g, ''));
            if (columns.length === 1 && !/^\||[^\\]\|$/.test(lineText)) { break; }

            token = state.push('tr_open', 'tr', 1);
            for (i = 0; i < columnCount; i++) {
                token          = state.push('td_open', 'td', 1);
                token.attrs    = [];
                if (aligns[i]) {
                    token.attrs.push([ 'style', 'text-align:' + aligns[i] ]);
                }
                if (wraps[i]) {
                    token.attrs.push([ 'class', '.export_wrap' ]);
                }

                token          = state.push('inline', '', 0);
                token.content  = columns[i] ? columns[i].trim() : '';
                token.children = [];

                token          = state.push('td_close', 'td', -1);
            }
            token = state.push('tr_close', 'tr', -1);
        }
        token = state.push('tbody_close', 'tbody', -1);
        token = state.push('table_close', 'table', -1);

        tableLines[1] = tbodyLines[1] = nextLine;
        state.line = nextLine;
        return true;
    }
    md.block.ruler.at('table', table, { alt: [ 'paragraph', 'reference' ] });
};
<|endoftext|>


<commit_before>'use strict';

const { name, version, homepage } = require('./package');

const urlParser = require('url');
const uuid = require('uuid/v1');
const dayjs = require('dayjs');
const debug = require('debug')(name);
const ignoredEvents = require('./lib/ignoredEvents');
const { parseRequestCookies } = require('./lib/cookies');
const { getHeaderValue, parseHeaders } = require('./lib/headers');
const {
  isHttp1x,
  formatMillis,
  parsePostData,
  isSupportedProtocol,
  toNameValuePairs
} = require('./lib/util');
const populateEntryFromResponse = require('./lib/entryFromResponse');

const defaultOptions = {
  includeResourcesFromDiskCache: false
};
const isEmpty = o => !o;

const max = Math.max;

function addFromFirstRequest(page, params) {
  if (!page.__timestamp) {
    page.__wallTime = params.wallTime;
    page.__timestamp = params.timestamp;
    page.startedDateTime = dayjs.unix(params.wallTime).toISOString(); //epoch float64, eg 1440589909.59248
    // URL is better than blank, and it's what devtools uses.
    page.title = page.title === '' ? params.request.url : page.title;
  }
}

module.exports = {
  harFromMessages(messages, options) {
    options = Object.assign({}, defaultOptions, options);

    const ignoredRequests = new Set(),
      rootFrameMappings = new Map();

    let pages = [],
      entries = [],
      entriesWithoutPage = [],
      responsesWithoutPage = [],
      paramsWithoutPage = [],
      currentPageId;

    for (const message of messages) {
      const params = message.params;

      const method = message.method;

      if (!/^(Page|Network)\..+/.test(method)) {
        continue;
      }

      switch (method) {
        case 'Page.frameStartedLoading':
        case 'Page.frameScheduledNavigation':
        case 'Page.navigatedWithinDocument':
          {
            const frameId = params.frameId;

            const rootFrame = rootFrameMappings.get(frameId) || frameId;
            if (pages.some(page => page.__frameId === rootFrame)) {
              // Navigated from Browsertime
              if (params.reason !== 'scriptInitiated') {
                continue;
              } else if (
                // This is something we've seen on Aftonbladets splash screens
                params.reason === 'scriptInitiated' &&
                params.url === 'about:blank'
              ) {
                continue;
              } else if (pages.length > 0) {
                // At the moment we only pickup the first scriptInitiated navigatoion as a page = 1 page pe JSON
                // since it makes things simpler
                continue;
              }
            }
            currentPageId = uuid();
            const title =
              method === 'Page.navigatedWithinDocument' ? params.url : '';
            const page = {
              id: currentPageId,
              startedDateTime: '',
              title: title,
              pageTimings: {},
              __frameId: rootFrame
            };
            pages.push(page);
            // do we have any unmmapped requests, add them
            if (entriesWithoutPage.length > 0) {
              // update page
              for (let entry of entriesWithoutPage) {
                entry.pageref = page.id;
              }
              entries = entries.concat(entriesWithoutPage);
              addFromFirstRequest(page, paramsWithoutPage[0]);
            }
            if (responsesWithoutPage.length > 0) {
              for (let params of responsesWithoutPage) {
                let entry = entries.find(
                  entry => entry.__requestId === params.requestId
                );
                if (entry) {
                  populateEntryFromResponse(entry, params.response, page);
                } else {
                  debug(`Couln't find matching request for response`);
                }
              }
            }
          }
          break;

        case 'Network.requestWillBeSent':
          {
            const request = params.request;
            if (!isSupportedProtocol(request.url)) {
              ignoredRequests.add(params.requestId);
              continue;
            }
            const page = pages[pages.length - 1];
            const cookieHeader = getHeaderValue(request.headers, 'Cookie');

            // Remove fragment, that's what Chrome does.
            const url = urlParser.parse(request.url, true);
            url.hash = null;

            const postData = parsePostData(
              getHeaderValue(request.headers, 'Content-Type'),
              request.postData
            );

            const req = {
              method: request.method,
              url: urlParser.format(url),
              queryString: toNameValuePairs(url.query),
              postData,
              headersSize: -1,
              bodySize: isEmpty(request.postData) ? 0 : request.postData.length,
              cookies: parseRequestCookies(cookieHeader),
              headers: parseHeaders(request.headers)
            };

            const entry = {
              cache: {},
              startedDateTime: '',
              __requestWillBeSentTime: params.timestamp,
              __wallTime: params.wallTime,
              __requestId: params.requestId,
              __frameId: params.frameId,
              _initialPriority: request.initialPriority,
              _priority: request.initialPriority,
              pageref: currentPageId,
              request: req,
              time: 0,
              _initiator_detail: JSON.stringify(params.initiator),
              _initiator_type: params.initiator.type
            };

            // The object initiator change according to its type
            switch (params.initiator.type) {
              case 'parser':
                {
                  entry._initiator = params.initiator.url;
                  entry._initiator_line = params.initiator.lineNumber + 1; // Because lineNumber is 0 based
                }
                break;

              case 'script':
                {
                  if (
                    params.initiator.stack &&
                    params.initiator.stack.callFrames.length > 0
                  ) {
                    const topCallFrame = params.initiator.stack.callFrames[0];
                    entry._initiator = topCallFrame.url;
                    entry._initiator_line = topCallFrame.lineNumber + 1; // Because lineNumber is 0 based
                    entry._initiator_column = topCallFrame.columnNumber + 1; // Because columnNumber is 0 based
                    entry._initiator_function_name = topCallFrame.functionName;
                    entry._initiator_script_id = topCallFrame.scriptId;
                  }
                }
                break;
            }

            if (params.redirectResponse) {
              const previousEntry = entries.find(
                entry => entry.__requestId === params.requestId
              );
              if (previousEntry) {
                previousEntry.__requestId += 'r';
                populateEntryFromResponse(
                  previousEntry,
                  params.redirectResponse,
                  page
                );
              } else {
                debug(
                  `Couldn't find original request for redirect response: ${
                    params.requestId
                  }`
                );
              }
            }

            if (!page) {
              debug(
                `Request will be sent with requestId ${
                  params.requestId
                } that can't be mapped to any page at the moment.`
              );
              // ignoredRequests.add(params.requestId);
              entriesWithoutPage.push(entry);
              paramsWithoutPage.push(params);
              continue;
            }

            entries.push(entry);

            // this is the first request for this page, so set timestamp of page.
            addFromFirstRequest(page, params);
            // wallTime is not necessarily monotonic, timestamp is. So calculate startedDateTime from timestamp diffs.
            // (see https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/network/ResourceLoadTiming.h?q=requestTime+package:%5Echromium$&dr=CSs&l=84)
            const entrySecs =
              page.__wallTime + (params.timestamp - page.__timestamp);
            entry.startedDateTime = dayjs.unix(entrySecs).toISOString();
          }
          break;

        case 'Network.requestServedFromCache':
          {
            if (pages.length < 1) {
              //we haven't loaded any pages yet.
              continue;
            }

            if (ignoredRequests.has(params.requestId)) {
              continue;
            }

            const entry = entries.find(
              entry => entry.__requestId === params.requestId
            );
            if (!entry) {
              debug(
                `Received requestServedFromCache for requestId ${
                  params.requestId
                } with no matching request.`
              );
              continue;
            }

            entry.__servedFromCache = true;
            entry.cache.beforeRequest = {
              lastAccess: '',
              eTag: '',
              hitCount: 0
            };
          }
          break;

        case 'Network.responseReceived':
          {
            if (pages.length < 1) {
              //we haven't loaded any pages yet.
              responsesWithoutPage.push(params);
              continue;
            }

            if (ignoredRequests.has(params.requestId)) {
              continue;
            }

            let entry = entries.find(
              entry => entry.__requestId === params.requestId
            );

            if (!entry) {
              entry = entriesWithoutPage.find(
                entry => entry.__requestId === params.requestId
              );
            }
            if (!entry) {
              debug(
                `Received network response for requestId ${
                  params.requestId
                } with no matching request.`
              );
              continue;
            }

            const frameId =
              rootFrameMappings.get(params.frameId) || params.frameId;
            const page = pages.find(page => page.__frameId === frameId);
            if (!page) {
              debug(
                `Received network response for requestId ${
                  params.requestId
                } that can't be mapped to any page.`
              );
              continue;
            }

            try {
              populateEntryFromResponse(entry, params.response, page);
            } catch (e) {
              debug(
                `Error parsing response: ${JSON.stringify(
                  params,
                  undefined,
                  2
                )}`
              );
              throw e;
            }
          }
          break;

        case 'Network.dataReceived':
          {
            if (pages.length < 1) {
              //we haven't loaded any pages yet.
              continue;
            }
            if (ignoredRequests.has(params.requestId)) {
              continue;
            }

            const entry = entries.find(
              entry => entry.__requestId === params.requestId
            );
            if (!entry) {
              debug(
                `Received network data for requestId ${
                  params.requestId
                } with no matching request.`
              );
              continue;
            }
            entry.response.content.size += params.dataLength;
          }
          break;

        case 'Network.loadingFinished':
          {
            if (pages.length < 1) {
              //we haven't loaded any pages yet.
              continue;
            }
            if (ignoredRequests.has(params.requestId)) {
              ignoredRequests.delete(params.requestId);
              continue;
            }

            const entry = entries.find(
              entry => entry.__requestId === params.requestId
            );
            if (!entry) {
              debug(
                `Network loading finished for requestId ${
                  params.requestId
                } with no matching request.`
              );
              continue;
            }

            const timings = entry.timings;
            timings.receive = formatMillis(
              (params.timestamp - entry._requestTime) * 1000 -
                entry.__receiveHeadersEnd
            );
            entry.time =
              max(0, timings.blocked) +
              max(0, timings.dns) +
              max(0, timings.connect) +
              timings.send +
              timings.wait +
              timings.receive;

            // For cached entries, Network.loadingFinished can have an earlier
            // timestamp than Network.dataReceived

            // encodedDataLength will be -1 sometimes
            if (params.encodedDataLength >= 0) {
              const response = entry.response;

              response._transferSize = params.encodedDataLength;
              response.bodySize = params.encodedDataLength;

              if (isHttp1x(response.httpVersion) && response.headersSize > -1) {
                response.bodySize -= response.headersSize;
              }

              const compression = Math.max(
                0,
                response.content.size - response.bodySize
              );
              if (compression > 0) {
                response.content.compression = compression;
              }
            }
          }
          break;

        case 'Page.loadEventFired':
          {
            if (pages.length < 1) {
              //we haven't loaded any pages yet.
              continue;
            }

            const page = pages[pages.length - 1];

            if (params.timestamp && page.__timestamp) {
              page.pageTimings.onLoad = formatMillis(
                (params.timestamp - page.__timestamp) * 1000
              );
            }
          }
          break;

        case 'Page.domContentEventFired':
          {
            if (pages.length < 1) {
              //we haven't loaded any pages yet.
              continue;
            }

            const page = pages[pages.length - 1];

            if (params.timestamp && page.__timestamp) {
              page.pageTimings.onContentLoad = formatMillis(
                (params.timestamp - page.__timestamp) * 1000
              );
            }
          }
          break;

        case 'Page.frameAttached':
          {
            const frameId = params.frameId,
              parentId = params.parentFrameId;

            rootFrameMappings.set(frameId, parentId);

            let grandParentId = rootFrameMappings.get(parentId);
            while (grandParentId) {
              rootFrameMappings.set(frameId, grandParentId);
              grandParentId = rootFrameMappings.get(grandParentId);
            }
          }
          break;

        case 'Network.loadingFailed':
          {
            if (ignoredRequests.has(params.requestId)) {
              ignoredRequests.delete(params.requestId);
              continue;
            }

            const entry = entries.find(
              entry => entry.__requestId === params.requestId
            );
            if (!entry) {
              debug(
                `Network loading failed for requestId ${
                  params.requestId
                } with no matching request.`
              );
              continue;
            }

            // This could be due to incorrect domain name etc. Sad, but unfortunately not something that a HAR file can
            // represent.
            debug(
              `Failed to load url '${entry.request.url}' (canceled: ${
                params.canceled
              })`
            );
            entries = entries.filter(
              entry => entry.__requestId !== params.requestId
            );
          }
          break;

        case 'Network.resourceChangedPriority':
          {
            const entry = entries.find(
              entry => entry.__requestId === params.requestId
            );

            if (!entry) {
              debug(
                `Received resourceChangedPriority for requestId ${
                  params.requestId
                } with no matching request.`
              );
              continue;
            }

            entry._priority = message.params.newPriority;
          }
          break;

        default:
          // Keep the old functionallity and log unknown events
          ignoredEvents(method);
          break;
      }
    }

    if (!options.includeResourcesFromDiskCache) {
      entries = entries.filter(
        entry => entry.cache.beforeRequest === undefined
      );
    }

    const deleteInternalProperties = o => {
      // __ properties are only for internal use, _ properties are custom properties for the HAR
      for (const prop in o) {
        if (prop.startsWith('__')) {
          delete o[prop];
        }
      }
      return o;
    };

    entries = entries
      .filter(entry => {
        if (!entry.response) {
          debug(`Dropping incomplete request: ${entry.request.url}`);
        }
        return entry.response;
      })
      .map(deleteInternalProperties);
    pages = pages.map(deleteInternalProperties);
    pages = pages.reduce((result, page, index) => {
      const hasEntry = entries.some(entry => entry.pageref === page.id);
      if (hasEntry) {
        result.push(page);
      } else {
        debug(`Skipping empty page: ${index + 1}`);
      }
      return result;
    }, []);
    const pagerefMapping = pages.reduce((result, page, index) => {
      result[page.id] = `page_${index + 1}`;
      return result;
    }, {});

    pages = pages.map(page => {
      page.id = pagerefMapping[page.id];
      return page;
    });
    entries = entries.map(entry => {
      entry.pageref = pagerefMapping[entry.pageref];
      return entry;
    });

    // FIXME sanity check if there are any pages/entries created

    return {
      log: {
        version: '1.2',
        creator: { name, version, comment: homepage },
        pages,
        entries
      }
    };
  }
};
<commit_msg>simplify logic<commit_after>'use strict';

const { name, version, homepage } = require('./package');

const urlParser = require('url');
const uuid = require('uuid/v1');
const dayjs = require('dayjs');
const debug = require('debug')(name);
const ignoredEvents = require('./lib/ignoredEvents');
const { parseRequestCookies } = require('./lib/cookies');
const { getHeaderValue, parseHeaders } = require('./lib/headers');
const {
  isHttp1x,
  formatMillis,
  parsePostData,
  isSupportedProtocol,
  toNameValuePairs
} = require('./lib/util');
const populateEntryFromResponse = require('./lib/entryFromResponse');

const defaultOptions = {
  includeResourcesFromDiskCache: false
};
const isEmpty = o => !o;

const max = Math.max;

function addFromFirstRequest(page, params) {
  if (!page.__timestamp) {
    page.__wallTime = params.wallTime;
    page.__timestamp = params.timestamp;
    page.startedDateTime = dayjs.unix(params.wallTime).toISOString(); //epoch float64, eg 1440589909.59248
    // URL is better than blank, and it's what devtools uses.
    page.title = page.title === '' ? params.request.url : page.title;
  }
}

module.exports = {
  harFromMessages(messages, options) {
    options = Object.assign({}, defaultOptions, options);

    const ignoredRequests = new Set(),
      rootFrameMappings = new Map();

    let pages = [],
      entries = [],
      entriesWithoutPage = [],
      responsesWithoutPage = [],
      paramsWithoutPage = [],
      currentPageId;

    for (const message of messages) {
      const params = message.params;

      const method = message.method;

      if (!/^(Page|Network)\..+/.test(method)) {
        continue;
      }

      switch (method) {
        case 'Page.frameStartedLoading':
        case 'Page.frameScheduledNavigation':
        case 'Page.navigatedWithinDocument':
          {
            const frameId = params.frameId;
            const rootFrame = rootFrameMappings.get(frameId) || frameId;
            if (pages.some(page => page.__frameId === rootFrame)) {
              continue;
            }
            currentPageId = uuid();
            const title =
              method === 'Page.navigatedWithinDocument' ? params.url : '';
            const page = {
              id: currentPageId,
              startedDateTime: '',
              title: title,
              pageTimings: {},
              __frameId: rootFrame
            };
            pages.push(page);
            // do we have any unmmapped requests, add them
            if (entriesWithoutPage.length > 0) {
              // update page
              for (let entry of entriesWithoutPage) {
                entry.pageref = page.id;
              }
              entries = entries.concat(entriesWithoutPage);
              addFromFirstRequest(page, paramsWithoutPage[0]);
            }
            if (responsesWithoutPage.length > 0) {
              for (let params of responsesWithoutPage) {
                let entry = entries.find(
                  entry => entry.__requestId === params.requestId
                );
                if (entry) {
                  populateEntryFromResponse(entry, params.response, page);
                } else {
                  debug(`Couln't find matching request for response`);
                }
              }
            }
          }
          break;

        case 'Network.requestWillBeSent':
          {
            const request = params.request;
            if (!isSupportedProtocol(request.url)) {
              ignoredRequests.add(params.requestId);
              continue;
            }
            const page = pages[pages.length - 1];
            const cookieHeader = getHeaderValue(request.headers, 'Cookie');

            // Remove fragment, that's what Chrome does.
            const url = urlParser.parse(request.url, true);
            url.hash = null;

            const postData = parsePostData(
              getHeaderValue(request.headers, 'Content-Type'),
              request.postData
            );

            const req = {
              method: request.method,
              url: urlParser.format(url),
              queryString: toNameValuePairs(url.query),
              postData,
              headersSize: -1,
              bodySize: isEmpty(request.postData) ? 0 : request.postData.length,
              cookies: parseRequestCookies(cookieHeader),
              headers: parseHeaders(request.headers)
            };

            const entry = {
              cache: {},
              startedDateTime: '',
              __requestWillBeSentTime: params.timestamp,
              __wallTime: params.wallTime,
              __requestId: params.requestId,
              __frameId: params.frameId,
              _initialPriority: request.initialPriority,
              _priority: request.initialPriority,
              pageref: currentPageId,
              request: req,
              time: 0,
              _initiator_detail: JSON.stringify(params.initiator),
              _initiator_type: params.initiator.type
            };

            // The object initiator change according to its type
            switch (params.initiator.type) {
              case 'parser':
                {
                  entry._initiator = params.initiator.url;
                  entry._initiator_line = params.initiator.lineNumber + 1; // Because lineNumber is 0 based
                }
                break;

              case 'script':
                {
                  if (
                    params.initiator.stack &&
                    params.initiator.stack.callFrames.length > 0
                  ) {
                    const topCallFrame = params.initiator.stack.callFrames[0];
                    entry._initiator = topCallFrame.url;
                    entry._initiator_line = topCallFrame.lineNumber + 1; // Because lineNumber is 0 based
                    entry._initiator_column = topCallFrame.columnNumber + 1; // Because columnNumber is 0 based
                    entry._initiator_function_name = topCallFrame.functionName;
                    entry._initiator_script_id = topCallFrame.scriptId;
                  }
                }
                break;
            }

            if (params.redirectResponse) {
              const previousEntry = entries.find(
                entry => entry.__requestId === params.requestId
              );
              if (previousEntry) {
                previousEntry.__requestId += 'r';
                populateEntryFromResponse(
                  previousEntry,
                  params.redirectResponse,
                  page
                );
              } else {
                debug(
                  `Couldn't find original request for redirect response: ${
                    params.requestId
                  }`
                );
              }
            }

            if (!page) {
              debug(
                `Request will be sent with requestId ${
                  params.requestId
                } that can't be mapped to any page at the moment.`
              );
              // ignoredRequests.add(params.requestId);
              entriesWithoutPage.push(entry);
              paramsWithoutPage.push(params);
              continue;
            }

            entries.push(entry);

            // this is the first request for this page, so set timestamp of page.
            addFromFirstRequest(page, params);
            // wallTime is not necessarily monotonic, timestamp is. So calculate startedDateTime from timestamp diffs.
            // (see https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/network/ResourceLoadTiming.h?q=requestTime+package:%5Echromium$&dr=CSs&l=84)
            const entrySecs =
              page.__wallTime + (params.timestamp - page.__timestamp);
            entry.startedDateTime = dayjs.unix(entrySecs).toISOString();
          }
          break;

        case 'Network.requestServedFromCache':
          {
            if (pages.length < 1) {
              //we haven't loaded any pages yet.
              continue;
            }

            if (ignoredRequests.has(params.requestId)) {
              continue;
            }

            const entry = entries.find(
              entry => entry.__requestId === params.requestId
            );
            if (!entry) {
              debug(
                `Received requestServedFromCache for requestId ${
                  params.requestId
                } with no matching request.`
              );
              continue;
            }

            entry.__servedFromCache = true;
            entry.cache.beforeRequest = {
              lastAccess: '',
              eTag: '',
              hitCount: 0
            };
          }
          break;

        case 'Network.responseReceived':
          {
            if (pages.length < 1) {
              //we haven't loaded any pages yet.
              responsesWithoutPage.push(params);
              continue;
            }

            if (ignoredRequests.has(params.requestId)) {
              continue;
            }

            let entry = entries.find(
              entry => entry.__requestId === params.requestId
            );

            if (!entry) {
              entry = entriesWithoutPage.find(
                entry => entry.__requestId === params.requestId
              );
            }
            if (!entry) {
              debug(
                `Received network response for requestId ${
                  params.requestId
                } with no matching request.`
              );
              continue;
            }

            const frameId =
              rootFrameMappings.get(params.frameId) || params.frameId;
            const page = pages.find(page => page.__frameId === frameId);
            if (!page) {
              debug(
                `Received network response for requestId ${
                  params.requestId
                } that can't be mapped to any page.`
              );
              continue;
            }

            try {
              populateEntryFromResponse(entry, params.response, page);
            } catch (e) {
              debug(
                `Error parsing response: ${JSON.stringify(
                  params,
                  undefined,
                  2
                )}`
              );
              throw e;
            }
          }
          break;

        case 'Network.dataReceived':
          {
            if (pages.length < 1) {
              //we haven't loaded any pages yet.
              continue;
            }
            if (ignoredRequests.has(params.requestId)) {
              continue;
            }

            const entry = entries.find(
              entry => entry.__requestId === params.requestId
            );
            if (!entry) {
              debug(
                `Received network data for requestId ${
                  params.requestId
                } with no matching request.`
              );
              continue;
            }
            entry.response.content.size += params.dataLength;
          }
          break;

        case 'Network.loadingFinished':
          {
            if (pages.length < 1) {
              //we haven't loaded any pages yet.
              continue;
            }
            if (ignoredRequests.has(params.requestId)) {
              ignoredRequests.delete(params.requestId);
              continue;
            }

            const entry = entries.find(
              entry => entry.__requestId === params.requestId
            );
            if (!entry) {
              debug(
                `Network loading finished for requestId ${
                  params.requestId
                } with no matching request.`
              );
              continue;
            }

            const timings = entry.timings;
            timings.receive = formatMillis(
              (params.timestamp - entry._requestTime) * 1000 -
                entry.__receiveHeadersEnd
            );
            entry.time =
              max(0, timings.blocked) +
              max(0, timings.dns) +
              max(0, timings.connect) +
              timings.send +
              timings.wait +
              timings.receive;

            // For cached entries, Network.loadingFinished can have an earlier
            // timestamp than Network.dataReceived

            // encodedDataLength will be -1 sometimes
            if (params.encodedDataLength >= 0) {
              const response = entry.response;

              response._transferSize = params.encodedDataLength;
              response.bodySize = params.encodedDataLength;

              if (isHttp1x(response.httpVersion) && response.headersSize > -1) {
                response.bodySize -= response.headersSize;
              }

              const compression = Math.max(
                0,
                response.content.size - response.bodySize
              );
              if (compression > 0) {
                response.content.compression = compression;
              }
            }
          }
          break;

        case 'Page.loadEventFired':
          {
            if (pages.length < 1) {
              //we haven't loaded any pages yet.
              continue;
            }

            const page = pages[pages.length - 1];

            if (params.timestamp && page.__timestamp) {
              page.pageTimings.onLoad = formatMillis(
                (params.timestamp - page.__timestamp) * 1000
              );
            }
          }
          break;

        case 'Page.domContentEventFired':
          {
            if (pages.length < 1) {
              //we haven't loaded any pages yet.
              continue;
            }

            const page = pages[pages.length - 1];

            if (params.timestamp && page.__timestamp) {
              page.pageTimings.onContentLoad = formatMillis(
                (params.timestamp - page.__timestamp) * 1000
              );
            }
          }
          break;

        case 'Page.frameAttached':
          {
            const frameId = params.frameId,
              parentId = params.parentFrameId;

            rootFrameMappings.set(frameId, parentId);

            let grandParentId = rootFrameMappings.get(parentId);
            while (grandParentId) {
              rootFrameMappings.set(frameId, grandParentId);
              grandParentId = rootFrameMappings.get(grandParentId);
            }
          }
          break;

        case 'Network.loadingFailed':
          {
            if (ignoredRequests.has(params.requestId)) {
              ignoredRequests.delete(params.requestId);
              continue;
            }

            const entry = entries.find(
              entry => entry.__requestId === params.requestId
            );
            if (!entry) {
              debug(
                `Network loading failed for requestId ${
                  params.requestId
                } with no matching request.`
              );
              continue;
            }

            // This could be due to incorrect domain name etc. Sad, but unfortunately not something that a HAR file can
            // represent.
            debug(
              `Failed to load url '${entry.request.url}' (canceled: ${
                params.canceled
              })`
            );
            entries = entries.filter(
              entry => entry.__requestId !== params.requestId
            );
          }
          break;

        case 'Network.resourceChangedPriority':
          {
            const entry = entries.find(
              entry => entry.__requestId === params.requestId
            );

            if (!entry) {
              debug(
                `Received resourceChangedPriority for requestId ${
                  params.requestId
                } with no matching request.`
              );
              continue;
            }

            entry._priority = message.params.newPriority;
          }
          break;

        default:
          // Keep the old functionallity and log unknown events
          ignoredEvents(method);
          break;
      }
    }

    if (!options.includeResourcesFromDiskCache) {
      entries = entries.filter(
        entry => entry.cache.beforeRequest === undefined
      );
    }

    const deleteInternalProperties = o => {
      // __ properties are only for internal use, _ properties are custom properties for the HAR
      for (const prop in o) {
        if (prop.startsWith('__')) {
          delete o[prop];
        }
      }
      return o;
    };

    entries = entries
      .filter(entry => {
        if (!entry.response) {
          debug(`Dropping incomplete request: ${entry.request.url}`);
        }
        return entry.response;
      })
      .map(deleteInternalProperties);
    pages = pages.map(deleteInternalProperties);
    pages = pages.reduce((result, page, index) => {
      const hasEntry = entries.some(entry => entry.pageref === page.id);
      if (hasEntry) {
        result.push(page);
      } else {
        debug(`Skipping empty page: ${index + 1}`);
      }
      return result;
    }, []);
    const pagerefMapping = pages.reduce((result, page, index) => {
      result[page.id] = `page_${index + 1}`;
      return result;
    }, {});

    pages = pages.map(page => {
      page.id = pagerefMapping[page.id];
      return page;
    });
    entries = entries.map(entry => {
      entry.pageref = pagerefMapping[entry.pageref];
      return entry;
    });

    // FIXME sanity check if there are any pages/entries created

    return {
      log: {
        version: '1.2',
        creator: { name, version, comment: homepage },
        pages,
        entries
      }
    };
  }
};
<|endoftext|>


<commit_before>var util = require('util'),
    colors = require('colors');

module.exports = function (silent) {
  function getTimeStamp () {
    var x = new Date();

    var m = x.getMinutes(),
        s = x.getSeconds();

    return '{}/{}/{} {}:{}:{}'
      .format(x.getFullYear(), x.getMonth() + 1, x.getDate(), x.getHours(),
              m > 10 ? m : '0' + m, s > 10 ? s : '0' + s);
  }

  function stringifyArgs (args) {
    var str = '';
    for (var key in args) {
      if (typeof args[key] == 'object') {
        str += util.inspect(args[key]) + '\n';
      } else {
        str += args[key] + ' ';
      }
    }
    return str;
  }

  function getCallingMethod () {
    return new Error().stack.split('\n')[3].trim();
  }

  var logging = {};

  /**
   * Log arguments on the `info` logging level
   * @name info
   * @function
   */
  logging.info = function () {
    if (silent) return;
    console.info(colors.cyan.bold('[{}] Info {}'.format(getTimeStamp(), getCallingMethod())));
    console.info(colors.cyan(stringifyArgs(arguments)), '\n');
  };

  /**
   * Log arguments on the `warn` logging level
   * @name warn
   * @function
   */
  logging.warn = function () {
    if (silent) return;
    console.warn(colors.yellow.bold('[{}] Warning {}'.format(getTimeStamp(), getCallingMethod())));
    console.warn(colors.yellow(stringifyArgs(arguments)), '\n');
  };

  /**
   * Log arguments on the default logging level
   * @name log
   * @function
   */
  logging.log = function () {
    if (silent) return;
    console.log(colors.white.bold('[{}] Log {}'.format(getTimeStamp(), getCallingMethod())));
    console.log(colors.white(stringifyArgs(arguments)), '\n');
  };

  /**
   * Log arguments on the `error` logging level
   * @name error
   * @function
   */
  logging.error = function () {
    if (silent) return;
    console.error(colors.red.bold('[{}] Error {}'.format(getTimeStamp(), getCallingMethod())));
    console.error(colors.red(stringifyArgs(arguments)), '\n');
  };

  return logging;
};
<commit_msg>Remove silent flag<commit_after>var util = require('util'),
    colors = require('colors');

module.exports = (function () {
  function getTimeStamp () {
    var x = new Date();

    var m = x.getMinutes(),
        s = x.getSeconds();

    return '{}/{}/{} {}:{}:{}'
      .format(x.getFullYear(), x.getMonth() + 1, x.getDate(), x.getHours(),
              m > 10 ? m : '0' + m, s > 10 ? s : '0' + s);
  }

  function stringifyArgs (args) {
    var str = '';
    for (var key in args) {
      if (typeof args[key] == 'object') {
        str += util.inspect(args[key]) + '\n';
      } else {
        str += args[key] + ' ';
      }
    }
    return str;
  }

  function getCallingMethod () {
    return new Error().stack.split('\n')[3].trim();
  }

  var logging = {};

  /**
   * Log arguments on the `info` logging level
   * @name info
   * @function
   */
  logging.info = function () {
    console.info(colors.cyan.bold('[{}] Info {}'.format(getTimeStamp(), getCallingMethod())));
    console.info(colors.cyan(stringifyArgs(arguments)), '\n');
  };

  /**
   * Log arguments on the `warn` logging level
   * @name warn
   * @function
   */
  logging.warn = function () {
    console.warn(colors.yellow.bold('[{}] Warning {}'.format(getTimeStamp(), getCallingMethod())));
    console.warn(colors.yellow(stringifyArgs(arguments)), '\n');
  };

  /**
   * Log arguments on the default logging level
   * @name log
   * @function
   */
  logging.log = function () {
    console.log(colors.white.bold('[{}] Log {}'.format(getTimeStamp(), getCallingMethod())));
    console.log(colors.white(stringifyArgs(arguments)), '\n');
  };

  /**
   * Log arguments on the `error` logging level
   * @name error
   * @function
   */
  logging.error = function () {
    console.error(colors.red.bold('[{}] Error {}'.format(getTimeStamp(), getCallingMethod())));
    console.error(colors.red(stringifyArgs(arguments)), '\n');
  };

  return logging;
})();
<|endoftext|>


<commit_before>var google = require('googleapis')
  , request = require('request')
  , validUrl = require('valid-url')
  , apiVersion
  , pagespeedUrl
  , pagespeedonline
  ;

module.exports = function(opts, callback){

  if(!opts.key && !opts.nokey){
    return callback(new Error('Missing required param: key'), null);
  }

  if(!opts.url){
    return callback(new Error('Missing required param: url'), null);
  }

  if(opts.url && !validUrl.isWebUri(opts.url)){
    return callback(new Error('Invalid url'), null);
  }

  apiVersion = opts.apiversion || 'v1';

  if(opts.userequest){
    pagespeedUrl = 'https://www.googleapis.com/pagespeedonline/' + apiVersion + '/runPagespeed';
    request(pagespeedUrl, {qs:opts}, function(error, response, body){
      if(error){
        return callback(error, null);
      } else {
        return callback(null, body.toString());
      }
    })
  } else {
    pagespeedonline = google.pagespeedonline(apiVersion);
    pagespeedonline.pagespeedapi.runpagespeed(opts, function(error, req){
      if(error){
        return callback(error, null);
      }
      return callback(null, req);
    });
  }
};<commit_msg>Switches to v2 as default apiVersion<commit_after>var google = require('googleapis')
  , request = require('request')
  , validUrl = require('valid-url')
  , apiVersion
  , pagespeedUrl
  , pagespeedonline
  ;

module.exports = function(opts, callback){

  if(!opts.key && !opts.nokey){
    return callback(new Error('Missing required param: key'), null);
  }

  if(!opts.url){
    return callback(new Error('Missing required param: url'), null);
  }

  if(opts.url && !validUrl.isWebUri(opts.url)){
    return callback(new Error('Invalid url'), null);
  }

  apiVersion = opts.apiversion || 'v2';

  if(opts.userequest){
    pagespeedUrl = 'https://www.googleapis.com/pagespeedonline/' + apiVersion + '/runPagespeed';
    request(pagespeedUrl, {qs:opts}, function(error, response, body){
      if(error){
        return callback(error, null);
      } else {
        return callback(null, body.toString());
      }
    })
  } else {
    pagespeedonline = google.pagespeedonline(apiVersion);
    pagespeedonline.pagespeedapi.runpagespeed(opts, function(error, req){
      if(error){
        return callback(error, null);
      }
      return callback(null, req);
    });
  }
};<|endoftext|>


<commit_before>var es = require('event-stream');
var Handlebars = require('ember-handlebars');
var Emblem = require('emblem');
var path = require('path');
var extend = require('xtend');

// Return a declaration and namespace name for output
var getNSInfo = function(ns, omitLast) {
  var output = [];
  var curPath = 'this';
  if (ns !== 'this') {
    var nsParts = ns.split('.');
    nsParts.some(function(curPart, index) {
      if (curPart !== 'this') {
        curPath += '[' + JSON.stringify(curPart) + ']';

        // Ignore the last part of the namespace, it will be used for assignment
        if (omitLast && index === nsParts.length - 1) {
          return true;
        }
        else {
          output.push(curPath + ' = ' + curPath + ' || {};');
        }
      }
    });
  }

  return {
    namespace: curPath,
    pathParts: output,
    declaration: output.join('')
  };
};

// Default name processing function should give the filename without extension
var defaultProcessName = function(name) { return path.basename(name, path.extname(name)); };

module.exports = function(options) {
  options = extend({
    compilerOptions: {},
    declareNamespace: true,
    wrapped: true,
    outputType: 'browser', // browser, amd, commonjs, node, hybrid, bare
    processName: defaultProcessName,
    namespace: 'Ember.TEMPLATES',
    ember: true
  }, options);

  // Never declare namespaces if not provided
  if (!options.namespace) {
    options.declareNamespace = false;
  }

  var compileHandlebars = function(file, callback) {
    // Get the name of the template
    var name = options.processName(file.path);

    // Perform pre-compilation
    try {
      var compiled = Emblem.precompile(Handlebars, file.contents.toString(), options.compilerOptions);
    }
    catch(err) {
      return callback(err, file);
    }

    if (options.wrapped) {
      if (options.ember) {
        compiled = 'Ember.Handlebars.template('+compiled+')';
      }
      else {
        compiled = 'Handlebars.template('+compiled+')';
      }
    }

    // Handle different output times
    if (options.outputType === 'browser' || options.outputType === 'hybrid') {
      // Prepend namespace to name
      if (options.namespace !== false) {
        name = options.namespace+'.'+name;
      }

      // Get namespace information for the final template name
      var nameNSInfo = getNSInfo(name, true);

      if (options.outputType === 'hybrid') {
        var templateDef = compiled;

        compiled = "(function(g) {";
        compiled += "var Handlebars = g.Handlebars || require('handlebars');";

        if (options.declareNamespace) {
          compiled += nameNSInfo.declaration+compiled;
        }

        compiled += "var template = "+templateDef+";"
        compiled += "if (typeof exports === 'object' && exports) module.exports = template;";
        compiled += nameNSInfo.namespace+' = template;';
        compiled += "}(typeof window !== 'undefined' ? window : global));";
      }
      else {
        // Add assignment
        compiled = nameNSInfo.namespace+' = '+compiled+';';

        if (options.declareNamespace) {
          // Tack on namespace declaration, if necessary
          compiled = nameNSInfo.declaration+compiled;
        }
      }
    }
    else if (options.outputType === 'amd') {
      compiled = "define(['handlebars'], function(Handlebars) {return "+compiled+";});";
    }
    else if (options.outputType === 'commonjs') {
      compiled = "module.exports = function(Handlebars) {return "+compiled+";};";
    }
    else if (options.outputType === 'node') {
      compiled = "module.exports = "+compiled+";";
      compiled = "var Handlebars = global.Handlebars || require('handlebars');"+compiled;
    }
    else if (options.outputType !== 'bare') {
      callback(new Error('Invalid output type: '+options.outputType), file);
    }

    file.path = path.join(path.dirname(file.path), name+'.js');
    file.contents = new Buffer(compiled);

    callback(null, file);
  };

  return es.map(compileHandlebars);
};
<commit_msg>Namespace templates according to directory they're in<commit_after>var es = require('event-stream');
var Handlebars = require('ember-handlebars');
var Emblem = require('emblem');
var path = require('path');
var extend = require('xtend');

// Return a declaration and namespace name for output
var getNSInfo = function(ns, omitLast) {
  var output = [];
  var curPath = 'this';
  if (ns !== 'this') {
    var nsParts = ns.split('.');
    nsParts.some(function(curPart, index) {
      if (curPart !== 'this') {
        curPath += '[' + JSON.stringify(curPart) + ']';

        // Ignore the last part of the namespace, it will be used for assignment
        if (omitLast && index === nsParts.length - 1) {
          return true;
        }
        else {
          output.push(curPath + ' = ' + curPath + ' || {};');
        }
      }
    });
  }

  return {
    namespace: curPath,
    pathParts: output,
    declaration: output.join('')
  };
};

// Default name processing function should give the filename without extension
var defaultProcessName = function(name) { return path.basename(name, path.extname(name)); };

module.exports = function(options) {
  options = extend({
    compilerOptions: {},
    declareNamespace: true,
    wrapped: true,
    outputType: 'browser', // browser, amd, commonjs, node, hybrid, bare
    processName: defaultProcessName,
    namespace: 'Ember.TEMPLATES',
    ember: true
  }, options);

  // Never declare namespaces if not provided
  if (!options.namespace) {
    options.declareNamespace = false;
  }

  var compileHandlebars = function(file, callback) {
    // Get the name of the template
    // The name is namespaced to the directory that the file is in
    var name = path.relative(file.cwd, file.path)
      .slice(0, -path.extname(file.path).length)
      .split(path.sep);
    name = name.slice(2, name.length).join('/');

    // Perform pre-compilation
    try {
      var compiled = Emblem.precompile(Handlebars, file.contents.toString(), options.compilerOptions);
    }
    catch(err) {
      return callback(err, file);
    }

    if (options.wrapped) {
      if (options.ember) {
        compiled = 'Ember.Handlebars.template('+compiled+')';
      }
      else {
        compiled = 'Handlebars.template('+compiled+')';
      }
    }

    // Handle different output times
    if (options.outputType === 'browser' || options.outputType === 'hybrid') {
      // Prepend namespace to name
      if (options.namespace !== false) {
        name = options.namespace+'.'+name;
      }

      // Get namespace information for the final template name
      var nameNSInfo = getNSInfo(name, true);

      if (options.outputType === 'hybrid') {
        var templateDef = compiled;

        compiled = "(function(g) {";
        compiled += "var Handlebars = g.Handlebars || require('handlebars');";

        if (options.declareNamespace) {
          compiled += nameNSInfo.declaration+compiled;
        }

        compiled += "var template = "+templateDef+";"
        compiled += "if (typeof exports === 'object' && exports) module.exports = template;";
        compiled += nameNSInfo.namespace+' = template;';
        compiled += "}(typeof window !== 'undefined' ? window : global));";
      }
      else {
        // Add assignment
        compiled = nameNSInfo.namespace+' = '+compiled+';';

        if (options.declareNamespace) {
          // Tack on namespace declaration, if necessary
          compiled = nameNSInfo.declaration+compiled;
        }
      }
    }
    else if (options.outputType === 'amd') {
      compiled = "define(['handlebars'], function(Handlebars) {return "+compiled+";});";
    }
    else if (options.outputType === 'commonjs') {
      compiled = "module.exports = function(Handlebars) {return "+compiled+";};";
    }
    else if (options.outputType === 'node') {
      compiled = "module.exports = "+compiled+";";
      compiled = "var Handlebars = global.Handlebars || require('handlebars');"+compiled;
    }
    else if (options.outputType !== 'bare') {
      callback(new Error('Invalid output type: '+options.outputType), file);
    }

    file.path = path.join(path.dirname(file.path), name+'.js');
    file.contents = new Buffer(compiled);

    callback(null, file);
  };

  return es.map(compileHandlebars);
};
<|endoftext|>


<commit_before>'use strict'

const build = require('./lib/perform')
const buildBlogPages = require('./lib/blog')
const buildSass = require('./lib/sass')
const homePage = require('./src/js/pages/home')
const optimizeHtml = require('./lib/html')
const { chain } = require('ramda')
const Task = require('data.task')

let css =

buildSass('src/sass', 'src/sass/app.scss')
  .map(x => css = x)
  .chain(_ => buildBlogPages('src/blog'))
  .chain(posts => {
    return build({
      outputDir: 'docs',
      copyable: [
        { from: 'src/fonts', to: 'docs/fonts' },
        { from: 'src/images', to: 'docs/images' },
        { from: 'src/CNAME', to: 'docs/CNAME' },
        { from: 'src/favicon.ico', to: 'docs/favicon.ico' }
      ],
      writable: [
        { path: 'docs/index.html', content: optimizeHtml(homePage({ posts })) },
        { path: 'docs/styles.css', content: css }
      ].concat(posts.map(x => {
        return { path: `docs${x.metadata.relativePath}`, content: optimizeHtml(x.content) }
      }))
    })
  })
  .fork(
    err => console.error('Error: ', err),
    data => console.log('Build succeeded:', data)
  )
<commit_msg>Fix mutation thing<commit_after>'use strict'

const build = require('./lib/perform')
const buildBlogPages = require('./lib/blog')
const buildSass = require('./lib/sass')
const homePage = require('./src/js/pages/home')
const optimizeHtml = require('./lib/html')

// Mutation hack
let css = ''

buildSass('src/sass', 'src/sass/app.scss')
  .map(x => css = x)
  .chain(_ => buildBlogPages('src/blog'))
  .chain(posts => {
    return build({
      outputDir: 'docs',
      copyable: [
        { from: 'src/fonts', to: 'docs/fonts' },
        { from: 'src/images', to: 'docs/images' },
        { from: 'src/CNAME', to: 'docs/CNAME' },
        { from: 'src/favicon.ico', to: 'docs/favicon.ico' }
      ],
      writable: [
        { path: 'docs/index.html', content: optimizeHtml(homePage({ posts })) },
        { path: 'docs/styles.css', content: css }
      ].concat(posts.map(x => {
        return { path: `docs${x.metadata.relativePath}`, content: optimizeHtml(x.content) }
      }))
    })
  })
  .fork(
    err => console.error('Error: ', err),
    data => console.log('Build succeeded:', data)
  )
<|endoftext|>


<commit_before>var exec = require('child_process').exec,
    spawn = require('child_process').spawn,
    chalk = require('chalk'),
    path = require('path'),
    EventEmitter = require('events').EventEmitter,
    util = require('util'),
    ATTRIBUTES = 'username host sshKey'.split(/\s+/),
    DEBUG = true;

function debug() {
    if (DEBUG) {
        console.log.apply(console, [chalk.underline.green('DEBUG:') + ' '].concat(Array.prototype.slice.call(arguments)));
    }
};

function RemoteExec() {
    this.queue = [];
    this.ctx = {};
};

util.inherits(RemoteExec, EventEmitter);

// define setters
ATTRIBUTES.forEach(function(attribute) {
    RemoteExec.prototype[attribute] = function(val) {
        return this.ctx[attribute] = val;
    };
});

RemoteExec.prototype.remote = function() {
    return this.ctx.username + '@' + this.ctx.host;
};

RemoteExec.prototype.exec = function(cmd, callback) {
    this.queue.push(new Task({
        cmd: cmd,
        ctx: this.ctx,
        callback: callback
    }));
    this.start();
};

RemoteExec.prototype.start = function() {
    if (!this.isRunning) {
        this.emit('start');
        debug('start');
        this.isRunning = true;
        this.callNext();
    }
};

RemoteExec.prototype.stop = function() {
    debug('stop');
    this.isRunning = false;
    this.emit('finish');
};

RemoteExec.prototype.callNext = function() {
    var _this = this;

    setTimeout(function() {
        var task = _this.queue.shift();
        if (!task) {
            return _this.stop();
        }
        task.run(function(err) {
            if (err) {
                throw err;
            }
            _this.callNext();
        });
    }, 5);
};

function Task(options) {
    this.type = options.type;
    this.cmd = options.cmd;
    this.ctx = options.ctx
}

Task.prototype.run = function(done) {
    var cmd = 'ssh';
    args = [
        this.ctx.username + '@' + this.ctx.host,
        '-q',
        this.cmd
    ];
    console.log(cmd, args);
    console.log(chalk.underline.cyan('executing:'), this.cmd);
    var child = spawn(cmd, args);
    child.stdout.pipe(process.stdout);
    child.stderr.pipe(process.stderr);
    child.on('close', function(code) {
        done();
    });
};

module.exports = RemoteExec;
<commit_msg>Immutable context<commit_after>var exec = require('child_process').exec,
    spawn = require('child_process').spawn,
    chalk = require('chalk'),
    path = require('path'),
    EventEmitter = require('events').EventEmitter,
    Immutable = require('immutable'),
    util = require('util'),
    ATTRIBUTES = [
        'username',
        'host',
        'sshKey'
    ],
    DEBUG = true;

function debug() {
    if (DEBUG) {
        console.log.apply(console, [chalk.underline.green('DEBUG:') + ' '].concat(Array.prototype.slice.call(arguments)));
    }
};

/*
 * @constructor
 */
function RemoteExec() {
    this.queue = [];
    // Context of task execution. Immutable
    this.ctx = Immutable.Map({});
};

util.inherits(RemoteExec, EventEmitter);

// define setter
RemoteExec.prototype.set = function(k, v) {
    this.ctx = this.ctx.set(k, v);
};

RemoteExec.prototype.exec = function(cmd, callback) {
    this.queue.push(new Task({
        cmd: cmd,
        ctx: this.ctx,
        callback: callback
    }));
    this.start();
};

RemoteExec.prototype.start = function() {
    if (!this.isRunning) {
        this.emit('start');
        debug('start');
        this.isRunning = true;
        this.callNext();
    }
};

RemoteExec.prototype.stop = function() {
    debug('stop');
    this.isRunning = false;
    this.emit('finish');
};

RemoteExec.prototype.callNext = function() {
    var _this = this;

    setTimeout(function() {
        var task = _this.queue.shift();
        if (!task) {
            return _this.stop();
        }
        task.run(function(err) {
            if (err) {
                throw err;
            }
            _this.callNext();
        });
    }, 5);
};

function Task(options) {
    this.type = options.type;
    this.cmd = options.cmd;
    this.ctx = options.ctx
}

Task.prototype.run = function(done) {
    var cmd = 'ssh',
        userAndHost;
    if (this.ctx.get('username')) {
        userAndHost = this.ctx.get('username') + '@' + this.ctx.get('host');
    } else {
        userAndHost = this.ctx.get('host');
    }
    args = [
        userAndHost,
        '-q',
        this.cmd
    ];
    console.log(cmd, args);
    console.log(chalk.underline.cyan('executing:'), this.cmd);
    var child = spawn(cmd, args);
    child.stdout.pipe(process.stdout);
    child.stderr.pipe(process.stderr);
    child.on('close', function(code) {
        done();
    });
};

module.exports = RemoteExec;
<|endoftext|>


<commit_before>'use strict';

var reg = /%(?:(\d+)\$|\((\w+)\))?([+ #-]*)('(.)|0)?((?:\d|\*)+)?(?:\.([\d*]*))?([bdiuoxXfFeEgGaAcsp%])/g;

function repeat(str, num) {
	if (num < 0) {
		return '';
	}
	return new Array(num + 1).join(str);
}

function paddLeft(str, length, what) {
	if (length <= str.length) {
		return str.substring(0, length);
	}
	what = what || ' ';
	return repeat(what, length - str.length) + str;
}

function paddRight(str, length, what) {
	if (length <= str.length) {
		return str.substring(0, length);
	}
	what = what || ' ';
	return str + repeat(what, length - str.length);
}

function contains(str, what) {
	return str.indexOf(what) !== -1;
}

var types = {
	number: 0,
	string: 1
};

function precBase(base, value, precision) {
	var val = value.toString(base);
	var floatingPoint = val.indexOf('.');
	return val.substring(0, floatingPoint + precision + 1);
}

var specifiers = {
	d: {
		transform: function(a) { return a | 0; },
		allowSign: true,
		type: types.number
	},
	u: {
		transform: function(a) { return a >>> 0; },
		allowSign: true,
		type: types.number
	},
	o: {
		transform: function(a) { return a.toString(8); },
		prefix: '0',
		type: types.number
	},
	x: {
		transform: function(a) { return Math.floor(a).toString(16); },
		prefix: '0x',
		type: types.number
	},
	X: {
		transform: function(a) { return specifiers.x.transform(a).toUpperCase(); },
		prefix: '0X',
		type: types.number
	},
	f: {
		transform: function(a, b) { return precBase(10, a.toLocaleString(), b); },
		allowSign: true,
		type: types.number
	},
	F: {
		transform: function(a, b) { return a.toFixed(b); },
		allowSign: true,
		type: types.number
	},
	e: {
		transform: function(a, b) { return a.toExponential(b); },
		allowSign: true
	},
	E: {
		transform: function(a, b) { return specifiers.e.transform(a, b).toUpperCase(); },
		allowSign: true,
		type: types.number
	},
	g: {
		transform: function(a, b) { return a.toPrecision(b); },
		allowSign: true,
		type: types.number
	},
	G: {
		transform: function(a, b) { return specifiers.g.transform(a, b).toUpperCase(); },
		allowSign: true,
		type: types.number
	},
	a: {
		transform: function(a, b) {
			return precBase(16, a, b) + 'p0';
		},
		allowSign: true,
		prefix: '0x',
		type: types.number
	},
	A: {
		transform: function(a, b) { return specifiers.a.transform(a, b).toUpperCase(); },
		allowSign: true,
		prefix: '0X',
		type: types.number
	},
	c: {
		transform: String.fromCharCode
	},
	s: {
		type: types.string
	},
	b: {
		transform: function(a, b) { return precBase(2, a, b); },
		type: types.number
	}
};

specifiers.i = specifiers.d;

function esprintf(formatString) {
	var valueIdx = 1;
	var parentArguments = arguments;
	var isAssoc = arguments[1] instanceof Object;
	// jshint maxparams:10
	return formatString.replace(reg,
		function(wholeMatch, reference, assocReference, flags, zeroPadding, customPadding, width, precision, type) {
		// jshint maxparams: 4
		if (type === '%') {
			return '%';
		}
		reference = parseInt(reference) || valueIdx;

		flags = flags || '';

		var leftJustify = contains(flags, '-');
		var forceSign = contains(flags, '+');
		var blankFill = contains(flags, ' ');
		var forcePrecisionOrPrefix = contains(flags, '#');

		customPadding = customPadding || zeroPadding;

		var padding = customPadding || ' ';

		var value;

		if (isAssoc) {
			if (!assocReference) {
				throw new Error('Cannot use associative parameters mixed with non associative');
			}
			value = parentArguments[1][assocReference];
			if (value === undefined) {
				throw new Error('No value for format parameter \'' + assocReference + '\'');
			}
		} else {
			if (assocReference) {
				throw new Error('Cannot use associative parameters mixed with non associative');
			}
			value = parentArguments[valueIdx++];
		}

		if (width === '*') {
			width = parentArguments[valueIdx++];

			if (width === undefined) {
				throw new Error('No value for dynamic width for parameter no. ' + (reference - 2));
			}
		} else {
			width = parseInt(width);
			if (!width) {
				width = value.length;
			}
		}

		precision = parseInt(precision) || 6;
		if (precision === '*') {
			precision = parentArguments[valueIdx++];
			if (precision === undefined) {
				throw new Error('No value for dynamic precision for parameter no. ' + (reference - 3));
			}
		}

		var specifier = specifiers[type];
		if (!specifier) {
			throw new Error('Unsupport identified \'' + type + '\'');
		}

		if (value === undefined) {
			throw new Error('No value for format parameter no. ' + (reference - 1));
		}

		if (specifier.type === types.number && !parseInt(value)) {
			throw new TypeError('Invalid value for format parameter no. ' + (reference - 1) + ' expected number, got string');
		}
		var ret = specifier.transform ? specifier.transform(value, precision) : value;
		var allowSign = specifier.allowSign;
		var prefix = specifier.prefix;

		var fullPrefix = (forcePrecisionOrPrefix ? prefix : '') +
		(
			(forceSign && allowSign === '+' && value > 0) ? '+' : (
				(value < 0) ? '-' : (blankFill ? ' ' : '')
			)
		);

		var method = leftJustify ? paddRight : paddLeft;

		if (padding === '0') {
			return fullPrefix + method(ret, width, '0');
		}
		return method(fullPrefix + ret, width, padding);
	});
}

module.exports = esprintf;
<commit_msg>Fixed a few length related bugs, added more tests<commit_after>'use strict';

function repeat(str, num) {
	if (num < 0) {
		return '';
	}

	return new Array(num + 1).join(str);
}

function paddLeft(str, length, what) {
	if (length <= str.length) {
		return str.substring(0, length);
	}
	what = what || ' ';
	return repeat(what, length - str.length) + str;
}

function paddRight(str, length, what) {
	if (length <= str.length) {
		return str.substring(0, length);
	}
	what = what || ' ';
	return str + repeat(what, length - str.length);
}

function contains(str, what) {
	return str.indexOf(what) !== -1;
}

var types = {
	number: 0,
	string: 1
};

function precBase(base, value, precision) {
	var val = value.toString(base);
	var floatingPoint = val.indexOf('.');
	return val.substring(0, floatingPoint + precision + 1);
}

var specifiers = {
	d: {
		transform: function(a) { return a | 0; },
		allowSign: true,
		type: types.number
	},
	u: {
		transform: function(a) { return a >>> 0; },
		allowSign: true,
		type: types.number
	},
	o: {
		transform: function(a) { return a.toString(8); },
		prefix: '0',
		type: types.number
	},
	x: {
		transform: function(a) { return Math.floor(a).toString(16); },
		prefix: '0x',
		type: types.number
	},
	X: {
		transform: function(a) { return specifiers.x.transform(a).toUpperCase(); },
		prefix: '0X',
		type: types.number
	},
	f: {
		transform: function(a, b) { return precBase(10, a.toLocaleString(), b); },
		allowSign: true,
		type: types.number
	},
	F: {
		transform: function(a, b) { return a.toFixed(b); },
		allowSign: true,
		type: types.number
	},
	e: {
		transform: function(a, b) { return a.toExponential(b); },
		allowSign: true
	},
	E: {
		transform: function(a, b) { return specifiers.e.transform(a, b).toUpperCase(); },
		allowSign: true,
		type: types.number
	},
	g: {
		transform: function(a, b) { return a.toPrecision(b); },
		allowSign: true,
		type: types.number
	},
	G: {
		transform: function(a, b) { return specifiers.g.transform(a, b).toUpperCase(); },
		allowSign: true,
		type: types.number
	},
	a: {
		transform: function(a, b) {
			return precBase(16, a, b) + 'p0';
		},
		allowSign: true,
		prefix: '0x',
		type: types.number
	},
	A: {
		transform: function(a, b) { return specifiers.a.transform(a, b).toUpperCase(); },
		allowSign: true,
		prefix: '0X',
		type: types.number
	},
	c: {
		transform: String.fromCharCode
	},
	s: {
		type: types.string
	},
	b: {
		transform: function(a, b) { return precBase(2, a, b); },
		type: types.number
	}
};

specifiers.i = specifiers.d;

var reg = /%(?:(\d+)\$|\((\w+)\))?([+ #-]*)('(.)|0)?((?:\d|\*)+)?(?:\.([\d*]*))?([bdiuoxXfFeEgGaAcsp%])/g;

function esprintf(formatString) {
	var valueIdx = 1;
	var parentArguments = arguments;
	var isAssoc = arguments[1] instanceof Object;
	// jshint maxparams:10
	return formatString.replace(reg,
		function(wholeMatch, reference, assocReference, flags, zeroPadding, customPadding, width, precision, type) {
		// jshint maxparams: 4
		if (type === '%') {
			return '%';
		}
		reference = parseInt(reference) || valueIdx;

		flags = flags || '';

		var leftJustify = contains(flags, '-');
		var forceSign = contains(flags, '+');
		var blankFill = contains(flags, ' ');
		var forcePrecisionOrPrefix = contains(flags, '#');

		customPadding = customPadding || zeroPadding;

		var padding = customPadding || ' ';

		var value;

		if (isAssoc) {
			if (!assocReference) {
				throw new Error('Cannot use associative parameters mixed with non associative');
			}
			value = parentArguments[1][assocReference];
			if (value === undefined) {
				throw new Error('No value for format parameter \'' + assocReference + '\'');
			}
		} else {
			if (assocReference) {
				throw new Error('Cannot use associative parameters mixed with non associative');
			}
			value = parentArguments[valueIdx++];
		}

		if (width === '*') {
			width = parentArguments[valueIdx++];

			if (width === undefined) {
				throw new Error('No value for dynamic width for parameter no. ' + (reference - 2));
			}
		} else {
			width = parseInt(width);
		}

		precision = parseInt(precision) || 6;
		if (precision === '*') {
			precision = parentArguments[valueIdx++];
			if (precision === undefined) {
				throw new Error('No value for dynamic precision for parameter no. ' + (reference - 3));
			}
		}

		var specifier = specifiers[type];
		if (!specifier) {
			throw new Error('Unsupport identified \'' + type + '\'');
		}

		if (value === undefined) {
			throw new Error('No value for format parameter no. ' + (reference - 1));
		}

		if (specifier.type === types.number && !parseInt(value)) {
			throw new TypeError('Invalid value for format parameter no. ' + (reference - 1) + ' expected number, got string');
		}
		var ret = specifier.transform ? specifier.transform(value, precision) : value;

		var allowSign = specifier.allowSign;
		var prefix = specifier.prefix;

		ret = ret.toString();

		var fullPrefix = (forcePrecisionOrPrefix ? prefix : '') +
		(
			(forceSign && allowSign && value > 0) ? '+' : (
				(value < 0) ? '-' : (blankFill ? ' ' : '')
			)
		);

		if (width !== undefined && width === width) {
			var method = leftJustify ? paddRight : paddLeft;

			if (padding === '0') {
				return fullPrefix + method(ret, width, '0');
			}
			return method(fullPrefix + ret, width, padding);
		}
		return fullPrefix + ret;
	});
}

module.exports = esprintf;
<|endoftext|>


<commit_before>/**
 * Created by nuintun on 2015/10/16.
 */

'use strict';

var is = require('is');
var pedding = require('pedding');
var through = require('through');
var duplexer = require('duplexer');
var Stream = require('stream').Stream;

/**
 * turn switch
 * @param selector
 * @param chunk
 * @returns {*}
 */
function turnSwitch(selector, chunk){
  if (is.fn(selector)) {
    return selector(chunk);
  }

  return selector;
}

/**
 * do write
 * @param stream
 * @param chunk
 * @param next
 */
function doWrite(stream, chunk, next){
  if (stream.write(chunk)) {
    next();
  } else {
    stream.once('drain', next);
  }
}

/**
 * stream switch
 * @param selector
 * @param cases
 * @param options
 * @returns {Duplexer|*}
 */
module.exports = function (selector, cases, options){
  options = options || { objectMode: true };

  var flags = [];
  var streams = [];
  var output = through(options);

  for (var flag in cases) {
    if (cases.hasOwnProperty(flag)) {
      var stream = cases[flag];

      if (!(stream instanceof Stream))
        throw new TypeError(flag + ' is not a stream');

      streams.push(stream);
      flags.push(flag);
    }
  }

  // stream end when all read ends
  var end = pedding(streams.length, function (){
    output.end();
  });

  // bind events
  streams.forEach(function (stream){
    stream.on('error', function (error){
      output.emit('error', error);
    });
    stream.once('end', end);
    stream.pipe(output, { end: false });
  });

  /**
   * input ---(unmatch)-------->--、
   * `---(caseA)----> streamA --->-、
   * `---(caseB)----> streamB ------> output
   */
  var input = through(function (chunk, encoding, next){
    var flag = turnSwitch(selector, chunk);
    var index = flags.indexOf(flag);

    if (index !== -1) {
      doWrite(streams[index], chunk, next);
    } else {
      doWrite(output, chunk, next);
    }
  }, function (next){
    streams.forEach(function (stream){
      stream.end();
    });
    next();
  });

  input.pipe(output, { end: false });

  return duplexer(options, input, output);
};
module.exports.through = through;
module.exports.duplexer = duplexer;
<commit_msg>use private npm module<commit_after>/**
 * Created by nuintun on 2015/10/16.
 */

'use strict';

var is = require('is');
var pedding = require('pedding');
var through = require('@nuintun/through');
var duplexer = require('@nuintun/duplexer');
var Stream = require('stream').Stream;

/**
 * turn switch
 * @param selector
 * @param chunk
 * @returns {*}
 */
function turnSwitch(selector, chunk){
  if (is.fn(selector)) {
    return selector(chunk);
  }

  return selector;
}

/**
 * do write
 * @param stream
 * @param chunk
 * @param next
 */
function doWrite(stream, chunk, next){
  if (stream.write(chunk)) {
    next();
  } else {
    stream.once('drain', next);
  }
}

/**
 * stream switch
 * @param selector
 * @param cases
 * @param options
 * @returns {Duplexer|*}
 */
module.exports = function (selector, cases, options){
  options = options || { objectMode: true };

  var flags = [];
  var streams = [];
  var output = through(options);

  for (var flag in cases) {
    if (cases.hasOwnProperty(flag)) {
      var stream = cases[flag];

      if (!(stream instanceof Stream))
        throw new TypeError(flag + ' is not a stream');

      streams.push(stream);
      flags.push(flag);
    }
  }

  // stream end when all read ends
  var end = pedding(streams.length, function (){
    output.end();
  });

  // bind events
  streams.forEach(function (stream){
    stream.on('error', function (error){
      output.emit('error', error);
    });
    stream.once('end', end);
    stream.pipe(output, { end: false });
  });

  /**
   * input ---(unmatch)-------->--、
   * `---(caseA)----> streamA --->-、
   * `---(caseB)----> streamB ------> output
   */
  var input = through(function (chunk, encoding, next){
    var flag = turnSwitch(selector, chunk);
    var index = flags.indexOf(flag);

    if (index !== -1) {
      doWrite(streams[index], chunk, next);
    } else {
      doWrite(output, chunk, next);
    }
  }, function (next){
    streams.forEach(function (stream){
      stream.end();
    });
    next();
  });

  input.pipe(output, { end: false });

  return duplexer(options, input, output);
};
module.exports.through = through;
module.exports.duplexer = duplexer;
<|endoftext|>


<commit_before>'use strict';
const fs = require('fs');
const path = require('path');
const color = require('color');
const yaml = require('js-yaml');

const filepaths = {
  backgrounds: path.resolve(__dirname, 'backgrounds'),
  gifs: path.resolve(__dirname, 'pokecursors')
};

const colorSchemes = {
  types: path.resolve(__dirname, 'types.yml'),
  pokemon: path.resolve(__dirname, 'pokemon.yml'),
  trainers: path.resolve(__dirname, 'trainers.yml')
};

function getUserOptions(configObj) {
  return Object.assign({}, {
    get pokemon() {
      if (Array.isArray(configObj.pokemon)) {
        return configObj.pokemon[Math.floor(Math.random() * configObj.pokemon.length)];
      }
      return configObj.pokemon || 'pikachu';
    },
    get poketab() {
      return (configObj.poketab || 'false') === 'true';
    },
    get unibody() {
      return (configObj.unibody || 'true') !== 'false';
    }
  });
}

function getRandomTheme(category) {
  const index = Math.floor(Math.random() * (Object.keys(category).length));
  const name = Object.keys(category)[index];
  return [name, category[name]];
}

function getThemes() {
  const themes = {};
  Object.keys(colorSchemes).forEach(category => {
    Object.assign(themes, yaml.safeLoad(fs.readFileSync(colorSchemes[category], 'utf8')));
  });
  return themes;
}

function getThemeColors(theme) {
  const themes = getThemes();
  const name = theme.trim().toLowerCase();
  if (name === 'random') {
    return getRandomTheme(themes.pokemon);
  }
  if (Object.prototype.hasOwnProperty.call(themes, name)) {
    // Choose a random theme from the given category -- i.e. `fire`
    return getRandomTheme(themes[name]);
  }
  if (Object.prototype.hasOwnProperty.call(themes.pokemon, name)) {
    // Return the requested pokemon theme -- i.e. `lapras`
    return [name, themes.pokemon[name]];
  }
  // Got non-existent theme name thus resolve to default
  return ['pikachu', themes.pokemon.pikachu];
}

function getMediaPaths(theme) {
  const [imagePath, gifPath] = [[], []];
  imagePath.push(...[path.join(filepaths.backgrounds, theme), '.png']);
  gifPath.push(...[path.join(filepaths.gifs, theme), '.gif']);
  if (process.platform === 'win32') {
    return [imagePath, gifPath].map(item => item.join('').replace(/\\/g, '/'));
  }
  return [imagePath.join(''), gifPath.join('')];
}

exports.decorateConfig = config => {
  // Get user options
  const options = getUserOptions(config);
  const [themeName, colors] = getThemeColors(options.pokemon);
  const [imagePath, gifPath] = getMediaPaths(themeName);

  // Set theme colors
  const {primary, secondary, tertiary, unibody} = colors;
  const background = options.unibody ? unibody : primary;
  const selection = color(primary).alpha(0.3).string();
  const transparent = color(secondary).alpha(0).string();
  const header = color(background).isDark() ? '#FAFAFA' : '#010101';
  const activeTab = color(secondary).isDark() ? '#FAFAFA' : '#383A42';
  const tab = color(activeTab).darken(0.1);

  // Set poketab
  const tabContent = options.poketab ? gifPath : '';

  const syntax = {
    backgroundColor: transparent,
    borderColor: background,
    cursorColor: secondary,
    foregroundColor: secondary,
    selectionColor: selection,
    colors: {
      black: tertiary,
      red: secondary,
      green: tertiary,
      yellow: secondary,
      blue: secondary,
      magenta: secondary,
      cyan: secondary,
      white: secondary,
      lightBlack: tertiary,
      lightRed: secondary,
      lightGreen: secondary,
      lightYellow: secondary,
      lightBlue: secondary,
      lightMagenta: secondary,
      lightCyan: secondary,
      lightWhite: secondary
    }
  };

  return Object.assign({}, config, syntax, {
    termCSS: config.termCSS || '',
    css: `
      ${config.css || ''}
      .terms_terms {
        background: url("file://${imagePath}") center;
        background-size: cover;
      }
      .header_shape, .header_appTitle {
        color: ${header};
      }
      .header_header, .header_windowHeader {
        background-color: ${background} !important;
      }
      .tab_textActive .tab_textInner::before {
        content: url("file://${tabContent}");
        position: absolute;
        right: 0;
        top: -4px;
      }
      .tabs_nav .tabs_list {
        border-bottom: 0;
      }
      .tabs_nav .tabs_title,
      .tabs_nav .tabs_list .tab_tab {
        color: ${secondary};
        border: 0;
      }
      .tab_icon {
        color: ${background};
        width: 15px;
        height: 15px;
      }
      .tab_icon:hover {
        background-color: ${background};
      }
      .tab_shape {
        color: ${secondary};
        width: 7px;
        height: 7px;
      }
      .tab_shape:hover {
        color: ${secondary};
      }
      .tab_active {
        background-color: ${activeTab};
      }
      .tabs_nav .tabs_list .tab_tab:not(.tab_active) {
        background-color: ${tab};
      }
      .tabs_nav .tabs_list {
        color: ${background};
      }
      .tab_tab::before {
        content: '';
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        height: 4px;
        background-color: ${secondary};
        transform: scaleX(0);
        transition: none;
      }
      .tab_tab.tab_active::before {
        transform: scaleX(1);
        transition: all 400ms cubic-bezier(0.0, 0.0, 0.2, 1)
      }
      .terms_terms .terms_termGroup .splitpane_panes .splitpane_divider {
        background-color: ${secondary} !important;
      }
    `
  });
};
<commit_msg>Removed white top-border when maximizing window<commit_after>'use strict';
const fs = require('fs');
const path = require('path');
const color = require('color');
const yaml = require('js-yaml');

const filepaths = {
  backgrounds: path.resolve(__dirname, 'backgrounds'),
  gifs: path.resolve(__dirname, 'pokecursors')
};

const colorSchemes = {
  types: path.resolve(__dirname, 'types.yml'),
  pokemon: path.resolve(__dirname, 'pokemon.yml'),
  trainers: path.resolve(__dirname, 'trainers.yml')
};

function getUserOptions(configObj) {
  return Object.assign({}, {
    get pokemon() {
      if (Array.isArray(configObj.pokemon)) {
        return configObj.pokemon[Math.floor(Math.random() * configObj.pokemon.length)];
      }
      return configObj.pokemon || 'pikachu';
    },
    get poketab() {
      return (configObj.poketab || 'false') === 'true';
    },
    get unibody() {
      return (configObj.unibody || 'true') !== 'false';
    }
  });
}

function getRandomTheme(category) {
  const index = Math.floor(Math.random() * (Object.keys(category).length));
  const name = Object.keys(category)[index];
  return [name, category[name]];
}

function getThemes() {
  const themes = {};
  Object.keys(colorSchemes).forEach(category => {
    Object.assign(themes, yaml.safeLoad(fs.readFileSync(colorSchemes[category], 'utf8')));
  });
  return themes;
}

function getThemeColors(theme) {
  const themes = getThemes();
  const name = theme.trim().toLowerCase();
  if (name === 'random') {
    return getRandomTheme(themes.pokemon);
  }
  if (Object.prototype.hasOwnProperty.call(themes, name)) {
    // Choose a random theme from the given category -- i.e. `fire`
    return getRandomTheme(themes[name]);
  }
  if (Object.prototype.hasOwnProperty.call(themes.pokemon, name)) {
    // Return the requested pokemon theme -- i.e. `lapras`
    return [name, themes.pokemon[name]];
  }
  // Got non-existent theme name thus resolve to default
  return ['pikachu', themes.pokemon.pikachu];
}

function getMediaPaths(theme) {
  const [imagePath, gifPath] = [[], []];
  imagePath.push(...[path.join(filepaths.backgrounds, theme), '.png']);
  gifPath.push(...[path.join(filepaths.gifs, theme), '.gif']);
  if (process.platform === 'win32') {
    return [imagePath, gifPath].map(item => item.join('').replace(/\\/g, '/'));
  }
  return [imagePath.join(''), gifPath.join('')];
}

exports.decorateConfig = config => {
  // Get user options
  const options = getUserOptions(config);
  const [themeName, colors] = getThemeColors(options.pokemon);
  const [imagePath, gifPath] = getMediaPaths(themeName);

  // Set theme colors
  const {primary, secondary, tertiary, unibody} = colors;
  const background = options.unibody ? unibody : primary;
  const selection = color(primary).alpha(0.3).string();
  const transparent = color(secondary).alpha(0).string();
  const header = color(background).isDark() ? '#FAFAFA' : '#010101';
  const activeTab = color(secondary).isDark() ? '#FAFAFA' : '#383A42';
  const tab = color(activeTab).darken(0.1);

  // Set poketab
  const tabContent = options.poketab ? gifPath : '';

  const syntax = {
    backgroundColor: transparent,
    borderColor: background,
    cursorColor: secondary,
    foregroundColor: secondary,
    selectionColor: selection,
    colors: {
      black: tertiary,
      red: secondary,
      green: tertiary,
      yellow: secondary,
      blue: secondary,
      magenta: secondary,
      cyan: secondary,
      white: secondary,
      lightBlack: tertiary,
      lightRed: secondary,
      lightGreen: secondary,
      lightYellow: secondary,
      lightBlue: secondary,
      lightMagenta: secondary,
      lightCyan: secondary,
      lightWhite: secondary
    }
  };

  return Object.assign({}, config, syntax, {
    termCSS: config.termCSS || '',
    css: `
      ${config.css || ''}
      .terms_terms {
        background: url("file://${imagePath}") center;
        background-size: cover;
      }
      .header_shape, .header_appTitle {
        color: ${header};
      }
      .header_header, .header_windowHeader {
        background-color: ${background} !important;
      }
     .hyper_main {
        background-color: ${background};
      }
      .tab_textActive .tab_textInner::before {
        content: url("file://${tabContent}");
        position: absolute;
        right: 0;
        top: -4px;
      }
      .tabs_nav .tabs_list {
        border-bottom: 0;
      }
      .tabs_nav .tabs_title,
      .tabs_nav .tabs_list .tab_tab {
        color: ${secondary};
        border: 0;
      }
      .tab_icon {
        color: ${background};
        width: 15px;
        height: 15px;
      }
      .tab_icon:hover {
        background-color: ${background};
      }
      .tab_shape {
        color: ${secondary};
        width: 7px;
        height: 7px;
      }
      .tab_shape:hover {
        color: ${secondary};
      }
      .tab_active {
        background-color: ${activeTab};
      }
      .tabs_nav .tabs_list .tab_tab:not(.tab_active) {
        background-color: ${tab};
      }
      .tabs_nav .tabs_list {
        color: ${background};
      }
      .tab_tab::before {
        content: '';
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        height: 4px;
        background-color: ${secondary};
        transform: scaleX(0);
        transition: none;
      }
      .tab_tab.tab_active::before {
        transform: scaleX(1);
        transition: all 400ms cubic-bezier(0.0, 0.0, 0.2, 1)
      }
      .terms_terms .terms_termGroup .splitpane_panes .splitpane_divider {
        background-color: ${secondary} !important;
      }
    `
  });
};
<|endoftext|>