<commit_before>import { Readable } from "stream";
import fs from "fs";
import path from "path";
import SVGIcons2SVGFontStream from "svgicons2svgfont";
import cosmiconfig from "cosmiconfig";
import pLimit from "p-limit";
import defaultMetadataProvider from "svgicons2svgfont/src/metadata";
import fileSorter from "svgicons2svgfont/src/filesorter";
import globby from "globby";
import deepmerge from "deepmerge";
import nunjucks from "nunjucks";
import svg2ttf from "svg2ttf";
import ttf2eot from "ttf2eot";
import ttf2woff from "ttf2woff";
import wawoff2 from "wawoff2";
import xml2js from "xml2js";

async function buildConfig(options) {
  let searchPath = process.cwd();
  let configPath = null;

  if (options.configFile) {
    searchPath = null;
    configPath = path.resolve(process.cwd(), options.configFile);
  }

  const configExplorer = cosmiconfig("webfont");
  const config = await (configPath
    ? configExplorer.load(configPath)
    : configExplorer.search(searchPath));

  if (!config) {
    return {};
  }

  return config;
}

function getGlyphsData(files, options) {
  const metadataProvider =
    options.metadataProvider ||
    defaultMetadataProvider({
      prependUnicode: options.prependUnicode,
      startUnicode: options.startUnicode
    });

  const xmlParser = new xml2js.Parser();
  const throttle = pLimit(options.maxConcurrency);

  return Promise.all(
    files.map(srcPath =>
      throttle(
        () =>
          new Promise((resolve, reject) => {
            const glyph = fs.createReadStream(srcPath);
            let glyphContents = "";

            return glyph
              .on("error", glyphError => reject(glyphError))
              .on("data", data => {
                glyphContents += data.toString();
              })
              .on("end", () => {
                // Maybe bug in xml2js
                if (glyphContents.length === 0) {
                  return reject(new Error(`Empty file ${srcPath}`));
                }

                return xmlParser.parseString(glyphContents, error => {
                  if (error) {
                    return reject(error);
                  }

                  const glyphData = {
                    contents: glyphContents,
                    srcPath
                  };

                  return resolve(glyphData);
                });
              });
          })
      )
    )
  ).then(glyphsData => {
    const sortedGlyphsData = options.sort
      ? glyphsData.sort((fileA, fileB) =>
          fileSorter(fileA.srcPath, fileB.srcPath)
        )
      : glyphsData;

    return Promise.all(
      sortedGlyphsData.map(
        glyphData =>
          new Promise((resolve, reject) => {
            metadataProvider(glyphData.srcPath, (error, metadata) => {
              if (error) {
                return reject(error);
              }

              glyphData.metadata = metadata;

              return resolve(glyphData);
            });
          })
      )
    );
  });
}

function toSvg(glyphsData, options) {
  let result = "";

  return new Promise((resolve, reject) => {
    const fontStream = new SVGIcons2SVGFontStream({
      ascent: options.ascent,
      centerHorizontally: options.centerHorizontally,
      descent: options.descent,
      fixedWidth: options.fixedWidth,
      fontHeight: options.fontHeight,
      fontId: options.fontId,
      fontName: options.fontName,
      fontStyle: options.fontStyle,
      fontWeight: options.fontWeight,
      // eslint-disable-next-line no-console, no-empty-function
      log: options.verbose ? console.log.bind(console) : () => {},
      metadata: options.metadata,
      normalize: options.normalize,
      round: options.round
    })
      .on("finish", () => resolve(result))
      .on("data", data => {
        result += data;
      })
      .on("error", error => reject(error));

    glyphsData.forEach(glyphData => {
      const glyphStream = new Readable();

      glyphStream.push(glyphData.contents);
      glyphStream.push(null);

      glyphStream.metadata = glyphData.metadata;

      fontStream.write(glyphStream);
    });

    fontStream.end();
  });
}

function toTtf(buffer, options) {
  return Buffer.from(svg2ttf(buffer, options).buffer);
}

function toEot(buffer) {
  return Buffer.from(ttf2eot(buffer).buffer);
}

function toWoff(buffer, options) {
  return Buffer.from(ttf2woff(buffer, options).buffer);
}

function toWoff2(buffer) {
  return wawoff2.compress(buffer);
}

export default async function(initialOptions) {
  if (!initialOptions || !initialOptions.files) {
    throw new Error("You must pass webfont a `files` glob");
  }

  let options = Object.assign(
    {},
    {
      ascent: undefined, // eslint-disable-line no-undefined
      centerHorizontally: false,
      descent: 0,
      fixedWidth: false,
      fontHeight: null,
      fontId: null,
      fontName: "webfont",
      fontStyle: "",
      fontWeight: "",
      formats: ["svg", "ttf", "eot", "woff", "woff2"],
      formatsOptions: {
        ttf: {
          copyright: null,
          ts: null,
          version: null
        }
      },
      glyphTransformFn: null,
      // Maybe allow setup from CLI
      // This is usually less than file read maximums while staying performance
      maxConcurrency: 100,
      metadata: null,
      metadataProvider: null,
      normalize: false,
      prependUnicode: false,
      round: 10e12,
      sort: true,
      startUnicode: 0xea01,
      template: null,
      templateClassName: null,
      templateFontName: null,
      templateFontPath: "./",
      verbose: false
    },
    initialOptions
  );

  const config = await buildConfig({
    configFile: options.configFile
  });

  if (Object.keys(config).length > 0) {
    options = deepmerge(options, config.config, {
      arrayMerge: (_destinationArray, sourceArray, _opts) => sourceArray
    });
    options.filePath = config.filepath;
  }

  const foundFiles = await globby([].concat(options.files));
  const filteredFiles = foundFiles.filter(
    foundFile => path.extname(foundFile) === ".svg"
  );

  if (filteredFiles.length === 0) {
    throw new Error("Files glob patterns specified did not match any files");
  }

  const result = {};

  result.glyphsData = await getGlyphsData(filteredFiles, options);
  result.svg = await toSvg(result.glyphsData, options);
  result.ttf = toTtf(
    result.svg,
    options.formatsOptions && options.formatsOptions.ttf
      ? options.formatsOptions.ttf
      : {}
  );

  if (options.formats.includes("eot")) {
    result.eot = toEot(result.ttf);
  }

  if (options.formats.includes("woff")) {
    result.woff = toWoff(result.ttf, { metadata: options.metadata });
  }

  if (options.formats.includes("woff2")) {
    result.woff2 = await toWoff2(result.ttf);
  }

  if (options.template) {
    const templateDirectory = path.resolve(__dirname, "../templates");
    const buildInTemplates = {
      css: { path: path.join(templateDirectory, "template.css.njk") },
      html: { path: path.join(templateDirectory, "template.html.njk") },
      scss: { path: path.join(templateDirectory, "template.scss.njk") },
      styl: { path: path.join(templateDirectory, "template.styl.njk") }
    };

    // eslint-disable-next-line init-declarations
    let templateFilePath;

    if (Object.keys(buildInTemplates).includes(options.template)) {
      result.usedBuildInTemplate = true;

      nunjucks.configure(path.resolve(__dirname, "../"));

      templateFilePath = `${templateDirectory}/template.${
        options.template
      }.njk`;
    } else {
      const resolvedTemplateFilePath = path.resolve(options.template);

      nunjucks.configure(path.dirname(resolvedTemplateFilePath));

      templateFilePath = path.resolve(resolvedTemplateFilePath);
    }

    const nunjucksOptions = deepmerge.all([
      {
        glyphs: result.glyphsData.map(glyphData => {
          if (typeof options.glyphTransformFn === "function") {
            glyphData.metadata = options.glyphTransformFn(glyphData.metadata);
          }

          return glyphData.metadata;
        })
      },
      options,
      {
        className: options.templateClassName || options.fontName,
        fontName: options.templateFontName || options.fontName,
        fontPath: options.templateFontPath.replace(/\/?$/, "/")
      }
    ]);

    result.template = nunjucks.render(templateFilePath, nunjucksOptions);
  }

  if (!options.formats.includes("svg")) {
    delete result.svg;
  }

  if (!options.formats.includes("ttf")) {
    delete result.ttf;
  }

  result.config = options;

  return result;
}
<commit_msg>style(standalone): ignore `require-atomic-updates` errors, remove unneeded ignore<commit_after>import { Readable } from "stream";
import fs from "fs";
import path from "path";
import SVGIcons2SVGFontStream from "svgicons2svgfont";
import cosmiconfig from "cosmiconfig";
import pLimit from "p-limit";
import defaultMetadataProvider from "svgicons2svgfont/src/metadata";
import fileSorter from "svgicons2svgfont/src/filesorter";
import globby from "globby";
import deepmerge from "deepmerge";
import nunjucks from "nunjucks";
import svg2ttf from "svg2ttf";
import ttf2eot from "ttf2eot";
import ttf2woff from "ttf2woff";
import wawoff2 from "wawoff2";
import xml2js from "xml2js";

async function buildConfig(options) {
  let searchPath = process.cwd();
  let configPath = null;

  if (options.configFile) {
    searchPath = null;
    configPath = path.resolve(process.cwd(), options.configFile);
  }

  const configExplorer = cosmiconfig("webfont");
  const config = await (configPath
    ? configExplorer.load(configPath)
    : configExplorer.search(searchPath));

  if (!config) {
    return {};
  }

  return config;
}

function getGlyphsData(files, options) {
  const metadataProvider =
    options.metadataProvider ||
    defaultMetadataProvider({
      prependUnicode: options.prependUnicode,
      startUnicode: options.startUnicode
    });

  const xmlParser = new xml2js.Parser();
  const throttle = pLimit(options.maxConcurrency);

  return Promise.all(
    files.map(srcPath =>
      throttle(
        () =>
          new Promise((resolve, reject) => {
            const glyph = fs.createReadStream(srcPath);
            let glyphContents = "";

            // eslint-disable-next-line no-promise-executor-return
            return glyph
              .on("error", glyphError => reject(glyphError))
              .on("data", data => {
                glyphContents += data.toString();
              })
              .on("end", () => {
                // Maybe bug in xml2js
                if (glyphContents.length === 0) {
                  return reject(new Error(`Empty file ${srcPath}`));
                }

                return xmlParser.parseString(glyphContents, error => {
                  if (error) {
                    return reject(error);
                  }

                  const glyphData = {
                    contents: glyphContents,
                    srcPath
                  };

                  return resolve(glyphData);
                });
              });
          })
      )
    )
  ).then(glyphsData => {
    const sortedGlyphsData = options.sort
      ? glyphsData.sort((fileA, fileB) =>
          fileSorter(fileA.srcPath, fileB.srcPath)
        )
      : glyphsData;

    return Promise.all(
      sortedGlyphsData.map(
        glyphData =>
          new Promise((resolve, reject) => {
            metadataProvider(glyphData.srcPath, (error, metadata) => {
              if (error) {
                return reject(error);
              }

              glyphData.metadata = metadata;

              return resolve(glyphData);
            });
          })
      )
    );
  });
}

function toSvg(glyphsData, options) {
  let result = "";

  return new Promise((resolve, reject) => {
    const fontStream = new SVGIcons2SVGFontStream({
      ascent: options.ascent,
      centerHorizontally: options.centerHorizontally,
      descent: options.descent,
      fixedWidth: options.fixedWidth,
      fontHeight: options.fontHeight,
      fontId: options.fontId,
      fontName: options.fontName,
      fontStyle: options.fontStyle,
      fontWeight: options.fontWeight,
      // eslint-disable-next-line no-console, no-empty-function
      log: options.verbose ? console.log.bind(console) : () => {},
      metadata: options.metadata,
      normalize: options.normalize,
      round: options.round
    })
      .on("finish", () => resolve(result))
      .on("data", data => {
        result += data;
      })
      .on("error", error => reject(error));

    glyphsData.forEach(glyphData => {
      const glyphStream = new Readable();

      glyphStream.push(glyphData.contents);
      glyphStream.push(null);

      glyphStream.metadata = glyphData.metadata;

      fontStream.write(glyphStream);
    });

    fontStream.end();
  });
}

function toTtf(buffer, options) {
  return Buffer.from(svg2ttf(buffer, options).buffer);
}

function toEot(buffer) {
  return Buffer.from(ttf2eot(buffer).buffer);
}

function toWoff(buffer, options) {
  return Buffer.from(ttf2woff(buffer, options).buffer);
}

function toWoff2(buffer) {
  return wawoff2.compress(buffer);
}

export default async function(initialOptions) {
  if (!initialOptions || !initialOptions.files) {
    throw new Error("You must pass webfont a `files` glob");
  }

  let options = Object.assign(
    {},
    {
      ascent: undefined, // eslint-disable-line no-undefined
      centerHorizontally: false,
      descent: 0,
      fixedWidth: false,
      fontHeight: null,
      fontId: null,
      fontName: "webfont",
      fontStyle: "",
      fontWeight: "",
      formats: ["svg", "ttf", "eot", "woff", "woff2"],
      formatsOptions: {
        ttf: {
          copyright: null,
          ts: null,
          version: null
        }
      },
      glyphTransformFn: null,
      // Maybe allow setup from CLI
      // This is usually less than file read maximums while staying performance
      maxConcurrency: 100,
      metadata: null,
      metadataProvider: null,
      normalize: false,
      prependUnicode: false,
      round: 10e12,
      sort: true,
      startUnicode: 0xea01,
      template: null,
      templateClassName: null,
      templateFontName: null,
      templateFontPath: "./",
      verbose: false
    },
    initialOptions
  );

  const config = await buildConfig({
    configFile: options.configFile
  });

  if (Object.keys(config).length > 0) {
    // eslint-disable-next-line require-atomic-updates
    options = deepmerge(options, config.config, {
      arrayMerge: (_destinationArray, sourceArray, _opts) => sourceArray
    });
    // eslint-disable-next-line require-atomic-updates
    options.filePath = config.filepath;
  }

  const foundFiles = await globby([].concat(options.files));
  const filteredFiles = foundFiles.filter(
    foundFile => path.extname(foundFile) === ".svg"
  );

  if (filteredFiles.length === 0) {
    throw new Error("Files glob patterns specified did not match any files");
  }

  const result = {};

  result.glyphsData = await getGlyphsData(filteredFiles, options);
  result.svg = await toSvg(result.glyphsData, options);
  result.ttf = toTtf(
    result.svg,
    options.formatsOptions && options.formatsOptions.ttf
      ? options.formatsOptions.ttf
      : {}
  );

  if (options.formats.includes("eot")) {
    result.eot = toEot(result.ttf);
  }

  if (options.formats.includes("woff")) {
    result.woff = toWoff(result.ttf, { metadata: options.metadata });
  }

  if (options.formats.includes("woff2")) {
    result.woff2 = await toWoff2(result.ttf);
  }

  if (options.template) {
    const templateDirectory = path.resolve(__dirname, "../templates");
    const buildInTemplates = {
      css: { path: path.join(templateDirectory, "template.css.njk") },
      html: { path: path.join(templateDirectory, "template.html.njk") },
      scss: { path: path.join(templateDirectory, "template.scss.njk") },
      styl: { path: path.join(templateDirectory, "template.styl.njk") }
    };

    let templateFilePath;

    if (Object.keys(buildInTemplates).includes(options.template)) {
      result.usedBuildInTemplate = true;

      nunjucks.configure(path.resolve(__dirname, "../"));

      templateFilePath = `${templateDirectory}/template.${
        options.template
      }.njk`;
    } else {
      const resolvedTemplateFilePath = path.resolve(options.template);

      nunjucks.configure(path.dirname(resolvedTemplateFilePath));

      templateFilePath = path.resolve(resolvedTemplateFilePath);
    }

    const nunjucksOptions = deepmerge.all([
      {
        glyphs: result.glyphsData.map(glyphData => {
          if (typeof options.glyphTransformFn === "function") {
            glyphData.metadata = options.glyphTransformFn(glyphData.metadata);
          }

          return glyphData.metadata;
        })
      },
      options,
      {
        className: options.templateClassName || options.fontName,
        fontName: options.templateFontName || options.fontName,
        fontPath: options.templateFontPath.replace(/\/?$/, "/")
      }
    ]);

    result.template = nunjucks.render(templateFilePath, nunjucksOptions);
  }

  if (!options.formats.includes("svg")) {
    delete result.svg;
  }

  if (!options.formats.includes("ttf")) {
    delete result.ttf;
  }

  result.config = options;

  return result;
}
<|endoftext|>


<commit_before>define(function(require) {
    var Enemy = require('entity/enemy');
    var Player = require('entity/player');
    var Collision = require('callback/collision');

    var state = {};
    var collisionLayer;
    var player;
    var enemyGroup;
    var cursors;
    state.create = function() {
        // set size of game world
        // create tilemap for level
        var map = state.add.tilemap('test_map');
        map.addTilesetImage('test_tiles', 'test_tiles');
        // create collision group
        collisionLayer = map.createLayer('collision');
        // fill collision group with collision layer
        map.setCollision(1, true, collisionLayer);
        collisionLayer.resizeWorld();
        // create player sprite
        player = new Player(state.game, 100, 100, 'badman');
        state.add.existing(player);
        // fix camera to player
        state.camera.follow(player);
        // create cursor keys/other input
        cursors = state.input.keyboard.createCursorKeys();
        state.physics.arcade.gravity.y = 800;

        enemyGroup = state.add.group();
        var i;
        for (i = 0; i < 30; i++) enemyGroup.add(new Enemy(state.game,
            Math.random() * state.world.width, 200, 'badman'));
    };
    state.update = function() {
        // world collision
        state.physics.arcade.collide(player, collisionLayer);
        state.physics.arcade.collide(enemyGroup, collisionLayer);
        // player vs. enemies collision
        state.physics.arcade.collide(player, enemyGroup, Collision.playerEnemy);
        // update enemy AI state
        // scan for input
        player.body.velocity.x = 0;
        if (cursors.left.isDown) player.body.velocity.x = -150;
        if (cursors.right.isDown) player.body.velocity.x = 150;
        if (cursors.up.isDown && player.body.onFloor())
            player.body.velocity.y = -400;
    };
    state.render = function() {
        state.time.advancedTiming = true;
        state.game.debug.text("FPS: " + state.time.fps, 20, 20, "#FFF");
    };
    return state;
});<commit_msg>Equip Magic Mirror. [Y]<commit_after>define(function(require) {
    var Enemy = require('entity/enemy');
    var Player = require('entity/player');
    var Collision = require('callback/collision');

    var state = {};
    var collisionLayer;
    var player;
    var enemyGroup;
    var cursors;
    state.create = function() {
        state.game.stage.backgroundColor = 0xCCCCCC;
        // create tilemap for level
        var map = state.add.tilemap('test_map');
        map.addTilesetImage('test_tiles', 'test_tiles');
        // create collision group
        collisionLayer = map.createLayer('collision');
        // fill collision group with collision layer
        map.setCollision(1, true, collisionLayer);
        // set size of game world
        collisionLayer.resizeWorld();
        // create player sprite
        player = new Player(state.game, 100, 100, 'badman');
        state.add.existing(player);
        // fix camera to player
        state.camera.follow(player);
        // create cursor keys/other input
        cursors = state.input.keyboard.createCursorKeys();
        state.physics.arcade.gravity.y = 800;

        enemyGroup = state.add.group();
        var i;
        for (i = 0; i < 30; i++) enemyGroup.add(new Enemy(state.game,
            Math.random() * state.world.width, 200, 'badman'));
    };
    state.update = function() {
        // world collision
        state.physics.arcade.collide(player, collisionLayer);
        state.physics.arcade.collide(enemyGroup, collisionLayer);
        // player vs. enemies collision
        state.physics.arcade.collide(player, enemyGroup, Collision.playerEnemy);
        // update enemy AI state
        // scan for input
        player.body.velocity.x = 0;
        if (cursors.left.isDown) player.body.velocity.x = -150;
        if (cursors.right.isDown) player.body.velocity.x = 150;
        if (cursors.up.isDown && player.body.onFloor())
            player.body.velocity.y = -400;
    };
    state.render = function() {
        state.time.advancedTiming = true;
        state.game.debug.text("FPS: " + state.time.fps, 20, 20, "#FFF");
    };
    return state;
});<|endoftext|>


<commit_before>/**
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/

'use strict';

import {nativeShadow, nativeCssVariables} from './style-settings.js';
import {parse, stringify, types, StyleNode} from './css-parse.js'; // eslint-disable-line no-unused-vars
import {MEDIA_MATCH} from './common-regex.js';
import {processUnscopedStyle, isUnscopedStyle} from './unscoped-style-handler.js';

/**
 * @param {string|StyleNode} rules
 * @param {function(StyleNode)=} callback
 * @return {string}
 */
export function toCssText (rules, callback) {
  if (!rules) {
    return '';
  }
  if (typeof rules === 'string') {
    rules = parse(rules);
  }
  if (callback) {
    forEachRule(rules, callback);
  }
  return stringify(rules, nativeCssVariables);
}

/**
 * @param {HTMLStyleElement} style
 * @return {StyleNode}
 */
export function rulesForStyle(style) {
  if (!style['__cssRules'] && style.textContent) {
    style['__cssRules'] = parse(style.textContent);
  }
  return style['__cssRules'] || null;
}

// Tests if a rule is a keyframes selector, which looks almost exactly
// like a normal selector but is not (it has nothing to do with scoping
// for example).
/**
 * @param {StyleNode} rule
 * @return {boolean}
 */
export function isKeyframesSelector(rule) {
  return Boolean(rule['parent']) &&
  rule['parent']['type'] === types.KEYFRAMES_RULE;
}

/**
 * @param {StyleNode} node
 * @param {Function=} styleRuleCallback
 * @param {Function=} keyframesRuleCallback
 * @param {boolean=} onlyActiveRules
 */
export function forEachRule(node, styleRuleCallback, keyframesRuleCallback, onlyActiveRules) {
  if (!node) {
    return;
  }
  let skipRules = false;
  let type = node['type'];
  if (onlyActiveRules) {
    if (type === types.MEDIA_RULE) {
      let matchMedia = node['selector'].match(MEDIA_MATCH);
      if (matchMedia) {
        // if rule is a non matching @media rule, skip subrules
        if (!window.matchMedia(matchMedia[1]).matches) {
          skipRules = true;
        }
      }
    }
  }
  if (type === types.STYLE_RULE) {
    styleRuleCallback(node);
  } else if (keyframesRuleCallback &&
    type === types.KEYFRAMES_RULE) {
    keyframesRuleCallback(node);
  } else if (type === types.MIXIN_RULE) {
    skipRules = true;
  }
  let r$ = node['rules'];
  if (r$ && !skipRules) {
    for (let i=0, l=r$.length, r; (i<l) && (r=r$[i]); i++) {
      forEachRule(r, styleRuleCallback, keyframesRuleCallback, onlyActiveRules);
    }
  }
}

// add a string of cssText to the document.
/**
 * @param {string} cssText
 * @param {string} moniker
 * @param {Node} target
 * @param {Node} contextNode
 * @return {HTMLStyleElement}
 */
export function applyCss(cssText, moniker, target, contextNode) {
  let style = createScopeStyle(cssText, moniker);
  applyStyle(style, target, contextNode);
  return style;
}

/**
 * @param {string} cssText
 * @param {string} moniker
 * @return {HTMLStyleElement}
 */
export function createScopeStyle(cssText, moniker) {
  let style = /** @type {HTMLStyleElement} */(document.createElement('style'));
  if (moniker) {
    style.setAttribute('scope', moniker);
  }
  style.textContent = cssText;
  return style;
}

/**
 * Track the position of the last added style for placing placeholders
 * @type {Node}
 */
let lastHeadApplyNode = null;

// insert a comment node as a styling position placeholder.
/**
 * @param {string} moniker
 * @return {!Comment}
 */
export function applyStylePlaceHolder(moniker) {
  let placeHolder = document.createComment(' Shady DOM styles for ' +
    moniker + ' ');
  let after = lastHeadApplyNode ?
    lastHeadApplyNode['nextSibling'] : null;
  let scope = document.head;
  scope.insertBefore(placeHolder, after || scope.firstChild);
  lastHeadApplyNode = placeHolder;
  return placeHolder;
}

/**
 * @param {HTMLStyleElement} style
 * @param {?Node} target
 * @param {?Node} contextNode
 */
export function applyStyle(style, target, contextNode) {
  target = target || document.head;
  let after = (contextNode && contextNode.nextSibling) ||
    target.firstChild;
  target.insertBefore(style, after);
  if (!lastHeadApplyNode) {
    lastHeadApplyNode = style;
  } else {
    // only update lastHeadApplyNode if the new style is inserted after the old lastHeadApplyNode
    let position = style.compareDocumentPosition(lastHeadApplyNode);
    if (position === Node.DOCUMENT_POSITION_PRECEDING) {
      lastHeadApplyNode = style;
    }
  }
}

/**
 * @param {string} buildType
 * @return {boolean}
 */
export function isTargetedBuild(buildType) {
  return nativeShadow ? buildType === 'shadow' : buildType === 'shady';
}

/**
 * Walk from text[start] matching parens and
 * returns position of the outer end paren
 * @param {string} text
 * @param {number} start
 * @return {number}
 */
export function findMatchingParen(text, start) {
  let level = 0;
  for (let i=start, l=text.length; i < l; i++) {
    if (text[i] === '(') {
      level++;
    } else if (text[i] === ')') {
      if (--level === 0) {
        return i;
      }
    }
  }
  return -1;
}

/**
 * @param {string} str
 * @param {function(string, string, string, string)} callback
 */
export function processVariableAndFallback(str, callback) {
  // find 'var('
  let start = str.indexOf('var(');
  if (start === -1) {
    // no var?, everything is prefix
    return callback(str, '', '', '');
  }
  //${prefix}var(${inner})${suffix}
  let end = findMatchingParen(str, start + 3);
  let inner = str.substring(start + 4, end);
  let prefix = str.substring(0, start);
  // suffix may have other variables
  let suffix = processVariableAndFallback(str.substring(end + 1), callback);
  let comma = inner.indexOf(',');
  // value and fallback args should be trimmed to match in property lookup
  if (comma === -1) {
    // variable, no fallback
    return callback(prefix, inner.trim(), '', suffix);
  }
  // var(${value},${fallback})
  let value = inner.substring(0, comma).trim();
  let fallback = inner.substring(comma + 1).trim();
  return callback(prefix, value, fallback, suffix);
}

/**
 * @param {Element} element
 * @param {string} value
 */
export function setElementClassRaw(element, value) {
  // use native setAttribute provided by ShadyDOM when setAttribute is patched
  if (nativeShadow) {
    element.setAttribute('class', value);
  } else {
    window['ShadyDOM']['nativeMethods']['setAttribute'].call(element, 'class', value);
  }
}

/**
 * @param {Element | {is: string, extends: string}} element
 * @return {{is: string, typeExtension: string}}
 */
export function getIsExtends(element) {
  let localName = element['localName'];
  let is = '', typeExtension = '';
  /*
  NOTE: technically, this can be wrong for certain svg elements
  with `-` in the name like `<font-face>`
  */
  if (localName) {
    if (localName.indexOf('-') > -1) {
      is = localName;
    } else {
      typeExtension = localName;
      is = (element.getAttribute && element.getAttribute('is')) || '';
    }
  } else {
    is = /** @type {?} */(element).is;
    typeExtension = /** @type {?} */(element).extends;
  }
  return {is, typeExtension};
}

/**
 * @param {Element|DocumentFragment} element
 * @return {string}
 */
export function gatherStyleText(element) {
  /** @type {!Array<string>} */
  const styleTextParts = [];
  const styles = /** @type {!NodeList<!HTMLStyleElement>} */(element.querySelectorAll('style'));
  for (let i = 0; i < styles.length; i++) {
    const style = styles[i];
    if (isUnscopedStyle(style)) {
      if (!nativeShadow) {
        processUnscopedStyle(style);
        style.parentNode.removeChild(style);
      }
    } else {
      styleTextParts.push(style.textContent);
      style.parentNode.removeChild(style);
    }
  }
  return styleTextParts.join('').trim();
}

/**
 * Split a selector separated by commas into an array in a smart way
 * @param {string} selector
 * @return {!Array<string>}
 */
export function splitSelectorList(selector) {
  const parts = [];
  let part = '';
  for (let i = 0; i >= 0 && i < selector.length; i++) {
    // A selector with parentheses will be one complete part
    if (selector[i] === '(') {
      // find the matching paren
      const end = findMatchingParen(selector, i);
      // push the paren block into the part
      part += selector.slice(i, end + 1);
      // move the index to after the paren block
      i = end;
    } else if (selector[i] === ',') {
      parts.push(part);
      part = '';
    } else {
      part += selector[i];
    }
  }
  // catch any pieces after the last comma
  if (part) {
    parts.push(part);
  }
  return parts;
}

const CSS_BUILD_ATTR = 'css-build';

/**
 * Return the polymer-css-build "build type" applied to this element
 *
 * @param {!HTMLElement} element
 * @return {string} Can be "", "shady", or "shadow"
 */
export function getCssBuild(element) {
  if (element.__cssBuild === undefined) {
    element.__cssBuild = element.getAttribute(CSS_BUILD_ATTR);
  }
  return element.__cssBuild || '';
}

/**
 * Check if the given element, either a <template> or <style>, has been processed
 * by polymer-css-build.
 *
 * If so, then we can make a number of optimizations:
 * - polymer-css-build will decompose mixins into individual CSS Custom Properties,
 * so the ApplyShim can be skipped entirely.
 * - Under native ShadowDOM, the style text can just be copied into each instance
 * without modification
 * - If the build is "shady" and ShadyDOM is in use, the styling does not need
 * scoping beyond the shimming of CSS Custom Properties
 *
 * @param {!HTMLElement} element
 * @return {boolean}
 */
export function elementHasBuiltCss(element) {
  return getCssBuild(element) !== '';
}<commit_msg>support comment in templates that are not in dom-module for css-build<commit_after>/**
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/

'use strict';

import {nativeShadow, nativeCssVariables} from './style-settings.js';
import {parse, stringify, types, StyleNode} from './css-parse.js'; // eslint-disable-line no-unused-vars
import {MEDIA_MATCH} from './common-regex.js';
import {processUnscopedStyle, isUnscopedStyle} from './unscoped-style-handler.js';

/**
 * @param {string|StyleNode} rules
 * @param {function(StyleNode)=} callback
 * @return {string}
 */
export function toCssText (rules, callback) {
  if (!rules) {
    return '';
  }
  if (typeof rules === 'string') {
    rules = parse(rules);
  }
  if (callback) {
    forEachRule(rules, callback);
  }
  return stringify(rules, nativeCssVariables);
}

/**
 * @param {HTMLStyleElement} style
 * @return {StyleNode}
 */
export function rulesForStyle(style) {
  if (!style['__cssRules'] && style.textContent) {
    style['__cssRules'] = parse(style.textContent);
  }
  return style['__cssRules'] || null;
}

// Tests if a rule is a keyframes selector, which looks almost exactly
// like a normal selector but is not (it has nothing to do with scoping
// for example).
/**
 * @param {StyleNode} rule
 * @return {boolean}
 */
export function isKeyframesSelector(rule) {
  return Boolean(rule['parent']) &&
  rule['parent']['type'] === types.KEYFRAMES_RULE;
}

/**
 * @param {StyleNode} node
 * @param {Function=} styleRuleCallback
 * @param {Function=} keyframesRuleCallback
 * @param {boolean=} onlyActiveRules
 */
export function forEachRule(node, styleRuleCallback, keyframesRuleCallback, onlyActiveRules) {
  if (!node) {
    return;
  }
  let skipRules = false;
  let type = node['type'];
  if (onlyActiveRules) {
    if (type === types.MEDIA_RULE) {
      let matchMedia = node['selector'].match(MEDIA_MATCH);
      if (matchMedia) {
        // if rule is a non matching @media rule, skip subrules
        if (!window.matchMedia(matchMedia[1]).matches) {
          skipRules = true;
        }
      }
    }
  }
  if (type === types.STYLE_RULE) {
    styleRuleCallback(node);
  } else if (keyframesRuleCallback &&
    type === types.KEYFRAMES_RULE) {
    keyframesRuleCallback(node);
  } else if (type === types.MIXIN_RULE) {
    skipRules = true;
  }
  let r$ = node['rules'];
  if (r$ && !skipRules) {
    for (let i=0, l=r$.length, r; (i<l) && (r=r$[i]); i++) {
      forEachRule(r, styleRuleCallback, keyframesRuleCallback, onlyActiveRules);
    }
  }
}

// add a string of cssText to the document.
/**
 * @param {string} cssText
 * @param {string} moniker
 * @param {Node} target
 * @param {Node} contextNode
 * @return {HTMLStyleElement}
 */
export function applyCss(cssText, moniker, target, contextNode) {
  let style = createScopeStyle(cssText, moniker);
  applyStyle(style, target, contextNode);
  return style;
}

/**
 * @param {string} cssText
 * @param {string} moniker
 * @return {HTMLStyleElement}
 */
export function createScopeStyle(cssText, moniker) {
  let style = /** @type {HTMLStyleElement} */(document.createElement('style'));
  if (moniker) {
    style.setAttribute('scope', moniker);
  }
  style.textContent = cssText;
  return style;
}

/**
 * Track the position of the last added style for placing placeholders
 * @type {Node}
 */
let lastHeadApplyNode = null;

// insert a comment node as a styling position placeholder.
/**
 * @param {string} moniker
 * @return {!Comment}
 */
export function applyStylePlaceHolder(moniker) {
  let placeHolder = document.createComment(' Shady DOM styles for ' +
    moniker + ' ');
  let after = lastHeadApplyNode ?
    lastHeadApplyNode['nextSibling'] : null;
  let scope = document.head;
  scope.insertBefore(placeHolder, after || scope.firstChild);
  lastHeadApplyNode = placeHolder;
  return placeHolder;
}

/**
 * @param {HTMLStyleElement} style
 * @param {?Node} target
 * @param {?Node} contextNode
 */
export function applyStyle(style, target, contextNode) {
  target = target || document.head;
  let after = (contextNode && contextNode.nextSibling) ||
    target.firstChild;
  target.insertBefore(style, after);
  if (!lastHeadApplyNode) {
    lastHeadApplyNode = style;
  } else {
    // only update lastHeadApplyNode if the new style is inserted after the old lastHeadApplyNode
    let position = style.compareDocumentPosition(lastHeadApplyNode);
    if (position === Node.DOCUMENT_POSITION_PRECEDING) {
      lastHeadApplyNode = style;
    }
  }
}

/**
 * @param {string} buildType
 * @return {boolean}
 */
export function isTargetedBuild(buildType) {
  return nativeShadow ? buildType === 'shadow' : buildType === 'shady';
}

/**
 * Walk from text[start] matching parens and
 * returns position of the outer end paren
 * @param {string} text
 * @param {number} start
 * @return {number}
 */
export function findMatchingParen(text, start) {
  let level = 0;
  for (let i=start, l=text.length; i < l; i++) {
    if (text[i] === '(') {
      level++;
    } else if (text[i] === ')') {
      if (--level === 0) {
        return i;
      }
    }
  }
  return -1;
}

/**
 * @param {string} str
 * @param {function(string, string, string, string)} callback
 */
export function processVariableAndFallback(str, callback) {
  // find 'var('
  let start = str.indexOf('var(');
  if (start === -1) {
    // no var?, everything is prefix
    return callback(str, '', '', '');
  }
  //${prefix}var(${inner})${suffix}
  let end = findMatchingParen(str, start + 3);
  let inner = str.substring(start + 4, end);
  let prefix = str.substring(0, start);
  // suffix may have other variables
  let suffix = processVariableAndFallback(str.substring(end + 1), callback);
  let comma = inner.indexOf(',');
  // value and fallback args should be trimmed to match in property lookup
  if (comma === -1) {
    // variable, no fallback
    return callback(prefix, inner.trim(), '', suffix);
  }
  // var(${value},${fallback})
  let value = inner.substring(0, comma).trim();
  let fallback = inner.substring(comma + 1).trim();
  return callback(prefix, value, fallback, suffix);
}

/**
 * @param {Element} element
 * @param {string} value
 */
export function setElementClassRaw(element, value) {
  // use native setAttribute provided by ShadyDOM when setAttribute is patched
  if (nativeShadow) {
    element.setAttribute('class', value);
  } else {
    window['ShadyDOM']['nativeMethods']['setAttribute'].call(element, 'class', value);
  }
}

/**
 * @param {Element | {is: string, extends: string}} element
 * @return {{is: string, typeExtension: string}}
 */
export function getIsExtends(element) {
  let localName = element['localName'];
  let is = '', typeExtension = '';
  /*
  NOTE: technically, this can be wrong for certain svg elements
  with `-` in the name like `<font-face>`
  */
  if (localName) {
    if (localName.indexOf('-') > -1) {
      is = localName;
    } else {
      typeExtension = localName;
      is = (element.getAttribute && element.getAttribute('is')) || '';
    }
  } else {
    is = /** @type {?} */(element).is;
    typeExtension = /** @type {?} */(element).extends;
  }
  return {is, typeExtension};
}

/**
 * @param {Element|DocumentFragment} element
 * @return {string}
 */
export function gatherStyleText(element) {
  /** @type {!Array<string>} */
  const styleTextParts = [];
  const styles = /** @type {!NodeList<!HTMLStyleElement>} */(element.querySelectorAll('style'));
  for (let i = 0; i < styles.length; i++) {
    const style = styles[i];
    if (isUnscopedStyle(style)) {
      if (!nativeShadow) {
        processUnscopedStyle(style);
        style.parentNode.removeChild(style);
      }
    } else {
      styleTextParts.push(style.textContent);
      style.parentNode.removeChild(style);
    }
  }
  return styleTextParts.join('').trim();
}

/**
 * Split a selector separated by commas into an array in a smart way
 * @param {string} selector
 * @return {!Array<string>}
 */
export function splitSelectorList(selector) {
  const parts = [];
  let part = '';
  for (let i = 0; i >= 0 && i < selector.length; i++) {
    // A selector with parentheses will be one complete part
    if (selector[i] === '(') {
      // find the matching paren
      const end = findMatchingParen(selector, i);
      // push the paren block into the part
      part += selector.slice(i, end + 1);
      // move the index to after the paren block
      i = end;
    } else if (selector[i] === ',') {
      parts.push(part);
      part = '';
    } else {
      part += selector[i];
    }
  }
  // catch any pieces after the last comma
  if (part) {
    parts.push(part);
  }
  return parts;
}

const CSS_BUILD_ATTR = 'css-build';

/**
 * Return the polymer-css-build "build type" applied to this element
 *
 * @param {!HTMLElement} element
 * @return {string} Can be "", "shady", or "shadow"
 */
export function getCssBuild(element) {
  if (element.__cssBuild === undefined) {
    const buildComment = getBuildComment(element);
    if (buildComment) {
      element.removeChild(element.firstChild);
    }
    element.__cssBuild = element.getAttribute(CSS_BUILD_ATTR) || buildComment;
  }
  return element.__cssBuild || '';
}

/**
 * Check if the given element, either a <template> or <style>, has been processed
 * by polymer-css-build.
 *
 * If so, then we can make a number of optimizations:
 * - polymer-css-build will decompose mixins into individual CSS Custom Properties,
 * so the ApplyShim can be skipped entirely.
 * - Under native ShadowDOM, the style text can just be copied into each instance
 * without modification
 * - If the build is "shady" and ShadyDOM is in use, the styling does not need
 * scoping beyond the shimming of CSS Custom Properties
 *
 * @param {!HTMLElement} element
 * @return {boolean}
 */
export function elementHasBuiltCss(element) {
  return getCssBuild(element) !== '';
}

/**
 * For templates made with tagged template literals, polymer-css-build will
 * insert a comment of the form `<!--css-build:shadow-->`
 *
 * @param {!HTMLElement} element
 * @return {string}
 */
export function getBuildComment(element) {
  const buildComment = element.firstChild;
  if (buildComment instanceof Comment) {
    const commentParts = buildComment.textContent.trim().split(':');
    if (commentParts[0] === CSS_BUILD_ATTR) {
      return commentParts[1];
    }
  }
  return '';
}<|endoftext|>


<commit_before>//reqs...measureValue
var React = require('react');
var _ = require('underscore');
var connect = require('react-redux').connect;
var utils = require('../../../../utils/sampleUtils.js');
var AreaChart = require('../../../../../../lib/react-d3').AreaChart;

var HistogramWrapper = React.createClass({
  componentWillMount : function() {
    this.genChartHistograms();

  },
  genChartHistograms : function() {
    //concat all the samples to find the min and max for min sizing
    var allSamples = _.reduce(this.props.samples, function(memo, array){
      return memo.concat(array);
    });
    var minValue = Math.floor(Math.min.apply(null, allSamples));
    var maxValue = Math.ceil(Math.max.apply(null, allSamples));

    //set max freq
    var maxFreq = 0;
    var chartData = _.map(this.props.samples, function(values, key){
      var histogram = utils.genHistogram(this.props.bins, values);
      minValue = Math.min(histogram.min, minValue);
      maxValue = Math.max(histogram.max, maxValue);
      maxFreq = Math.max(histogram.maxFreq, maxFreq);
      return  { data : {name: 'a name', values: histogram.coordinates}, label: key};
    }, this);

    this.histograms = _.map(chartData, function(dataObj, index) {
      return (

        <AreaChart
          data= {dataObj.data}
          yScale = {[0, maxFreq]}
          xScale = {[minValue, maxValue]}
          width={500}
          height={300}
          viewBoxObject={{
            x: 0,
            y: 0,
            height: 400,
            width: 500
          }}
          xAxisTickInterval={{unit: 'frequency', interval: 1}}
          title = {dataObj.label} />

)

    }, this);
  },
  histograms  : [],
  render: function() {
    return (

      {this.histograms}

    );
  }
});

// export chart
module.exports = HistogramWrapper;
<commit_msg>Fix histogram bin widths<commit_after>//reqs...measureValue
var React = require('react');
var _ = require('underscore');
var connect = require('react-redux').connect;
var utils = require('../../../../utils/sampleUtils.js');
var AreaChart = require('../../../../../../lib/react-d3').AreaChart;

var HistogramWrapper = React.createClass({
  componentWillMount : function() {
    this.genChartHistograms();

  },
  genChartHistograms : function() {
    //concat all the samples to find the min and max for min sizing
    var allSamples = _.reduce(this.props.samples, function(memo, array){
      return memo.concat(array);
    });
    var minValue = Math.floor(Math.min.apply(null, allSamples));
    var maxValue = Math.ceil(Math.max.apply(null, allSamples));

    //set max freq
    var maxFreq = 0;
    var chartData = _.map(this.props.samples, function(values, key){
      var histogram = utils.genHistogram(this.props.bins, values, minValue, maxValue);
      maxFreq = Math.max(histogram.maxFreq, maxFreq);
      return  { data : {name: 'a name', values: histogram.coordinates}, label: key};
    }, this);

    this.histograms = _.map(chartData, function(dataObj, index) {
      return (

        <AreaChart
          data= {dataObj.data}
          yScale = {[0, maxFreq]}
          xScale = {[minValue, maxValue]}
          width={500}
          height={300}
          viewBoxObject={{
            x: 0,
            y: 0,
            height: 400,
            width: 500
          }}
          xAxisTickInterval={{unit: 'frequency', interval: 1}}
          title = {dataObj.label} />

)

    }, this);
  },
  histograms  : [],
  render: function() {
    return (

      {this.histograms}

    );
  }
});

// export chart
module.exports = HistogramWrapper;
<|endoftext|>


<commit_before>/**
 * controller - home.
 * User: raytin
 * Date: 13-3-27
 * Time: 上午10:56
 */
var proxy = require("../proxy"),
    common = proxy.common,
    userProxy = proxy.User,
    topicProxy = proxy.Topic,
    config = require('../config').config,
    EventProxy = require("eventproxy");

var fs = require('fs');

exports.index = function(req, res, next){
    /*console.log(req.user); //无效
    //console.log(req.params);
    //console.log(req.body);
    //var ab = 8;
    //req.flash('info', 'you have %s items in yours', ab);
    //req.session.info = 'ubssss';
    //req.session.handa = 'dddyyy';
    //var info = req.flash( 'info');
    //console.log(info);
    //req.session.handa = null;
    fs.readdir('./public/csss', function(err, files){
        if(err) return console.log(999999999999999);
        console.log(files);
    });
    var user = null;
    if(req.session && req.session.user ){
        user = req.session.user;
    }
    console.log(res.locals);
    res.locals.user = user;
    res.locals.testfun = function(str){
        return '['+str+']';
    };
     console.log(req.query);
    */
    console.log(req.session);
    var ep = new EventProxy(),
        page = req.query.page || 1,
        limit = config.limit,
        opt = {skip: (page - 1) * limit, limit: limit, sort: [['_id', 'desc']]};

    //ep.all('userList', 'topicList', 'current_user', 'userListByCount', function(userList, topicList, current_user, userListByCount){
    ep.all( 'topicList', 'sidebar', 'topbar', 'totalCount', function(topicList, sidebar, topbar, totalCount){
        res.render('index',
            {
                title: config.name,
                config: config,
                topics: topicList,
                topInfo: topbar.topInfo,
                users: sidebar.users,
                userInfo: sidebar.userInfo,
                usersByCount: sidebar.usersByCount,
                totalCount: totalCount,
                page: parseInt(page)
            }
        );
    });
    ep.fail(next);

    topicProxy.getTopicList('', opt, ep.done(function(topicList){
        var topicLen = topicList.length;

        // 如果用户设置了昵称，则优先显示昵称
        // 将昵称与头像附加到主题对象
        ep.after('toAll', topicLen, function(){
            ep.emit('topicList', topicList);
        });

        // 获取当前主题的作者昵称与头像
        topicList.forEach(function(cur, i){
            userProxy.getOneUserInfo({_id : cur.author_id}, 'nickName head', ep.done(function(user){
                var nickName = user.nickName;

                cur.author_nickName = nickName ? nickName : user.name;
                cur.head = user.head ? user.head : config.nopic;

                ep.emit('toAll');
            }));
        });
    }));

    // 获取右侧资源
    common.getSidebarNeed(res, next, {fields: 'name nickName head fans followed topic_count sign lastLogin_time'}, function(need){
        ep.emit('sidebar', need);
    });

    // 获取顶部资源
    common.getTopbarNeed(res, next, function(need){
        ep.emit('topbar', need);
    });

    // 取得总页数
    topicProxy.getTopicCount(ep.done(function(totalCount){
        ep.emit('totalCount', Math.ceil(totalCount / limit));
    }));

};

// 以下代码仅为测试之用
exports.test = function(req, res, next){
    res.render('test', {
        title: 'test'
    });
};

exports.ajaxTest = function(req, res, next){
    userProxy.getUserList(function(err, users){
        if(err) return next(err);
        if(users && users.length){
            res.json(users)
        }
    });
};<commit_msg>密集测试&开发<commit_after>/**
 * controller - home.
 * User: raytin
 * Date: 13-3-27
 * Time: 上午10:56
 */
var proxy = require("../proxy"),
    common = proxy.common,
    userProxy = proxy.User,
    topicProxy = proxy.Topic,
    config = require('../config').config,
    EventProxy = require("eventproxy");

var fs = require('fs');

exports.index = function(req, res, next){
    /*console.log(req.user); //无效
    //console.log(req.params);
    //console.log(req.body);
    //var ab = 8;
    //req.flash('info', 'you have %s items in yours', ab);
    //req.session.info = 'ubssss';
    //req.session.handa = 'dddyyy';
    //var info = req.flash( 'info');
    //console.log(info);
    //req.session.handa = null;
    fs.readdir('./public/csss', function(err, files){
        if(err) return console.log(999999999999999);
        console.log(files);
    });
    var user = null;
    if(req.session && req.session.user ){
        user = req.session.user;
    }
    console.log(res.locals);
    res.locals.user = user;
    res.locals.testfun = function(str){
        return '['+str+']';
    };
     console.log(req.query);
    */
    console.log(req.session);
    var ep = new EventProxy(),
        page = req.query.page || 1,
        limit = config.limit,
        opt = {skip: (page - 1) * limit, limit: limit, sort: [['_id', 'desc']]};

    //ep.all('userList', 'topicList', 'current_user', 'userListByCount', function(userList, topicList, current_user, userListByCount){
    ep.all( 'topicList', 'sidebar', 'topbar', 'totalCount', function(topicList, sidebar, topbar, totalCount){
        res.render('index',
            {
                title: config.name,
                config: config,
                topics: topicList,
                topInfo: topbar.topInfo,
                users: sidebar.users,
                userInfo: sidebar.userInfo,
                usersByCount: sidebar.usersByCount,
                totalCount: totalCount,
                page: parseInt(page)
            }
        );
    });
    ep.fail(next);

    topicProxy.getTopicList('', opt, ep.done(function(topicList){
        var topicLen = topicList.length;

        // 如果用户设置了昵称，则优先显示昵称
        // 将昵称与头像附加到主题对象
        ep.after('toAll', topicLen, function(){
            ep.emit('topicList', topicList);
        });

        // 获取当前主题的作者昵称与头像
        topicList.forEach(function(cur, i){
            userProxy.getOneUserInfo({_id : cur.author_id}, 'name nickName head', ep.done(function(user){
                var nickName = user.nickName;

                cur.author_nickName = nickName ? nickName : user.name;
                cur.head = user.head ? user.head : config.nopic;

                ep.emit('toAll');
            }));
        });
    }));

    // 获取右侧资源
    common.getSidebarNeed(res, next, {fields: 'name nickName head fans followed topic_count sign lastLogin_time'}, function(need){
        ep.emit('sidebar', need);
    });

    // 获取顶部资源
    common.getTopbarNeed(res, next, function(need){
        ep.emit('topbar', need);
    });

    // 取得总页数
    topicProxy.getTopicCount(ep.done(function(totalCount){
        ep.emit('totalCount', Math.ceil(totalCount / limit));
    }));

};

// 以下代码仅为测试之用
exports.test = function(req, res, next){
    res.render('test', {
        title: 'test'
    });
};

exports.ajaxTest = function(req, res, next){
    userProxy.getUserList(function(err, users){
        if(err) return next(err);
        if(users && users.length){
            res.json(users)
        }
    });
};<|endoftext|>


<commit_before>var io;
var mongoose = require('mongoose');

var LectureSchema = require('../models/Lecture.js').LectureSchema;
var qSchema = require('../models/Q.js').QSchema;
var chatSchema = require('../models/Chat.js').ChatSchema;
var quizSchema = require('../models/Quiz.js').QuizSchema;
var answerSchema = require('../models/Quiz.js').AnswerSchema;

var Lecture = mongoose.model('lectures', LectureSchema);
var Q = mongoose.model('qs', qSchema);
var Chat = mongoose.model('chats', chatSchema);
var Quiz = mongoose.model('quizs', quizSchema);
var Answer = mongoose.model('answers', answerSchema);

var socketRoom = {};
var lectures = {};
module.exports = {
	index : function(sio) {
		io = sio;
	},
	lecture : function (socket) {

		var qs = [];
		var cs = [];

		var lectureObj;
		var duration = 60;

		function currentTime(startAt) {
			return (new Date()).getTime() - startAt;
		}

		socket.emit('connected');

		socket.on('requestLecture', function(Id) {
			var lectureId = Id.lectureId;
			var userId = Id.userId;
			console.log(lectureId + " joined");
			socket.join(lectureId);
			socketRoom[socket.id] = {lectureId: lectureId, userId: userId};

			if( lectures[lectureId] === undefined)
				lectures[lectureId] = {startAt: 0, lapTime: 0, isLectureStarted: 'false', attendee: []};

			console.log(socketRoom);

			socket.emit('joinLecture', Id);

			lectures[lectureId].attendee.push(Id);
			io.sockets.in(socketRoom[socket.id].lectureId).emit('lectureAttend', lectures[lectureId].attendee);

			Lecture.findById(lectureId, '', {lean:true}, function(error, lecture){
				if(lecture) {
					lectureObj = lecture;
					if(lecture.duration !== undefined) {
						lectures[lectureId].duration = lecture.duration;
					}

				}
				while(qs.length > 0) qs.pop();
				Q.find({lecture: lectureId}, {}, {}, function(error, q){
					qs = qs.concat(q);
					while(cs.length > 0) cs.pop();
					Chat.find({lecture: lectureId}, {}, {}, function(error, c){
						cs = cs.concat(c);
						//console.log(cs);
						socket.emit('initQnChat', qStat(lectures[lectureId].duration, qs), cs);
					});
				});

				if(lectures[lectureId].isLectureStarted == 'true') {
					console.log("you are late");
					console.log(lectures[lectureId].startAt);
					console.log(currentTime(lectures[lectureId].startAt));
					socket.emit('startLecture', lectures[lectureId].startAt, lectures[lectureId].lapTime);
				}
			});

		});

		socket.on('startLecture', function(time) {

			console.log(time.startAt);
			lectures[socketRoom[socket.id].lectureId].startAt = time.startAt;
			lectures[socketRoom[socket.id].lectureId].lapTime = time.lapTime;
			lectures[socketRoom[socket.id].lectureId].isLectureStarted = 'true';

			io.sockets.in(socketRoom[socket.id].lectureId).emit('startLecture', time.startAt, time.lapTime);
		});

		socket.on('pauseLecture', function(time) {
			lectures[socketRoom[socket.id].lectureId].lapTime = time.time;
			lectures[socketRoom[socket.id].lectureId].isLectureStarted = 'false';
			io.sockets.in(socketRoom[socket.id].lectureId).emit('pauseLecture', time.startAt, time.lapTime);
		});

		socket.on('stopLecture', function(time) {
			lectures[socketRoom[socket.id].lectureId].lapTime = time.time;
			lectures[socketRoom[socket.id].lectureId].isLectureStarted = 'false';
			io.sockets.in(socketRoom[socket.id].lectureId).emit('stopLecture', time.startAt, time.lapTime);

			//saving
		});

		socket.on('liveTimeUpdate', function(time){
			//console.log("liveTime: " + time);
			if(socketRoom[socket.id] !== undefined)
				lectures[socketRoom[socket.id].lectureId].duration = time;
		});

		socket.on('leaveLecture', function(lectureId) {
			console.log(lectureId + " leaved");
			socket.leave(socketRoom[socket.id].lectureId);
		});

		socket.on('sendMessage', function(data){
			console.log('sendMessage!');

			if( data.src === ''){
				return;
			}
			io.sockets.in(socketRoom[socket.id].lectureId).emit('receiveMessage', data);
			var object = { user: data.src,
				     	   lecture: data.lecture,
					       time: data.time,
					       timestamp: data.timestamp,
					       msg: data.message
				         };
			if(data.type == "q"){
				var q = new Q(object);
				q.save(function(err, doc){
					if(err || !doc){
						throw err;
					}
				});
				qs.push(q);
			}
			else if (data.type == "chat"){
				//console.log("chat ");
				object.user_name = data.src_name;
				var chat = new Chat(object);
				chat.save(function(err,doc){
					if (err || !doc){
						throw 'Error';
					}
				});
				cs.push(chat);
			}
    	});

		socket.on('sendQuiz', function(data){
			console.log('sendQuiz!');

			//quiz DB
			// src, lectureId, question, type
			var quizObj = { userId: data.src,
							lectureId: data.lectureId,
							question: data.question,
							type: data.type,
							choice: data.choice
						  }
			var quiz = new Quiz(quizObj);
			quiz.save(function(err,doc){
				if (err || !doc){
					throw 'Error';
				}
				data.quizId = doc._id;
				console.log(doc._id);
				io.sockets.in(socketRoom[socket.id].lectureId).emit('receiveQuiz', data);
			});
		});

		socket.on('sendQuizAns', function(answer){
			console.log('sendQuizAns!');
			console.log(answer);
			for (var key in socketRoom){
				if (socketRoom[key].userId == answer.target){
					io.sockets.socket(key).emit('receiveAns', answer.data);
				}
			}

			var answerObj = { userId: answer.src,
							  quizId: answer.quizId,
							  lectureId: answer.lectureId,
							  type: answer.type,
							  answer: answer.data
							}
			var ans = new Answer(answerObj);
			ans.save(function(err,doc){
				if (err || !doc){
					throw 'Error';
				}
			});
		});

		socket.on('qData', function(){
			var data = qStat(lectures[socketRoom[socket.id].lectureId].duration, qs);
			io.sockets.in(socketRoom[socket.id].lectureId).emit('qData', data);
		});

		//canvas

		socket.on('canvasDraw', function(stroke){
			socket.broadcast.emit('canvasDraw', stroke);
		});

		socket.on('disconnect', function(data) {
			console.log('disconnected');
			if (socketRoom[socket.id] !== undefined){
				var key = socketRoom[socket.id];

				socket.leave(socketRoom[socket.id]);
				delete socketRoom[socket.id];
				//delete lectures[key].attendee

				lectures[key.lectureId].attendee = lectures[key.lectureId].attendee.filter(function(e){
					return e.userId !== key.userId;
				});

				io.sockets.in(key.lectureId).emit('disconnect', key.userId);
			}
			/*
			var clients = io.sockets.clients(key);
			for (var i = 0; i < clients.length; i++){
				clients[i].leave(key);
        	}
        	*/
		});

	}

}

function qStat(lDuration, qs){
	/*
	 * Google column chart
	 */
	 var i = 0;
	 var labels = [];
	 var data = [];
	 var duration = Math.ceil(lDuration / 60.0);
	 console.log(lDuration + " " + duration);
	 if (isNaN(duration)) duration = 10;
	 else if (duration < 10) duration = 10;

	 var columnChart =[['Time (min)', 'Value']];
	 for (i = 0; i<=duration; i++){
		 var d = [];
		 d.push(i.toString());
		 d.push(0);
		 //console.log(d);
		 columnChart.push(d);
	 }
	 console.log(duration);
	 for (i in qs){
		 var time = Math.floor(qs[i].time / 60.0);
		 if (columnChart[time + 1] !== undefined)
			 columnChart[time + 1][1]++;
	 }
	 return columnChart;
}<commit_msg>q-graph bug fix  (서로 다른 클라이언트에서 Q를 보냈을 때, 싱크되지 않고 각각 저장되서 Q 그래프를 망치는 문제 수정)<commit_after>var io;
var mongoose = require('mongoose');

var LectureSchema = require('../models/Lecture.js').LectureSchema;
var qSchema = require('../models/Q.js').QSchema;
var chatSchema = require('../models/Chat.js').ChatSchema;
var quizSchema = require('../models/Quiz.js').QuizSchema;
var answerSchema = require('../models/Quiz.js').AnswerSchema;

var Lecture = mongoose.model('lectures', LectureSchema);
var Q = mongoose.model('qs', qSchema);
var Chat = mongoose.model('chats', chatSchema);
var Quiz = mongoose.model('quizs', quizSchema);
var Answer = mongoose.model('answers', answerSchema);

var socketRoom = {};
var lectures = {};
module.exports = {
	index : function(sio) {
		io = sio;
	},
	lecture : function (socket) {
		//var qs = [];
		//var cs = [];

		var lectureObj;
		var duration = 60;

		function currentTime(startAt) {
			return (new Date()).getTime() - startAt;
		}

		socket.emit('connected');

		socket.on('requestLecture', function(Id) {
			var lectureId = Id.lectureId;
			var userId = Id.userId;
			console.log(lectureId + " joined");
			socket.join(lectureId);
			socketRoom[socket.id] = {lectureId: lectureId, userId: userId};

			if( lectures[lectureId] === undefined){
				lectures[lectureId] = {startAt: 0, lapTime: 0, isLectureStarted: 'false', attendee: []};
				lectures[lectureId].qs = [];
				lectures[lectureId].cs = [];
			}
			console.log(socketRoom);

			socket.emit('joinLecture', Id);

			lectures[lectureId].attendee.push(Id);
			io.sockets.in(socketRoom[socket.id].lectureId).emit('lectureAttend', lectures[lectureId].attendee);

			Lecture.findById(lectureId, '', {lean:true}, function(error, lecture){
				if(lecture) {
					lectureObj = lecture;
					if(lecture.duration !== undefined) {
						lectures[lectureId].duration = lecture.duration;
					}

				}

				while(lectures[lectureId].qs.length > 0) lectures[lectureId].qs.pop();
				Q.find({lecture: lectureId}, {}, {}, function(error, q){
					lectures[lectureId].qs = lectures[lectureId].qs.concat(q);
					//qs = qs.concat(q);

					while(lectures[lectureId].cs.length > 0) lectures[lectureId].cs.pop();
					Chat.find({lecture: lectureId}, {}, {}, function(error, c){
						lectures[lectureId].cs = lectures[lectureId].cs.concat(c);
						//console.log(cs);
						socket.emit('initQnChat', qStat(lectures[lectureId].duration, lectures[lectureId].qs), lectures[lectureId].cs);
					});
				});

				if(lectures[lectureId].isLectureStarted == 'true') {
					console.log("you are late");
					console.log(lectures[lectureId].startAt);
					console.log(currentTime(lectures[lectureId].startAt));
					socket.emit('startLecture', lectures[lectureId].startAt, lectures[lectureId].lapTime);
				}
			});

		});

		socket.on('startLecture', function(time) {

			console.log(time.startAt);
			lectures[socketRoom[socket.id].lectureId].startAt = time.startAt;
			lectures[socketRoom[socket.id].lectureId].lapTime = time.lapTime;
			lectures[socketRoom[socket.id].lectureId].isLectureStarted = 'true';

			io.sockets.in(socketRoom[socket.id].lectureId).emit('startLecture', time.startAt, time.lapTime);
		});

		socket.on('pauseLecture', function(time) {
			lectures[socketRoom[socket.id].lectureId].lapTime = time.time;
			lectures[socketRoom[socket.id].lectureId].isLectureStarted = 'false';
			io.sockets.in(socketRoom[socket.id].lectureId).emit('pauseLecture', time.startAt, time.lapTime);
		});

		socket.on('stopLecture', function(time) {
			lectures[socketRoom[socket.id].lectureId].lapTime = time.time;
			lectures[socketRoom[socket.id].lectureId].isLectureStarted = 'false';
			io.sockets.in(socketRoom[socket.id].lectureId).emit('stopLecture', time.startAt, time.lapTime);

			//saving
		});

		socket.on('liveTimeUpdate', function(time){
			//console.log("liveTime: " + time);
			if(socketRoom[socket.id] !== undefined)
				lectures[socketRoom[socket.id].lectureId].duration = time;
		});

		socket.on('leaveLecture', function(lectureId) {
			console.log(lectureId + " leaved");
			socket.leave(socketRoom[socket.id].lectureId);
		});

		socket.on('sendMessage', function(data){
			console.log('sendMessage!');

			if( data.src === ''){
				return;
			}
			io.sockets.in(socketRoom[socket.id].lectureId).emit('receiveMessage', data);
			var object = { user: data.src,
				     	   lecture: data.lecture,
					       time: data.time,
					       timestamp: data.timestamp,
					       msg: data.message
				         };
			if(data.type == "q"){
				var q = new Q(object);
				q.save(function(err, doc){
					if(err || !doc){
						throw err;
					}
				});
				lectures[socketRoom[socket.id].lectureId].qs.push(q);
			}
			else if (data.type == "chat"){
				//console.log("chat ");
				object.user_name = data.src_name;
				var chat = new Chat(object);
				chat.save(function(err,doc){
					if (err || !doc){
						throw 'Error';
					}
				});
				lectures[socketRoom[socket.id].lectureId].cs.push(chat);
			}
    	});

		socket.on('sendQuiz', function(data){
			console.log('sendQuiz!');

			//quiz DB
			// src, lectureId, question, type
			var quizObj = { userId: data.src,
							lectureId: data.lectureId,
							question: data.question,
							type: data.type,
							choice: data.choice
						  }
			var quiz = new Quiz(quizObj);
			quiz.save(function(err,doc){
				if (err || !doc){
					throw 'Error';
				}
				data.quizId = doc._id;
				console.log(doc._id);
				io.sockets.in(socketRoom[socket.id].lectureId).emit('receiveQuiz', data);
			});
		});

		socket.on('sendQuizAns', function(answer){
			console.log('sendQuizAns!');
			console.log(answer);
			for (var key in socketRoom){
				if (socketRoom[key].userId == answer.target){
					io.sockets.socket(key).emit('receiveAns', answer.data);
				}
			}

			var answerObj = { userId: answer.src,
							  quizId: answer.quizId,
							  lectureId: answer.lectureId,
							  type: answer.type,
							  answer: answer.data
							}
			var ans = new Answer(answerObj);
			ans.save(function(err,doc){
				if (err || !doc){
					throw 'Error';
				}
			});
		});

		socket.on('qData', function(){
			var data = qStat(lectures[socketRoom[socket.id].lectureId].duration, lectures[socketRoom[socket.id].lectureId].qs);
			io.sockets.in(socketRoom[socket.id].lectureId).emit('qData', data);
		});

		//canvas

		socket.on('canvasDraw', function(stroke){
			socket.broadcast.emit('canvasDraw', stroke);
		});

		socket.on('disconnect', function(data) {
			console.log('disconnected');
			if (socketRoom[socket.id] !== undefined){
				var key = socketRoom[socket.id];

				socket.leave(socketRoom[socket.id]);
				delete socketRoom[socket.id];
				//delete lectures[key].attendee

				lectures[key.lectureId].attendee = lectures[key.lectureId].attendee.filter(function(e){
					return e.userId !== key.userId;
				});

				io.sockets.in(key.lectureId).emit('disconnect', key.userId);
			}
			/*
			var clients = io.sockets.clients(key);
			for (var i = 0; i < clients.length; i++){
				clients[i].leave(key);
        	}
        	*/
		});

	}

}

function qStat(lDuration, qs){
	/*
	 * Google column chart
	 */
	 var i = 0;
	 var labels = [];
	 var data = [];
	 var duration = Math.ceil(lDuration / 60.0);
	 console.log(lDuration + " " + duration);
	 if (isNaN(duration)) duration = 10;
	 else if (duration < 10) duration = 10;

	 var columnChart =[['Time (min)', 'Value']];
	 for (i = 0; i<=duration; i++){
		 var d = [];
		 d.push(i.toString());
		 d.push(0);
		 //console.log(d);
		 columnChart.push(d);
	 }
	 console.log(duration);
	 for (i in qs){
		 var time = Math.floor(qs[i].time / 60.0);
		 if (columnChart[time + 1] !== undefined)
			 columnChart[time + 1][1]++;
	 }
	 return columnChart;
}<|endoftext|>


<commit_before>const test    = require('tape')
const sinon   = require('sinon')
const helpers = require('../test/helpers')

const isObject    = require('../internal/isObject')
const isFunction  = require('../internal/isFunction')
const bindFunc    = helpers.bindFunc
const noop        = helpers.noop

const identity      = require('../combinators/identity')
const composeB      = require('../combinators/composeB')
const reverseApply  = require('../combinators/composeB')

const MockCrock = require('../test/MockCrock')

const Null = require('./Null')

test('Null', t => {
  const m = Null(0)

  t.ok(isFunction(Null), 'is a function')
  t.ok(isObject(m), 'returns an object')

  t.ok(isFunction(Null.type), 'provides a type function')
  t.ok(isFunction(Null.empty), 'provides an empty function')

  t.doesNotThrow(Null, 'allows no parameters')

  t.end()
})

test('Null inspect', t => {
  const m = Null(0)

  t.ok(isFunction(m.inspect), 'provides an inpsect function')
  t.equal(m.inspect(), 'Null', 'returns inspect string')

  t.end()
})

test('Null type', t => {
  const m = Null(0)

  t.ok(isFunction(m.type), 'provides a type function')
  t.equal(m.type(), 'Null', 'type returns Null')

  t.end()
})

test('Null value', t => {
  const x = 'some value'
  const m = Null(x)

  t.ok(isFunction(m.value), 'is a function')
  t.equal(m.value(), null,'value always returns null' )

  t.end()
})

test('Null equals functionality', t => {
  const a = Null(0)
  const b = Null(0)
  const c = Null(1)

  const value = 0
  const nonNull = MockCrock(value)

  t.equal(a.equals(c), true, 'returns true when 2 Nulls initial values are not equal')
  t.equal(a.equals(b), true, 'returns true when 2 Nulls initial values are equal')
  t.equal(a.equals(value), false, 'returns false when passed a simple value')
  t.equal(a.equals(nonNull), false, 'returns false when passed a non-Null')

  t.end()
})

test('Null equals properties (Setoid)', t => {
  const a = Null(0)
  const b = Null(0)
  const c = Null(1)
  const d = Null(0)

  t.ok(isFunction(Null(0).equals), 'provides an equals function')
  t.equal(a.equals(a), true, 'reflexivity')
  t.equal(a.equals(b), b.equals(a), 'symmetry (equal)')
  t.equal(a.equals(c), c.equals(a), 'symmetry (!equal)')
  t.equal(a.equals(b) && b.equals(d), a.equals(d), 'transitivity')

  t.end()
})

test('Null concat properties (Semigoup)', t => {
  const a = Null(0)
  const b = Null(true)
  const c = Null('')

  const left  = a.concat(b).concat(c)
  const right = a.concat(b.concat(c))

  t.ok(isFunction(a.concat), 'provides a concat function')
  t.equal(left.value(), right.value(), 'associativity')
  t.equal(a.concat(b).type(), a.type(), 'returns a Null')

  t.end()
})

test('Null concat functionality', t => {
  const a = Null(23)
  const b = Null(null)

  const notNull = MockCrock()

  const cat = bindFunc(a.concat)

  t.throws(cat(undefined), TypeError, 'throws with undefined')
  t.throws(cat(null), TypeError, 'throws with null')
  t.throws(cat(0), TypeError, 'throws with falsey number')
  t.throws(cat(1), TypeError, 'throws with truthy number')
  t.throws(cat(''), TypeError, 'throws with falsey string')
  t.throws(cat('string'), TypeError, 'throws with truthy string')
  t.throws(cat(false), TypeError, 'throws with false')
  t.throws(cat(true), TypeError, 'throws with true')
  t.throws(cat([]), TypeError, 'throws with an array')
  t.throws(cat({}), TypeError, 'throws with an object')
  t.throws(cat(notNull), TypeError, 'throws when passed non-Null')

  t.equal(a.concat(b).value(), null, 'reports null for 23')
  t.equal(b.concat(a).value(), null, 'null for true')

  t.end()
})

test('Null empty properties (Monoid)', t => {
  const m = Null(3)

  t.ok(isFunction(m.concat), 'provides a concat function')
  t.ok(isFunction(m.empty), 'provides an empty function')

  const right = m.concat(m.empty())
  const left  = m.empty().concat(m)

  t.equal(right.value(), m.value(), 'right identity')
  t.equal(left.value(), m.value(), 'left identity')

  t.end()
})

test('Null empty functionality', t => {
  const x = Null(0).empty()

  t.equal(x.type(), 'Null', 'provides a Null')
  t.equal(x.value(), null, 'wraps a null value')

  t.end()
})

test('Null map errors', t => {
  const map = bindFunc(Null(0).map)

  t.throws(map(undefined), TypeError, 'throws when passed undefined')
  t.throws(map(null), TypeError, 'throws when passed null')
  t.throws(map(0), TypeError, 'throws when passed falsey number')
  t.throws(map(1), TypeError, 'throws when passed truthy number')
  t.throws(map(''), TypeError, 'throws when passed falsey string')
  t.throws(map('string'), TypeError, 'throws when passed truthy string')
  t.throws(map(false), TypeError, 'throws when passed false')
  t.throws(map(true), TypeError, 'throws when passed true')
  t.throws(map([]), TypeError, 'throws when passed an array')
  t.throws(map({}), TypeError, 'throws when passed an object')
  t.doesNotThrow(map(noop))

  t.end()
})

test('Null map functionality', t => {
  const spy = sinon.spy(x => x + 2)
  const x   = 42

  const m = Null(x).map(spy)

  t.equal(m.type(), 'Null', 'returns a Null')
  t.notOk(spy.called, 'does not call mapping function')
  t.equal(m.value(), null, 'returns null')

  t.end()
})

test('Null map properties (Functor)', t => {
  const m = Null(10)

  const f = x => x + 54
  const g = x => x * 4

  t.ok(isFunction(m.map), 'provides a map function')

  t.equal(m.map(identity).value(), m.value(), 'identity')
  t.equal(m.map(composeB(f, g)).value(), m.map(g).map(f).value(), 'composition')

  t.end()
})

test('Null ap errors', t => {
  const m  = MockCrock('joy')
  const ap = bindFunc(Null(32).ap)

  t.throws(ap(undefined), TypeError, 'throws when passed undefined')
  t.throws(ap(null), TypeError, 'throws when passed null')
  t.throws(ap(0), TypeError, 'throws when passed a falsey number')
  t.throws(ap(1), TypeError, 'throws when passed a truthy number')
  t.throws(ap(''), TypeError, 'throws when passed a falsey string')
  t.throws(ap('string'), TypeError, 'throws when passed a truthy string')
  t.throws(ap(false), TypeError, 'throws when passed false')
  t.throws(ap(true), TypeError, 'throws when passed true')
  t.throws(ap([]), TypeError, 'throws when passed an array')
  t.throws(ap({}), TypeError, 'throws when passed an object')

  t.throws(ap(m), TypeError, 'throws when container types differ')

  t.end()
})

test('Null ap properties (Apply)', t => {
  const m = Null({ some: 'thing' })

  const a = m.map(composeB).ap(m).ap(m)
  const b = m.ap(m.ap(m))

  t.ok(isFunction(Null(0).map), 'implements the Functor spec')
  t.ok(isFunction(Null(0).ap), 'provides an ap function')

  t.same(a.ap(Null(3)).value(), b.ap(Null(3)).value(), 'composition')

  t.end()
})

test('Null of', t => {
  t.equal(Null.of, Null(0).of, 'Null.of is the same as the instance version')
  t.equal(Null.of(0).type(), 'Null', 'returns a Null')
  t.equal(Null.of(0).value(), null, 'returns the default null value')

  t.end()
})

test('Null of properties (Applicative)', t => {
  const m = Null(identity)

  t.ok(isFunction(Null(0).of), 'provides an of function')
  t.ok(isFunction(Null(0).ap), 'implements the Apply spec')

  t.equal(m.ap(Null(3)).value(), null, 'identity')
  t.equal(m.ap(Null.of(3)).value(), Null.of(identity(3)).value(), 'homomorphism')

  const a = x => m.ap(Null.of(x))
  const b = x => Null.of(reverseApply(x)).ap(m)

  t.equal(a(3).value(), b(3).value(), 'interchange')

  t.end()
})

test('Null chain errors', t => {
  const chain = bindFunc(Null(0).chain)

  t.throws(chain(undefined), TypeError, 'throws with undefined')
  t.throws(chain(null), TypeError, 'throws with null')
  t.throws(chain(0), TypeError, 'throws with falsey number')
  t.throws(chain(1), TypeError, 'throws with truthy number')
  t.throws(chain(''), TypeError, 'throws with falsey string')
  t.throws(chain('string'), TypeError, 'throws with truthy string')
  t.throws(chain(false), TypeError, 'throws with false')
  t.throws(chain(true), TypeError, 'throws with true')
  t.throws(chain([]), TypeError, 'throws with an array')
  t.throws(chain({}), TypeError, 'throws with an object')

  t.doesNotThrow(chain(noop), 'allows any function')

  t.end()
})

test('Null chain properties (Chain)', t => {
  t.ok(isFunction(Null(0).chain), 'provides a chain function')
  t.ok(isFunction(Null(0).ap), 'implements the Apply spec')

  const f = x => Null(x + 2)
  const g = x => Null(x + 10)

  const a = x => Null(x).chain(f).chain(g)
  const b = x => Null(x).chain(y => f(y).chain(g))

  t.equal(a(10).value(), b(10).value(), 'assosiativity')

  t.end()
})
<commit_msg>add Monad specs for Null<commit_after>const test    = require('tape')
const sinon   = require('sinon')
const helpers = require('../test/helpers')

const isObject    = require('../internal/isObject')
const isFunction  = require('../internal/isFunction')
const bindFunc    = helpers.bindFunc
const noop        = helpers.noop

const identity      = require('../combinators/identity')
const composeB      = require('../combinators/composeB')
const reverseApply  = require('../combinators/composeB')

const MockCrock = require('../test/MockCrock')

const Null = require('./Null')

test('Null', t => {
  const m = Null(0)

  t.ok(isFunction(Null), 'is a function')
  t.ok(isObject(m), 'returns an object')

  t.ok(isFunction(Null.type), 'provides a type function')
  t.ok(isFunction(Null.empty), 'provides an empty function')

  t.doesNotThrow(Null, 'allows no parameters')

  t.end()
})

test('Null inspect', t => {
  const m = Null(0)

  t.ok(isFunction(m.inspect), 'provides an inpsect function')
  t.equal(m.inspect(), 'Null', 'returns inspect string')

  t.end()
})

test('Null type', t => {
  const m = Null(0)

  t.ok(isFunction(m.type), 'provides a type function')
  t.equal(m.type(), 'Null', 'type returns Null')

  t.end()
})

test('Null value', t => {
  const x = 'some value'
  const m = Null(x)

  t.ok(isFunction(m.value), 'is a function')
  t.equal(m.value(), null,'value always returns null' )

  t.end()
})

test('Null equals functionality', t => {
  const a = Null(0)
  const b = Null(0)
  const c = Null(1)

  const value = 0
  const nonNull = MockCrock(value)

  t.equal(a.equals(c), true, 'returns true when 2 Nulls initial values are not equal')
  t.equal(a.equals(b), true, 'returns true when 2 Nulls initial values are equal')
  t.equal(a.equals(value), false, 'returns false when passed a simple value')
  t.equal(a.equals(nonNull), false, 'returns false when passed a non-Null')

  t.end()
})

test('Null equals properties (Setoid)', t => {
  const a = Null(0)
  const b = Null(0)
  const c = Null(1)
  const d = Null(0)

  t.ok(isFunction(Null(0).equals), 'provides an equals function')
  t.equal(a.equals(a), true, 'reflexivity')
  t.equal(a.equals(b), b.equals(a), 'symmetry (equal)')
  t.equal(a.equals(c), c.equals(a), 'symmetry (!equal)')
  t.equal(a.equals(b) && b.equals(d), a.equals(d), 'transitivity')

  t.end()
})

test('Null concat properties (Semigoup)', t => {
  const a = Null(0)
  const b = Null(true)
  const c = Null('')

  const left  = a.concat(b).concat(c)
  const right = a.concat(b.concat(c))

  t.ok(isFunction(a.concat), 'provides a concat function')
  t.equal(left.value(), right.value(), 'associativity')
  t.equal(a.concat(b).type(), a.type(), 'returns a Null')

  t.end()
})

test('Null concat functionality', t => {
  const a = Null(23)
  const b = Null(null)

  const notNull = MockCrock()

  const cat = bindFunc(a.concat)

  t.throws(cat(undefined), TypeError, 'throws with undefined')
  t.throws(cat(null), TypeError, 'throws with null')
  t.throws(cat(0), TypeError, 'throws with falsey number')
  t.throws(cat(1), TypeError, 'throws with truthy number')
  t.throws(cat(''), TypeError, 'throws with falsey string')
  t.throws(cat('string'), TypeError, 'throws with truthy string')
  t.throws(cat(false), TypeError, 'throws with false')
  t.throws(cat(true), TypeError, 'throws with true')
  t.throws(cat([]), TypeError, 'throws with an array')
  t.throws(cat({}), TypeError, 'throws with an object')
  t.throws(cat(notNull), TypeError, 'throws when passed non-Null')

  t.equal(a.concat(b).value(), null, 'reports null for 23')
  t.equal(b.concat(a).value(), null, 'null for true')

  t.end()
})

test('Null empty properties (Monoid)', t => {
  const m = Null(3)

  t.ok(isFunction(m.concat), 'provides a concat function')
  t.ok(isFunction(m.empty), 'provides an empty function')

  const right = m.concat(m.empty())
  const left  = m.empty().concat(m)

  t.equal(right.value(), m.value(), 'right identity')
  t.equal(left.value(), m.value(), 'left identity')

  t.end()
})

test('Null empty functionality', t => {
  const x = Null(0).empty()

  t.equal(x.type(), 'Null', 'provides a Null')
  t.equal(x.value(), null, 'wraps a null value')

  t.end()
})

test('Null map errors', t => {
  const map = bindFunc(Null(0).map)

  t.throws(map(undefined), TypeError, 'throws when passed undefined')
  t.throws(map(null), TypeError, 'throws when passed null')
  t.throws(map(0), TypeError, 'throws when passed falsey number')
  t.throws(map(1), TypeError, 'throws when passed truthy number')
  t.throws(map(''), TypeError, 'throws when passed falsey string')
  t.throws(map('string'), TypeError, 'throws when passed truthy string')
  t.throws(map(false), TypeError, 'throws when passed false')
  t.throws(map(true), TypeError, 'throws when passed true')
  t.throws(map([]), TypeError, 'throws when passed an array')
  t.throws(map({}), TypeError, 'throws when passed an object')
  t.doesNotThrow(map(noop))

  t.end()
})

test('Null map functionality', t => {
  const spy = sinon.spy(x => x + 2)
  const x   = 42

  const m = Null(x).map(spy)

  t.equal(m.type(), 'Null', 'returns a Null')
  t.notOk(spy.called, 'does not call mapping function')
  t.equal(m.value(), null, 'returns null')

  t.end()
})

test('Null map properties (Functor)', t => {
  const m = Null(10)

  const f = x => x + 54
  const g = x => x * 4

  t.ok(isFunction(m.map), 'provides a map function')

  t.equal(m.map(identity).value(), m.value(), 'identity')
  t.equal(m.map(composeB(f, g)).value(), m.map(g).map(f).value(), 'composition')

  t.end()
})

test('Null ap errors', t => {
  const m  = MockCrock('joy')
  const ap = bindFunc(Null(32).ap)

  t.throws(ap(undefined), TypeError, 'throws when passed undefined')
  t.throws(ap(null), TypeError, 'throws when passed null')
  t.throws(ap(0), TypeError, 'throws when passed a falsey number')
  t.throws(ap(1), TypeError, 'throws when passed a truthy number')
  t.throws(ap(''), TypeError, 'throws when passed a falsey string')
  t.throws(ap('string'), TypeError, 'throws when passed a truthy string')
  t.throws(ap(false), TypeError, 'throws when passed false')
  t.throws(ap(true), TypeError, 'throws when passed true')
  t.throws(ap([]), TypeError, 'throws when passed an array')
  t.throws(ap({}), TypeError, 'throws when passed an object')

  t.throws(ap(m), TypeError, 'throws when container types differ')

  t.end()
})

test('Null ap properties (Apply)', t => {
  const m = Null({ some: 'thing' })

  const a = m.map(composeB).ap(m).ap(m)
  const b = m.ap(m.ap(m))

  t.ok(isFunction(Null(0).map), 'implements the Functor spec')
  t.ok(isFunction(Null(0).ap), 'provides an ap function')

  t.same(a.ap(Null(3)).value(), b.ap(Null(3)).value(), 'composition')

  t.end()
})

test('Null of', t => {
  t.equal(Null.of, Null(0).of, 'Null.of is the same as the instance version')
  t.equal(Null.of(0).type(), 'Null', 'returns a Null')
  t.equal(Null.of(0).value(), null, 'returns the default null value')

  t.end()
})

test('Null of properties (Applicative)', t => {
  const m = Null(identity)

  t.ok(isFunction(Null(0).of), 'provides an of function')
  t.ok(isFunction(Null(0).ap), 'implements the Apply spec')

  t.equal(m.ap(Null(3)).value(), null, 'identity')
  t.equal(m.ap(Null.of(3)).value(), Null.of(identity(3)).value(), 'homomorphism')

  const a = x => m.ap(Null.of(x))
  const b = x => Null.of(reverseApply(x)).ap(m)

  t.equal(a(3).value(), b(3).value(), 'interchange')

  t.end()
})

test('Null chain errors', t => {
  const chain = bindFunc(Null(0).chain)

  t.throws(chain(undefined), TypeError, 'throws with undefined')
  t.throws(chain(null), TypeError, 'throws with null')
  t.throws(chain(0), TypeError, 'throws with falsey number')
  t.throws(chain(1), TypeError, 'throws with truthy number')
  t.throws(chain(''), TypeError, 'throws with falsey string')
  t.throws(chain('string'), TypeError, 'throws with truthy string')
  t.throws(chain(false), TypeError, 'throws with false')
  t.throws(chain(true), TypeError, 'throws with true')
  t.throws(chain([]), TypeError, 'throws with an array')
  t.throws(chain({}), TypeError, 'throws with an object')

  t.doesNotThrow(chain(noop), 'allows any function')

  t.end()
})

test('Null chain properties (Chain)', t => {
  t.ok(isFunction(Null(0).chain), 'provides a chain function')
  t.ok(isFunction(Null(0).ap), 'implements the Apply spec')

  const f = x => Null(x + 2)
  const g = x => Null(x + 10)

  const a = x => Null(x).chain(f).chain(g)
  const b = x => Null(x).chain(y => f(y).chain(g))

  t.equal(a(10).value(), b(10).value(), 'assosiativity')

  t.end()
})

test('Identity chain properties (Monad)', t => {
  t.ok(isFunction(Null(0).chain), 'implements the Chain spec')
  t.ok(isFunction(Null(0).of), 'implements the Applicative spec')

  const f = x => Null(x)

  t.equal(Null.of(56).chain(f).value(), f(56).value(), 'left identity')

  t.equal(f(3).chain(Null.of).value(), f(3).value(), 'right identity')

  t.end()
})
<|endoftext|>


<commit_before>var app = angular.module('RadioBrowserApp');

app.controller('ListController', function (radiobrowser, audioplayer, relLink, $stateParams, $state) {
    var vm = this;

    var resultListFull = [];
    var relLinkCorrected = relLink.value;

    console.log($stateParams);
    if ($stateParams.complex) {
        var items = [];
        if ($stateParams.name) {
            items.push('name=' + encodeURIComponent($stateParams.name));
        }
        if ($stateParams.country) {
            items.push('country=' + encodeURIComponent($stateParams.country));
        }
        if ($stateParams.state) {
            items.push('state=' + encodeURIComponent($stateParams.state));
        }
        if ($stateParams.tag) {
            items.push('tag=' + encodeURIComponent($stateParams.tag));
        }
        items.push('limit=' + encodeURIComponent('100'));
        relLinkCorrected = '/json/stations/search?' + items.join('&');
    } else if ($stateParams.tag) {
        relLinkCorrected = '/json/stations/bytagexact/' + encodeURIComponent($stateParams.tag);
    } else if ($stateParams.state) {
        relLinkCorrected = '/json/stations/bystateexact/' + encodeURIComponent($stateParams.state);
    } else if ($stateParams.country) {
        relLinkCorrected = '/json/stations/bycountryexact/' + encodeURIComponent($stateParams.country);
    } else if ($stateParams.language) {
        relLinkCorrected = '/json/stations/bylanguageexact/' + encodeURIComponent($stateParams.language);
    } else if ($stateParams.codec) {
        relLinkCorrected = '/json/stations/bycodecexact/' + encodeURIComponent($stateParams.codec);
    } else if ($stateParams.name) {
        relLinkCorrected = '/json/stations/byname/' + encodeURIComponent($stateParams.name);
    }

    function changeItemsPerPage(items) {
        vm.itemsPerPage = items;
        updateList();
    }

    function updateList() {
        vm.resultList = resultListFull.slice((vm.bigCurrentPage - 1) * vm.itemsPerPage, (vm.bigCurrentPage) * vm.itemsPerPage);
    }

    function vote(station) {
        radiobrowser.get('/json/vote/' + station.id).then(function (data) {
            if (data.data.ok === "true") {
                station.votes = parseInt(station.votes) + 1;
            } else {
                alert("could not vote for station: " + data.data.message);
            }
            updateList();
        }, function (err) {
            console.log("error:" + err);
        });
    }

    function displayList() {
        radiobrowser.get(relLinkCorrected).then(function (data) {
            resultListFull = data.data;
            vm.bigCurrentPage = 1;
            vm.bigTotalItems = data.data.length;
            updateList();
        }, function (err) {
            console.error(err);
        });
    }

    function revertStation(stationid, changeid) {
        console.log("revertStation:" + stationid + "  " + changeid);
        radiobrowser.get('/json/revert/' + stationid + '/' + changeid).then(function (data) {
            $state.go('lastchange');
            if (data.data.ok === "true") {
                alert("undelete ok");
            } else {
                alert("could not undelete station:" + data.data.message);
            }
        }, function (err) {
            console.log("error:" + err);
        });
    }

    function play(station) {
        // decode playlist
        radiobrowser.get("/json/url/" + station.stationuuid).then(function (data) {
            var stationReal = data.data;
            if (stationReal.ok === true) {
                var video = station.codec.indexOf(',') >= 0;
                audioplayer.play(stationReal.url, stationReal.name, parseInt(station.hls), video);
            }
        }, function (err) {
            console.log("error:" + err);
            alert("could not find station");
        });
    }

    function distinct(list) {
        var result = [];
        for (var i = 0; i < list.length; i++) {
            if (list[i].trim() === "") {
                continue;
            }
            if (result.indexOf(list[i]) < 0) {
                result.push(list[i]);
            }
        }
        return result;
    }

    function getTagsArray(tags_string) {
        if (tags_string.trim() === "") {
            return [];
        }
        return distinct(tags_string.split(','));
    }

    vm.editStation = null;
    vm.resultList = [];
    vm.itemsPerPage = 20;
    vm.bigCurrentPage = 1;
    vm.bigTotalItems = 0;

    vm.revertStation = revertStation;
    vm.vote = vote;
    vm.play = play;
    vm.changeItemsPerPage = changeItemsPerPage;
    vm.getTagsArray = getTagsArray;
    vm.updateList = updateList;

    var SERVER = "https://de1.api.radio-browser.info";

    vm.playlistPLS = SERVER + relLinkCorrected.replace(/json/, 'pls');
    vm.playlistM3U = SERVER + relLinkCorrected.replace(/json/, 'm3u');
    vm.playlistXSPF = SERVER + relLinkCorrected.replace(/json/, 'xspf');

    displayList();
});
<commit_msg>voting fixed<commit_after>var app = angular.module('RadioBrowserApp');

app.controller('ListController', function (radiobrowser, audioplayer, relLink, $stateParams, $state) {
    var vm = this;

    var resultListFull = [];
    var relLinkCorrected = relLink.value;

    console.log($stateParams);
    if ($stateParams.complex) {
        var items = [];
        if ($stateParams.name) {
            items.push('name=' + encodeURIComponent($stateParams.name));
        }
        if ($stateParams.country) {
            items.push('country=' + encodeURIComponent($stateParams.country));
        }
        if ($stateParams.state) {
            items.push('state=' + encodeURIComponent($stateParams.state));
        }
        if ($stateParams.tag) {
            items.push('tag=' + encodeURIComponent($stateParams.tag));
        }
        items.push('limit=' + encodeURIComponent('100'));
        relLinkCorrected = '/json/stations/search?' + items.join('&');
    } else if ($stateParams.tag) {
        relLinkCorrected = '/json/stations/bytagexact/' + encodeURIComponent($stateParams.tag);
    } else if ($stateParams.state) {
        relLinkCorrected = '/json/stations/bystateexact/' + encodeURIComponent($stateParams.state);
    } else if ($stateParams.country) {
        relLinkCorrected = '/json/stations/bycountryexact/' + encodeURIComponent($stateParams.country);
    } else if ($stateParams.language) {
        relLinkCorrected = '/json/stations/bylanguageexact/' + encodeURIComponent($stateParams.language);
    } else if ($stateParams.codec) {
        relLinkCorrected = '/json/stations/bycodecexact/' + encodeURIComponent($stateParams.codec);
    } else if ($stateParams.name) {
        relLinkCorrected = '/json/stations/byname/' + encodeURIComponent($stateParams.name);
    }

    function changeItemsPerPage(items) {
        vm.itemsPerPage = items;
        updateList();
    }

    function updateList() {
        vm.resultList = resultListFull.slice((vm.bigCurrentPage - 1) * vm.itemsPerPage, (vm.bigCurrentPage) * vm.itemsPerPage);
    }

    function vote(station) {
        radiobrowser.get('/json/vote/' + station.stationuuid).then(function (data) {
            if (data.data.ok === "true") {
                station.votes = parseInt(station.votes) + 1;
            } else {
                alert("could not vote for station: " + data.data.message);
            }
            updateList();
        }, function (err) {
            console.log("error:" + err);
        });
    }

    function displayList() {
        radiobrowser.get(relLinkCorrected).then(function (data) {
            resultListFull = data.data;
            vm.bigCurrentPage = 1;
            vm.bigTotalItems = data.data.length;
            updateList();
        }, function (err) {
            console.error(err);
        });
    }

    function revertStation(stationid, changeid) {
        console.log("revertStation:" + stationid + "  " + changeid);
        radiobrowser.get('/json/revert/' + stationid + '/' + changeid).then(function (data) {
            $state.go('lastchange');
            if (data.data.ok === "true") {
                alert("undelete ok");
            } else {
                alert("could not undelete station:" + data.data.message);
            }
        }, function (err) {
            console.log("error:" + err);
        });
    }

    function play(station) {
        // decode playlist
        radiobrowser.get("/json/url/" + station.stationuuid).then(function (data) {
            var stationReal = data.data;
            if (stationReal.ok === true) {
                var video = station.codec.indexOf(',') >= 0;
                audioplayer.play(stationReal.url, stationReal.name, parseInt(station.hls), video);
            }
        }, function (err) {
            console.log("error:" + err);
            alert("could not find station");
        });
    }

    function distinct(list) {
        var result = [];
        for (var i = 0; i < list.length; i++) {
            if (list[i].trim() === "") {
                continue;
            }
            if (result.indexOf(list[i]) < 0) {
                result.push(list[i]);
            }
        }
        return result;
    }

    function getTagsArray(tags_string) {
        if (tags_string.trim() === "") {
            return [];
        }
        return distinct(tags_string.split(','));
    }

    vm.editStation = null;
    vm.resultList = [];
    vm.itemsPerPage = 20;
    vm.bigCurrentPage = 1;
    vm.bigTotalItems = 0;

    vm.revertStation = revertStation;
    vm.vote = vote;
    vm.play = play;
    vm.changeItemsPerPage = changeItemsPerPage;
    vm.getTagsArray = getTagsArray;
    vm.updateList = updateList;

    var SERVER = "https://de1.api.radio-browser.info";

    vm.playlistPLS = SERVER + relLinkCorrected.replace(/json/, 'pls');
    vm.playlistM3U = SERVER + relLinkCorrected.replace(/json/, 'm3u');
    vm.playlistXSPF = SERVER + relLinkCorrected.replace(/json/, 'xspf');

    displayList();
});
<|endoftext|>


<commit_before>'use strict';

const Note = require('../models/note');

module.exports.edit = (req, res) => {
  Note.findById(req.params.id, (err, note) => {
    if (err) throw err;

    res.render('new-note', {note: note});
  });
};

module.exports.update = (req, res) => {
  Note.findByIdAndUpdate(req.params.id,
    req.body, (err, note) => {
      if (err) throw err;

      res.redirect(`/notes/${note._id}`);
    }
  );
};

module.exports.index = (req, res) => {
  Note.find({}, (err, notes) => {
    if (err) throw err;

    res.render('notes-index', {notes: notes});
  });
};

module.exports.newNote = (req, res) => {
  res.render('new-note');
};

module.exports.show = (req, res) => {
  Note.findById(req.params.id, (err, note) => {
    if (err) throw err;

    res.render('show-note', {note: note});
  });
};

module.exports.create = (req, res) => {
  Note.create(req.body, (err, note) => {
    if (err) throw err;

    res.redirect(`/notes/${note._id}`);
  });
};

module.exports.destroy = (req, res) => {
  Note.findByIdAndRemove(req.params.id, (err) => {
    if (err) throw err;

    res.redirect('/notes');
  });
};
<commit_msg>use enhanced object literals in controller<commit_after>'use strict';

const Note = require('../models/note');

module.exports = {
  edit (req, res) {
    Note.findById(req.params.id, (err, note) => {
      if (err) throw err;

      res.render('new-note', {note: note});
    });
  },

  update (req, res) {
    Note.findByIdAndUpdate(req.params.id,
      req.body, (err, note) => {
        if (err) throw err;

        res.redirect(`/notes/${note._id}`);
      }
    );
  },

  index (req, res) {
    Note.find({}, (err, notes) => {
      if (err) throw err;

      res.render('notes-index', {notes: notes});
    });
  },

  newNote (req, res) {
    res.render('new-note');
  },

  show (req, res) {
    Note.findById(req.params.id, (err, note) => {
      if (err) throw err;

      res.render('show-note', {note: note});
    });
  },

  create (req, res) {
    Note.create(req.body, (err, note) => {
      if (err) throw err;

      res.redirect(`/notes/${note._id}`);
    });
  },

  destroy (req, res) {
    Note.findByIdAndRemove(req.params.id, (err) => {
      if (err) throw err;

      res.redirect('/notes');
    });
  }
};
<|endoftext|>