<commit_before>var _ = require("./_");
var { getCards, getSets, getMws, getRandomSet, getExpansionOrCoreModernSets: getModernList, getExansionOrCoreSets: getSetsList } = require("./data");

function selectRarity(set) {
  // average pack contains:
  // 14 cards
  // 10 commons
  // 3 uncommons
  // 7/8 rare
  // 1/8 mythic
  // * 8 -> 112/80/24/7/1

  let n = _.rand(112);
  if (n < 1)
    return set.mythic;
  if (n < 8)
    return set.rare;
  if (n < 32)
    return set.uncommon;
  return set.common;
}

function pickFoil(set) {
  var rngFoil = _.rand(6);
  if (rngFoil < 1)
    if (set.mythic)
      if (_.rand(set.mythic.length + (set.rare.length * 2)) < set.mythic.length)
        return set.mythic;
      else
        return set.rare;
    else
      return set.rare;
  if (rngFoil < 3)
    return set.uncommon;
  return set.common;
}

function toPack(code) {
  var set = getSets()[code];
  var { basic, common, uncommon, rare, mythic, special, size } = set;

  if (mythic && !_.rand(8))
    rare = mythic;

  if (!rare.length) {
    rare = uncommon; //In some sets rare didn't exist. So we replace them with uncommons
  }

  //make small sets draftable.
  if (size < 10 && code != "SOI" && code != "EMN")
    size = 10;

  var pack = [].concat(
    _.choose(3, uncommon),
    _.choose(1, rare)
  );

  if (code == "SOI")
    //http://markrosewater.tumblr.com/post/141794840953/if-the-as-fan-of-double-face-cards-is-1125-that
    if (_.rand(8) == 0) {
      size = size - 1;
      if (_.rand(15) < 3)
        pack.push(_.choose(1, special.mythic));
      else
        pack.push(_.choose(1, special.rare));
    }
  if (code == "EMN")
    if (_.rand(8) == 0) {
      size = size - 1;
      if (_.rand(5) < 1)
        pack.push(_.choose(1, special.mythic));
      else
        pack.push(_.choose(1, special.rare));
    }
  let foilCard = false;
  let specialrnd;
  switch (code) {
  case "EMN":
    if (_.rand(2) < 1)
      special = special.uncommon;
    else
      special = special.common;
    break;

  case "SOI":
    if (_.rand(106) < 38)
      special = special.uncommon;
    else
      special = special.common;
    break;
  case "DGM":
    special = _.rand(20)
      ? special.gate
      : special.shock;
    break;
  case "EMA":
  case "MMA":
  case "MM2":
  case "MM3":
  case "IMA":
  case "UMA":
    special = selectRarity(set);
    foilCard = true;
    break;
  case "VMA":
    //http://www.wizards.com/magic/magazine/article.aspx?x=mtg/daily/arcana/1491
    if (_.rand(53))
      special = selectRarity(set);
    break;
  case "FRF":
    special = _.rand(20)
      ? special.common
      : special.fetch;
    break;
  case "ISD":
    //http://www.mtgsalvation.com/forums/magic-fundamentals/magic-general/327956-innistrad-block-transforming-card-pack-odds?comment=4
    //121 card sheet, 1 mythic, 12 rare (13), 42 uncommon (55), 66 common
    specialrnd = _.rand(121);
    if (specialrnd == 0)
      special = special.mythic;
    else if (specialrnd < 13)
      special = special.rare;
    else if (specialrnd < 55)
      special = special.uncommon;
    else
      special = special.common;
    break;
  case "DKA":
    //http://www.mtgsalvation.com/forums/magic-fundamentals/magic-general/327956-innistrad-block-transforming-card-pack-odds?comment=4
    //80 card sheet, 2 mythic, 6 rare (8), 24 uncommon (32), 48 common
    specialrnd = _.rand(80);
    if (specialrnd <= 1)
      special = special.mythic;
    else if (specialrnd < 8)
      special = special.rare;
    else if (specialrnd < 32)
      special = special.uncommon;
    else
      special = special.common;
    break;
  case "DOM": {
    // http://markrosewater.tumblr.com/post/172581930278/do-the-legendaries-that-appear-in-the-legendary
    // Every booster must contain a legendary creature either as uncommon or rare
    let hasLegendaryCreature = false;
    const isLegendaryCreature = cardName => {
      const card = getCards()[cardName];
      return card.supertypes.includes("Legendary") && card.type === "Creature";
    };

    pack.some(cardName => {
      return hasLegendaryCreature = isLegendaryCreature(cardName);
    });

    if (!hasLegendaryCreature) {
      var packIndex = 0;
      var pool = uncommon;
      // Choose to replace an uncommon(default) or rare slot
      if (_.rand(4) === 0) {
        packIndex = 3;
        var isMythic = mythic.includes(pack[packIndex]);
        pool = isMythic ? mythic : rare;
      }
      const legendaryCreatures = pool.filter(isLegendaryCreature);
      pack[packIndex] = _.choose(1, legendaryCreatures);
    }
    break;
  }
  case "M19": {
    //http://wizardsmagic.tumblr.com/post/175584204911/core-set-2019-packs-basic-lands-and-upcoming
    // 5/12 of times -> dual-land
    // 7/12 of times -> basic land
    const dualLands = common.filter(cardName => getCards()[cardName].type === "Land");
    common = common.filter(cardName => !dualLands.includes(cardName)); //delete dualLands from possible choice as common slot
    const isDualLand = _.rand(12) < 6;
    const land = _.choose(1, isDualLand ? dualLands : basic);
    pack.push(...land);
    break;
  }
  case "GRN":
  case "RNA": {
    // No basics. Always 1 common slots are occupied by guildgates
    const guildGates = common.filter(cardName => getCards()[cardName].type === "Land" && getCards()[cardName].sets[code].rarity == "common");
    common = common.filter(cardName => !guildGates.includes(cardName)); //delete guildGates from possible choice as common slot
    pack.push(_.choose(1, guildGates));
    break;
  }
  }
  var masterpiece = "";
  if (special) {
    if (special.masterpieces) {
      if (_.rand(144) == 0) {
        size = size - 1;
        specialpick = _.choose(1, special.masterpieces);
        specialpick = specialpick[0];
        pack.push(specialpick);
        masterpiece = specialpick;
      }
      special = 0;
    }
    else {
      var specialpick = _.choose(1, special);
      specialpick = specialpick[0];
      pack.push(specialpick);
      if (foilCard) {
        foilCard = specialpick;
      }
    }
  }
  if (_.rand(7) < 1 && !(foilCard) && !(masterpiece)) {
    // http://www.mtgsalvation.com/forums/magic-fundamentals/magic-general/768235-what-are-current-pack-odds-including-foils
    size = size - 1;
    foilCard = _.choose(1, pickFoil(set));
    pack.push(foilCard[0]);
  }
  pack = _.choose(size, common).concat(pack);

  return toCards(pack, code, foilCard, masterpiece);
}

function toCards(pool, code, foilCard, masterpiece) {
  var isCube = !code;
  var packSize = pool.length;
  return pool.map(cardName => {
    var card = Object.assign({}, getCards()[cardName]);
    card.packSize = packSize;
    var { sets } = card;

    if (isCube)
      [code] = Object.keys(sets)
        .filter(set => !["EXP", "MPS", "MPS_AKH"].includes(set)); // #121: Filter Invocations art

    card.code = getMws()[code] || code;
    var set = sets[code];

    if (masterpiece == card.name.toString().toLowerCase()) {
      card.rarity = "special";
      card.foil = true;
      if (code == "BFZ" || code == "OGW") {
        card.code = "EXP";
      } else if (code == "KLD" || code == "AER") {
        card.code = "MPS";
      } else if (code == "AKH" || code == "HOU") {
        card.code = "MPS_AKH";
      }
      set = sets[card.code];
      masterpiece = "";
    }
    if (foilCard == card.name.toString().toLowerCase()) {
      card.foil = true;
      foilCard = "";
    }
    delete card.sets;
    return Object.assign(card, set);
  });
}

const SealedCube = ({ cubeList, playersLength, playerPoolSize = 90 }) => {
  return DraftCube({
    cubeList,
    playersLength,
    packsNumber: 1,
    playerPackSize: playerPoolSize
  });
};

const DraftCube = ({ cubeList, playersLength, packsNumber = 3, playerPackSize = 15 }) => {
  let list = _.shuffle(cubeList); // copy the list to work on it

  return new Array(playersLength * packsNumber).fill()
    .map(() => {
      const playerPool = list.splice(0, playerPackSize);
      return toCards(playerPool);
    });
};

// Replace RNG set with real set
const  replaceRNGSet = (sets) => (
  sets.map(set => set === "RNG" ? getRandomSet().code : set)
);

const SealedNormal = ({ playersLength, sets }) => (
  new Array(playersLength).fill(replaceRNGSet(sets))
    .map(sets => sets.flatMap(toPack))
);

const DraftNormal = ({ playersLength, sets }) => (
  replaceRNGSet(sets)
    .flatMap(set => new Array(playersLength).fill(set))
    .map(toPack)
);

// Get a random set and transform it to pack
function getRandomPack(setList) {
  const code = chooseRandomSet(setList).code;
  return toPack(code);
}

const chooseRandomSet = (setList) => (
  _.choose(1, setList)[0]
);

// Create a complete random pack
function getTotalChaosPack(setList) {
  const chaosPool = [];
  const randomSet = chooseRandomSet(setList);

  // Check if set has at least rares
  if (randomSet.rare && randomSet.rare.length > 0) {
    const isMythic = randomSet.mythic && !_.rand(8);
    chaosPool.push(_.choose(1, isMythic ? randomSet.mythic : randomSet.rare));
  } else {
    //If no rare exists for the set, we pick an uncommon
    chaosPool.push(_.choose(1, randomSet.uncommon));
  }

  for (let k = 0; k < 3; k++) {
    chaosPool.push(_.choose(1, chooseRandomSet(setList).uncommon));
  }

  for (let k = 0; k < 11; k++) {
    chaosPool.push(_.choose(1, chooseRandomSet(setList).common));
  }
  return toCards(chaosPool);
}

const DraftChaos = ({ playersLength, packsNumber = 3, modernOnly, totalChaos }) => {
  const setList = modernOnly ? getModernList() : getSetsList();

  return new Array(playersLength * packsNumber).fill()
    .map(() => totalChaos ? getTotalChaosPack(setList) : getRandomPack(setList));
};

const SealedChaos = ({ playersLength, packsNumber = 6, modernOnly, totalChaos }) => {
  const pool = DraftChaos({playersLength, packsNumber, modernOnly, totalChaos});
  return new Array(playersLength).fill()
    .map(() => pool.splice(0, packsNumber).flat());
};

module.exports = {
  SealedCube,
  DraftCube,
  SealedNormal,
  DraftNormal,
  SealedChaos,
  DraftChaos
};
<commit_msg>Adds a planeswalker to every WAR booster (#443)<commit_after>var _ = require("./_");
var { getCards, getSets, getMws, getRandomSet, getExpansionOrCoreModernSets: getModernList, getExansionOrCoreSets: getSetsList } = require("./data");

function selectRarity(set) {
  // average pack contains:
  // 14 cards
  // 10 commons
  // 3 uncommons
  // 7/8 rare
  // 1/8 mythic
  // * 8 -> 112/80/24/7/1

  let n = _.rand(112);
  if (n < 1)
    return set.mythic;
  if (n < 8)
    return set.rare;
  if (n < 32)
    return set.uncommon;
  return set.common;
}

function pickFoil(set) {
  var rngFoil = _.rand(6);
  if (rngFoil < 1)
    if (set.mythic)
      if (_.rand(set.mythic.length + (set.rare.length * 2)) < set.mythic.length)
        return set.mythic;
      else
        return set.rare;
    else
      return set.rare;
  if (rngFoil < 3)
    return set.uncommon;
  return set.common;
}

function toPack(code) {
  var set = getSets()[code];
  var { basic, common, uncommon, rare, mythic, special, size } = set;

  if (mythic && !_.rand(8))
    rare = mythic;

  if (!rare.length) {
    rare = uncommon; //In some sets rare didn't exist. So we replace them with uncommons
  }

  //make small sets draftable.
  if (size < 10 && code != "SOI" && code != "EMN")
    size = 10;

  var pack = [].concat(
    _.choose(3, uncommon),
    _.choose(1, rare)
  );

  if (code == "SOI")
    //http://markrosewater.tumblr.com/post/141794840953/if-the-as-fan-of-double-face-cards-is-1125-that
    if (_.rand(8) == 0) {
      size = size - 1;
      if (_.rand(15) < 3)
        pack.push(_.choose(1, special.mythic));
      else
        pack.push(_.choose(1, special.rare));
    }
  if (code == "EMN")
    if (_.rand(8) == 0) {
      size = size - 1;
      if (_.rand(5) < 1)
        pack.push(_.choose(1, special.mythic));
      else
        pack.push(_.choose(1, special.rare));
    }
  let foilCard = false;
  let specialrnd;
  switch (code) {
  case "EMN":
    if (_.rand(2) < 1)
      special = special.uncommon;
    else
      special = special.common;
    break;

  case "SOI":
    if (_.rand(106) < 38)
      special = special.uncommon;
    else
      special = special.common;
    break;
  case "DGM":
    special = _.rand(20)
      ? special.gate
      : special.shock;
    break;
  case "EMA":
  case "MMA":
  case "MM2":
  case "MM3":
  case "IMA":
  case "UMA":
    special = selectRarity(set);
    foilCard = true;
    break;
  case "VMA":
    //http://www.wizards.com/magic/magazine/article.aspx?x=mtg/daily/arcana/1491
    if (_.rand(53))
      special = selectRarity(set);
    break;
  case "FRF":
    special = _.rand(20)
      ? special.common
      : special.fetch;
    break;
  case "ISD":
    //http://www.mtgsalvation.com/forums/magic-fundamentals/magic-general/327956-innistrad-block-transforming-card-pack-odds?comment=4
    //121 card sheet, 1 mythic, 12 rare (13), 42 uncommon (55), 66 common
    specialrnd = _.rand(121);
    if (specialrnd == 0)
      special = special.mythic;
    else if (specialrnd < 13)
      special = special.rare;
    else if (specialrnd < 55)
      special = special.uncommon;
    else
      special = special.common;
    break;
  case "DKA":
    //http://www.mtgsalvation.com/forums/magic-fundamentals/magic-general/327956-innistrad-block-transforming-card-pack-odds?comment=4
    //80 card sheet, 2 mythic, 6 rare (8), 24 uncommon (32), 48 common
    specialrnd = _.rand(80);
    if (specialrnd <= 1)
      special = special.mythic;
    else if (specialrnd < 8)
      special = special.rare;
    else if (specialrnd < 32)
      special = special.uncommon;
    else
      special = special.common;
    break;
  case "DOM": {
    // http://markrosewater.tumblr.com/post/172581930278/do-the-legendaries-that-appear-in-the-legendary
    // Every booster must contain a legendary creature either as uncommon or rare
    let hasLegendaryCreature = false;
    const isLegendaryCreature = cardName => {
      const card = getCards()[cardName];
      return card.supertypes.includes("Legendary") && card.type === "Creature";
    };

    pack.some(cardName => {
      return hasLegendaryCreature = isLegendaryCreature(cardName);
    });

    if (!hasLegendaryCreature) {
      var packIndex = 0;
      var pool = uncommon;
      // Choose to replace an uncommon(default) or rare slot
      if (_.rand(4) === 0) {
        packIndex = 3;
        var isMythic = mythic.includes(pack[packIndex]);
        pool = isMythic ? mythic : rare;
      }
      const legendaryCreatures = pool.filter(isLegendaryCreature);
      pack[packIndex] = _.choose(1, legendaryCreatures);
    }
    break;
  }
  case "M19": {
    //http://wizardsmagic.tumblr.com/post/175584204911/core-set-2019-packs-basic-lands-and-upcoming
    // 5/12 of times -> dual-land
    // 7/12 of times -> basic land
    const dualLands = common.filter(cardName => getCards()[cardName].type === "Land");
    common = common.filter(cardName => !dualLands.includes(cardName)); //delete dualLands from possible choice as common slot
    const isDualLand = _.rand(12) < 6;
    const land = _.choose(1, isDualLand ? dualLands : basic);
    pack.push(...land);
    break;
  }
  case "GRN":
  case "RNA": {
    // No basics. Always 1 common slots are occupied by guildgates
    const guildGates = common.filter(cardName => getCards()[cardName].type === "Land" && getCards()[cardName].sets[code].rarity == "common");
    common = common.filter(cardName => !guildGates.includes(cardName)); //delete guildGates from possible choice as common slot
    pack.push(_.choose(1, guildGates));
    break;
  }
  case "WAR": {
    // https://magic.wizards.com/en/articles/archive/feature/closer-look-stained-glass-planeswalkers-2019-03-08
    // Every booster must contain a planeswalker either as uncommon or rare
    const isPlaneswalker = cardName => {
      const card = getCards()[cardName];
      return card.type === "Planeswalker";
    };

    hasPlaneswalker = pack.some(cardName => isPlaneswalker(cardName));

    if (!hasPlaneswalker) {
      var packIndex = _.rand(4);
      var pool = uncommon;
      // Choose to replace an uncommon(default) or rare slot
      if (packIndex === 3) {
        var isMythic = mythic.includes(pack[packIndex]);
        pool = isMythic ? mythic : rare;
      }
      const planeswalkers = pool.filter(isPlaneswalker);
      pack[packIndex] = _.choose(1, planeswalkers);
    }
    break;
  }
  }
  var masterpiece = "";
  if (special) {
    if (special.masterpieces) {
      if (_.rand(144) == 0) {
        size = size - 1;
        specialpick = _.choose(1, special.masterpieces);
        specialpick = specialpick[0];
        pack.push(specialpick);
        masterpiece = specialpick;
      }
      special = 0;
    }
    else {
      var specialpick = _.choose(1, special);
      specialpick = specialpick[0];
      pack.push(specialpick);
      if (foilCard) {
        foilCard = specialpick;
      }
    }
  }
  if (_.rand(7) < 1 && !(foilCard) && !(masterpiece)) {
    // http://www.mtgsalvation.com/forums/magic-fundamentals/magic-general/768235-what-are-current-pack-odds-including-foils
    size = size - 1;
    foilCard = _.choose(1, pickFoil(set));
    pack.push(foilCard[0]);
  }
  pack = _.choose(size, common).concat(pack);

  return toCards(pack, code, foilCard, masterpiece);
}

function toCards(pool, code, foilCard, masterpiece) {
  var isCube = !code;
  var packSize = pool.length;
  return pool.map(cardName => {
    var card = Object.assign({}, getCards()[cardName]);
    card.packSize = packSize;
    var { sets } = card;

    if (isCube)
      [code] = Object.keys(sets)
        .filter(set => !["EXP", "MPS", "MPS_AKH"].includes(set)); // #121: Filter Invocations art

    card.code = getMws()[code] || code;
    var set = sets[code];

    if (masterpiece == card.name.toString().toLowerCase()) {
      card.rarity = "special";
      card.foil = true;
      if (code == "BFZ" || code == "OGW") {
        card.code = "EXP";
      } else if (code == "KLD" || code == "AER") {
        card.code = "MPS";
      } else if (code == "AKH" || code == "HOU") {
        card.code = "MPS_AKH";
      }
      set = sets[card.code];
      masterpiece = "";
    }
    if (foilCard == card.name.toString().toLowerCase()) {
      card.foil = true;
      foilCard = "";
    }
    delete card.sets;
    return Object.assign(card, set);
  });
}

const SealedCube = ({ cubeList, playersLength, playerPoolSize = 90 }) => {
  return DraftCube({
    cubeList,
    playersLength,
    packsNumber: 1,
    playerPackSize: playerPoolSize
  });
};

const DraftCube = ({ cubeList, playersLength, packsNumber = 3, playerPackSize = 15 }) => {
  let list = _.shuffle(cubeList); // copy the list to work on it

  return new Array(playersLength * packsNumber).fill()
    .map(() => {
      const playerPool = list.splice(0, playerPackSize);
      return toCards(playerPool);
    });
};

// Replace RNG set with real set
const  replaceRNGSet = (sets) => (
  sets.map(set => set === "RNG" ? getRandomSet().code : set)
);

const SealedNormal = ({ playersLength, sets }) => (
  new Array(playersLength).fill(replaceRNGSet(sets))
    .map(sets => sets.flatMap(toPack))
);

const DraftNormal = ({ playersLength, sets }) => (
  replaceRNGSet(sets)
    .flatMap(set => new Array(playersLength).fill(set))
    .map(toPack)
);

// Get a random set and transform it to pack
function getRandomPack(setList) {
  const code = chooseRandomSet(setList).code;
  return toPack(code);
}

const chooseRandomSet = (setList) => (
  _.choose(1, setList)[0]
);

// Create a complete random pack
function getTotalChaosPack(setList) {
  const chaosPool = [];
  const randomSet = chooseRandomSet(setList);

  // Check if set has at least rares
  if (randomSet.rare && randomSet.rare.length > 0) {
    const isMythic = randomSet.mythic && !_.rand(8);
    chaosPool.push(_.choose(1, isMythic ? randomSet.mythic : randomSet.rare));
  } else {
    //If no rare exists for the set, we pick an uncommon
    chaosPool.push(_.choose(1, randomSet.uncommon));
  }

  for (let k = 0; k < 3; k++) {
    chaosPool.push(_.choose(1, chooseRandomSet(setList).uncommon));
  }

  for (let k = 0; k < 11; k++) {
    chaosPool.push(_.choose(1, chooseRandomSet(setList).common));
  }
  return toCards(chaosPool);
}

const DraftChaos = ({ playersLength, packsNumber = 3, modernOnly, totalChaos }) => {
  const setList = modernOnly ? getModernList() : getSetsList();

  return new Array(playersLength * packsNumber).fill()
    .map(() => totalChaos ? getTotalChaosPack(setList) : getRandomPack(setList));
};

const SealedChaos = ({ playersLength, packsNumber = 6, modernOnly, totalChaos }) => {
  const pool = DraftChaos({playersLength, packsNumber, modernOnly, totalChaos});
  return new Array(playersLength).fill()
    .map(() => pool.splice(0, packsNumber).flat());
};

module.exports = {
  SealedCube,
  DraftCube,
  SealedNormal,
  DraftNormal,
  SealedChaos,
  DraftChaos
};
<|endoftext|>


<commit_before>
var assert = require('assert');
var carto = require('../lib/carto');
describe('RenderingJS', function() {
  var shader;
  var style = [
  '#world {',
    'line-width: 2;',
    'line-color: #f00;',
    '[frame-offset = 1] {',
      'line-width: 3;',
    '}',
    '[frame-offset = 2] {',
      'line-width: 3;',
    '}',
  '}',
  '',
  '#worls[frame-offset = 10] {',
      'line-width: 4;',
  '}'
  ].join('\n');

  beforeEach(function() {
    shader = (new carto.RendererJS({ debug: false })).render(style);
  });

  it ("shold render layers", function() {
    assert(shader.getLayers().length === 2);
  });

  it ("shold report frames used in the layer", function() {
    var layer = shader.getLayers()[0];
    assert( layer.frames()[0] === 0);
    assert( layer.frames()[1] === 1);

    layer = shader.getLayers()[1];
    assert( layer.frames()[0] === 10);
  });

  it ("shold render with frames var", function() {
    var layer = shader.getLayers()[1];
    var props = layer.getStyle({}, { 'zoom': 0, 'frame-offset': 10 });
    assert( props['line-width'] === 4);
  });

  it ("shold render variables", function() {
    var style = '#test { marker-width: [testing]; }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({testing: 2}, { 'zoom': 0, 'frame-offset': 10 });
    assert( props['marker-width'] === 2);
  });

  it ("should allow filter based rendering", function() {
    var style = '#test { marker-width: 10; [zoom = 1] { marker-width: 1; } }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({}, { 'zoom': 0, 'frame-offset': 10 });
    assert( props['marker-width'] ===  10);
    props = layer.getStyle({}, { 'zoom': 1, 'frame-offset': 10 });
    assert( props['marker-width'] ===  1);
  });

  it ("symbolizers should be in rendering order", function() {
    var style = '#test { polygon-fill: red; line-color: red; }';
    style += '#test2 { line-color: red;polygon-fill: red; line-witdh: 10; }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer0 = shader.getLayers()[0];
    assert(layer0.getSymbolizers()[0] === 'polygon');
    assert(layer0.getSymbolizers()[1] === 'line');

    var layer1 = shader.getLayers()[1];
    assert(layer0.getSymbolizers()[0] === 'polygon');
    assert(layer0.getSymbolizers()[1] === 'line');
  });

  it ("colorize should return a list of colours in same order", function() {
    var style = '#test { image-filters: colorize-alpha(blue, cyan, green, yellow, orange, red); }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer0 = shader.getLayers()[0];
    var st = layer0.getStyle({ value: 1 }, {"frame-offset": 0, "zoom": 3});
    var expectedColours = [[0, 0, 255], [0, 255, 255], [0, 128, 0], [255, 255, 0], [255, 165, 0], [255, 0, 0]];
    for (var i = 0; i < st["image-filters"].args; i++){
      assert (st["image-filters"].args[i].rgb === expectedColours[i]);
    }
  });

  it ("should return list of marker-files", function(){
    var css = [
          'Map {',
          '-torque-time-attribute: "date";',
          '-torque-aggregation-function: "count(cartodb_id)";',
          '-torque-frame-count: 760;',
          '-torque-animation-duration: 15;',
          '-torque-resolution: 2',
          '}',
          '#layer {',
          '  marker-width: 3;',
          '  marker-fill-opacity: 0.8;',
          '  marker-fill: #FEE391; ',
          '  marker-file: url(http://localhost:8081/gal.svg); ',
          '  comp-op: "lighten";',
          '  [value > 2] { marker-file: url(http://upload.wikimedia.org/wikipedia/commons/4/43/Flag_of_the_Galactic_Empire.svg); }',
          '  [value > 3] { marker-file: url(http://upload.wikimedia.org/wikipedia/commons/c/c9/Flag_of_Syldavia.svg); }',
          '  [frame-offset = 1] { marker-width: 10; marker-fill-opacity: 0.05;}',
          '  [frame-offset = 2] { marker-width: 15; marker-fill-opacity: 0.02;}',
          '}'
      ].join('\n');
      var shader = (new carto.RendererJS({ debug: true })).render(css);
      var markerURLs = shader.getImageURLs();
      var against = ["http://localhost:8081/gal.svg", "http://upload.wikimedia.org/wikipedia/commons/4/43/Flag_of_the_Galactic_Empire.svg", "http://upload.wikimedia.org/wikipedia/commons/c/c9/Flag_of_Syldavia.svg"];
      for(var i = 0; i<against.length; i++){
        assert(against[i] == markerURLs[i])
      }
  })

  it ("should return variable for styles that change", function() {
    var style = '#test { marker-width: [prop]; }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer0 = shader.getLayers()[0];
    assert(layer0.isVariable());

    style = '#test { marker-width: 1; }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    layer0 = shader.getLayers()[0];
    assert(!layer0.isVariable());

    style = '#test { marker-width: [prop]; marker-fill: red;  }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    layer0 = shader.getLayers()[0];
    assert(layer0.isVariable());
  });

  it("should parse styles with string", function() {
    var style = '#test { [column = "test\'ing"] { marker-width: 10; } }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({column: 'test\'ing'}, {  'zoom': 0, 'frame-offset': 10 });
    assert(props['marker-width'] ===  10);
  });

  it("should parse styles with filters not supported by dot notation", function() {
    var style = '#test["mapnik::geometry_type"=1] { marker-width: 10; }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({"mapnik::geometry_type": 1}, { 'zoom': 0 });
    assert.equal(props['marker-width'], 10);
    var emptyFilterProps = layer.getStyle({"mapnik::geometry_type": 2}, { 'zoom': 0 });
    assert.equal(emptyFilterProps['marker-width'], null);
  });

  it ("should parse turbocarto", function(){
    var css = [
          '#layer {',
          '  marker-width: ramp([cartodb_id], (#fff, #bbb), jenks);',
          '}'
      ].join('\n');
      var shader = (new carto.RendererJS({ debug: true })).render(css);
      var layer = shader.getLayers()[0];
      var st = layer.shader['marker-width'].style({}, {zoom: 1})
      assert.equal(st.name, "ramp")
      assert.equal(st.args.length, 3);
      assert.equal(st.args[1].value[0].rgb[0], 255);
      assert.equal(st.args[1].value[0].rgb[1], 255);
      assert.equal(st.args[1].value[0].rgb[2], 255);
      assert.equal(st.args[2].value, 'jenks');
  })

  it("should parse turbocarto with inner functions", function(){
    var css = [
      '#layer {',
      '  marker-width: ramp([cartodb_id], cartocolor(Bold), category(10));',
      '}'
    ].join('\n');
    var shader = (new carto.RendererJS({ debug: true })).render(css);
    var layer = shader.getLayers()[0];
    var st = layer.shader['marker-width'].style({}, {zoom: 1});
    assert.equal(st.name, "ramp");
    assert.equal(st.args.length, 3);
    assert.equal(st.args[1].name, 'cartocolor');
    assert.equal(st.args[1].args[0].value, 'Bold');
    assert.equal(st.args[2].name, 'category');
    assert.equal(st.args[2].args[0].value, 10);
  });

  it("should not throw `ReferenceError` with `=~` operator", function(){
    var css = [
      '#layer[name=~".*wadus*"] {',
      '  marker-width: 14;',
      '}'
    ].join('\n');

    assert.doesNotThrow(function () {
      var shader = (new carto.RendererJS({})).render(css);
      var layer = shader.getLayers()[0];
      var value = layer.shader['marker-width'].style({ name: 'wadus' }, { zoom: 1 });
    });
  });

  it("should not throw `TypeError` if left operand is not a `string` with operator `=~`", function(){
    var css = [
      '#layer[name=~".*wadus*"] {',
      '  marker-width: 14;',
      '}'
    ].join('\n');

    assert.doesNotThrow(function () {
      var shader = (new carto.RendererJS({})).render(css);
      var layer = shader.getLayers()[0];
      var value = layer.shader['marker-width'].style({ name: 1 }, { zoom: 1 });
      value = layer.shader['marker-width'].style({ name: null }, { zoom: 1 });
      value = layer.shader['marker-width'].style({ name: undefined }, { zoom: 1 });
      value = layer.shader['marker-width'].style({ name: true }, { zoom: 1 });
    });
  });
});
<commit_msg>Keep spaces<commit_after>
var assert = require('assert');
var carto = require('../lib/carto');
describe('RenderingJS', function() {
  var shader;
  var style = [
  '#world {',
    'line-width: 2;',
    'line-color: #f00;',
    '[frame-offset = 1] {',
      'line-width: 3;',
    '}',
    '[frame-offset = 2] {',
      'line-width: 3;',
    '}',
  '}',
  '',
  '#worls[frame-offset = 10] {',
      'line-width: 4;',
  '}'
  ].join('\n');

  beforeEach(function() {
    shader = (new carto.RendererJS({ debug: true })).render(style);
  });

  it ("shold render layers", function() {
    assert(shader.getLayers().length === 2);
  });

  it ("shold report frames used in the layer", function() {
    var layer = shader.getLayers()[0];
    assert( layer.frames()[0] === 0);
    assert( layer.frames()[1] === 1);

    layer = shader.getLayers()[1];
    assert( layer.frames()[0] === 10);
  });

  it ("shold render with frames var", function() {
    var layer = shader.getLayers()[1];
    var props = layer.getStyle({}, { 'zoom': 0, 'frame-offset': 10 });
    assert( props['line-width'] === 4);
  });

  it ("shold render variables", function() {
    var style = '#test { marker-width: [testing]; }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({testing: 2}, { 'zoom': 0, 'frame-offset': 10 });
    assert( props['marker-width'] === 2);
  });

  it ("should allow filter based rendering", function() {
    var style = '#test { marker-width: 10; [zoom = 1] { marker-width: 1; } }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({}, { 'zoom': 0, 'frame-offset': 10 });
    assert( props['marker-width'] ===  10);
    props = layer.getStyle({}, { 'zoom': 1, 'frame-offset': 10 });
    assert( props['marker-width'] ===  1);
  });

  it ("symbolizers should be in rendering order", function() {
    var style = '#test { polygon-fill: red; line-color: red; }';
    style += '#test2 { line-color: red;polygon-fill: red; line-witdh: 10; }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer0 = shader.getLayers()[0];
    assert(layer0.getSymbolizers()[0] === 'polygon');
    assert(layer0.getSymbolizers()[1] === 'line');

    var layer1 = shader.getLayers()[1];
    assert(layer0.getSymbolizers()[0] === 'polygon');
    assert(layer0.getSymbolizers()[1] === 'line');
  });

  it ("colorize should return a list of colours in same order", function() {
    var style = '#test { image-filters: colorize-alpha(blue, cyan, green, yellow, orange, red); }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer0 = shader.getLayers()[0];
    var st = layer0.getStyle({ value: 1 }, {"frame-offset": 0, "zoom": 3});
    var expectedColours = [[0, 0, 255], [0, 255, 255], [0, 128, 0], [255, 255, 0], [255, 165, 0], [255, 0, 0]];
    for (var i = 0; i < st["image-filters"].args; i++){
      assert (st["image-filters"].args[i].rgb === expectedColours[i]);
    }
  });

  it ("should return list of marker-files", function(){
    var css = [
          'Map {',
          '-torque-time-attribute: "date";',
          '-torque-aggregation-function: "count(cartodb_id)";',
          '-torque-frame-count: 760;',
          '-torque-animation-duration: 15;',
          '-torque-resolution: 2',
          '}',
          '#layer {',
          '  marker-width: 3;',
          '  marker-fill-opacity: 0.8;',
          '  marker-fill: #FEE391; ',
          '  marker-file: url(http://localhost:8081/gal.svg); ',
          '  comp-op: "lighten";',
          '  [value > 2] { marker-file: url(http://upload.wikimedia.org/wikipedia/commons/4/43/Flag_of_the_Galactic_Empire.svg); }',
          '  [value > 3] { marker-file: url(http://upload.wikimedia.org/wikipedia/commons/c/c9/Flag_of_Syldavia.svg); }',
          '  [frame-offset = 1] { marker-width: 10; marker-fill-opacity: 0.05;}',
          '  [frame-offset = 2] { marker-width: 15; marker-fill-opacity: 0.02;}',
          '}'
      ].join('\n');
      var shader = (new carto.RendererJS({ debug: true })).render(css);
      var markerURLs = shader.getImageURLs();
      var against = ["http://localhost:8081/gal.svg", "http://upload.wikimedia.org/wikipedia/commons/4/43/Flag_of_the_Galactic_Empire.svg", "http://upload.wikimedia.org/wikipedia/commons/c/c9/Flag_of_Syldavia.svg"];
      for(var i = 0; i<against.length; i++){
        assert(against[i] == markerURLs[i])
      }
  })

  it ("should return variable for styles that change", function() {
    var style = '#test { marker-width: [prop]; }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer0 = shader.getLayers()[0];
    assert(layer0.isVariable());

    style = '#test { marker-width: 1; }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    layer0 = shader.getLayers()[0];
    assert(!layer0.isVariable());

    style = '#test { marker-width: [prop]; marker-fill: red;  }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    layer0 = shader.getLayers()[0];
    assert(layer0.isVariable());
  });

  it("should parse styles with string", function() {
    var style = '#test { [column = "test\'ing"] { marker-width: 10; } }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({column: 'test\'ing'}, {  'zoom': 0, 'frame-offset': 10 });
    assert(props['marker-width'] ===  10);
  });

  it("should parse styles with filters not supported by dot notation", function() {
    var style = '#test["mapnik::geometry_type"=1] { marker-width: 10; }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({"mapnik::geometry_type": 1}, { 'zoom': 0 });
    assert.equal(props['marker-width'], 10);
    var emptyFilterProps = layer.getStyle({"mapnik::geometry_type": 2}, { 'zoom': 0 });
    assert.equal(emptyFilterProps['marker-width'], null);
  });

  it ("should parse turbocarto", function(){
    var css = [
          '#layer {',
          '  marker-width: ramp([cartodb_id], (#fff, #bbb), jenks);',
          '}'
      ].join('\n');
      var shader = (new carto.RendererJS({ debug: true })).render(css);
      var layer = shader.getLayers()[0];
      var st = layer.shader['marker-width'].style({}, {zoom: 1})
      assert.equal(st.name, "ramp")
      assert.equal(st.args.length, 3);
      assert.equal(st.args[1].value[0].rgb[0], 255);
      assert.equal(st.args[1].value[0].rgb[1], 255);
      assert.equal(st.args[1].value[0].rgb[2], 255);
      assert.equal(st.args[2].value, 'jenks');
  })

  it("should parse turbocarto with inner functions", function(){
    var css = [
      '#layer {',
      '  marker-width: ramp([cartodb_id], cartocolor(Bold), category(10));',
      '}'
    ].join('\n');
    var shader = (new carto.RendererJS({ debug: true })).render(css);
    var layer = shader.getLayers()[0];
    var st = layer.shader['marker-width'].style({}, {zoom: 1});
    assert.equal(st.name, "ramp");
    assert.equal(st.args.length, 3);
    assert.equal(st.args[1].name, 'cartocolor');
    assert.equal(st.args[1].args[0].value, 'Bold');
    assert.equal(st.args[2].name, 'category');
    assert.equal(st.args[2].args[0].value, 10);
  });

  it("should not throw `ReferenceError` with `=~` operator", function(){
    var css = [
      '#layer[name=~".*wadus*"] {',
      '  marker-width: 14;',
      '}'
    ].join('\n');

    assert.doesNotThrow(function () {
      var shader = (new carto.RendererJS({})).render(css);
      var layer = shader.getLayers()[0];
      var value = layer.shader['marker-width'].style({ name: 'wadus' }, { zoom: 1 });
    });
  });

  it("should not throw `TypeError` if left operand is not a `string` with operator `=~`", function(){
    var css = [
      '#layer[name=~".*wadus*"] {',
      '  marker-width: 14;',
      '}'
    ].join('\n');

    assert.doesNotThrow(function () {
      var shader = (new carto.RendererJS({})).render(css);
      var layer = shader.getLayers()[0];
      var value = layer.shader['marker-width'].style({ name: 1 }, { zoom: 1 });
      value = layer.shader['marker-width'].style({ name: null }, { zoom: 1 });
      value = layer.shader['marker-width'].style({ name: undefined }, { zoom: 1 });
      value = layer.shader['marker-width'].style({ name: true }, { zoom: 1 });
    });
  });
});
<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimension<commit_msg>Five bullets or six?<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions<|endoftext|>


<commit_before>var path = require('path');
var source = require('vinyl-source-stream');
var minimist = require('minimist');
var gulpif = require('gulp-if');
var gulp = require('gulp');
var gutil = require('gulp-util');
var preprocess = require('gulp-preprocess');
var watchify = require('watchify');
var browserify = require('browserify');
var babelify = require('babelify');
var tsify = require('tsify');
var stylus = require('gulp-stylus');
var minifyCss = require('gulp-minify-css');
var streamify = require('gulp-streamify');
var autoprefixer = require('gulp-autoprefixer');
var rename = require('gulp-rename');

// command line options
var minimistOptions = {
  string: ['env', 'mode', 'target'],
  default: {
    env: 'env.json',
    mode: 'dev',
    target: 'browser'
  }
};
var options = minimist(process.argv.slice(2), minimistOptions);

var paths = {
  styles: ['src/styl/reset.styl', 'src/styl/common.styl', 'src/styl/form.styl',
    'src/styl/overlay.styl', 'src/styl/overlay-popup.styl', 'src/styl/*.styl'
  ]
};

function buildHtml(src, dest, context) {
  console.log(context);
  return gulp.src(path.join(src, 'index.html'))
    .pipe(preprocess({context: context}))
    .pipe(gulp.dest(dest));
}

function buildStyl(src, dest, mode) {
  return gulp.src(src)
    .pipe(stylus())
    .pipe(streamify(autoprefixer({ browsers: ['and_chr >= 50', 'ios_saf >= 9']})))
    .pipe(gulpif(mode === 'prod', minifyCss()))
    .pipe(rename('app.css'))
    .pipe(gulp.dest(dest + '/css/compiled/'));
}

function buildScripts(src, dest, mode) {
  var opts = (mode === 'dev') ? { debug: true } : {};

  return browserify(src + '/js/main.ts', opts)
    .plugin(tsify)
    .transform(babelify, {
      extensions: ['.tsx', '.ts', '.js', '.jsx'],
      presets: ['es2015']
    })
    .bundle()
    .on('error', function(error) { gutil.log(gutil.colors.red(error.message)); })
    .pipe(source('app.js'))
    .pipe(gulp.dest(dest));
}

gulp.task('html', function() {
  var context = require('./' + options.env);
  context.MODE = options.mode;
  context.TARGET = options.target;

  return buildHtml('src', 'www', context);
});

gulp.task('styl', function() {
  return buildStyl('src/styl/index.styl', 'www', options.mode);
});

gulp.task('scripts', function() {
  return buildScripts('./src', 'www', options.mode);
});

gulp.task('watch-scripts', function() {
  var opts = watchify.args;
  opts.debug = true;

  var bundleStream = watchify(
    browserify('./src/js/main.ts', opts)
    .plugin(tsify)
    .transform(babelify, {
      extensions: ['.tsx', '.ts', '.js', '.jsx'],
      presets: ['es2015']
    })
  );

  function rebundle() {
    return bundleStream
      .bundle()
      .on('error', function(error) { gutil.log(gutil.colors.red(error.message)); })
      .pipe(source('app.js'))
      .pipe(gulp.dest('./www'));
  }

  bundleStream.on('update', rebundle);
  bundleStream.on('log', gutil.log);

  return rebundle();
});

// Watch Files For Changes
gulp.task('launch-watch', function() {
  gulp.watch(paths.styles, ['styl']);
  gulp.watch(['src/index.html', 'env.json'], ['html']);
});

gulp.task('default', ['html', 'styl', 'scripts']);
gulp.task('watch', ['html', 'styl', 'watch-scripts', 'launch-watch']);

module.exports = {
  buildHtml: buildHtml,
  buildStyl: buildStyl,
  buildScripts: buildScripts
};
<commit_msg>Tweak gulpfile<commit_after>var path = require('path');
var source = require('vinyl-source-stream');
var minimist = require('minimist');
var gulpif = require('gulp-if');
var gulp = require('gulp');
var gutil = require('gulp-util');
var preprocess = require('gulp-preprocess');
var watchify = require('watchify');
var browserify = require('browserify');
var babelify = require('babelify');
var tsify = require('tsify');
var stylus = require('gulp-stylus');
var minifyCss = require('gulp-minify-css');
var streamify = require('gulp-streamify');
var autoprefixer = require('gulp-autoprefixer');
var rename = require('gulp-rename');

// command line options
var minimistOptions = {
  string: ['env', 'mode', 'target'],
  default: {
    env: 'env.json',
    mode: 'dev',
    target: 'browser'
  }
};
var options = minimist(process.argv.slice(2), minimistOptions);

var paths = {
  styles: ['src/styl/reset.styl', 'src/styl/common.styl', 'src/styl/form.styl',
    'src/styl/overlay.styl', 'src/styl/overlay-popup.styl', 'src/styl/*.styl'
  ]
};

function buildHtml(src, dest, context) {
  console.log(context);
  return gulp.src(path.join(src, 'index.html'))
    .pipe(preprocess({context: context}))
    .pipe(gulp.dest(dest));
}

function buildStyl(src, dest, mode) {
  return gulp.src(src)
    .pipe(stylus())
    .pipe(streamify(autoprefixer({ browsers: ['and_chr >= 50', 'ios_saf >= 9']})))
    .pipe(gulpif(mode === 'release', minifyCss()))
    .pipe(rename('app.css'))
    .pipe(gulp.dest(dest + '/css/compiled/'));
}

function buildScripts(src, dest, mode) {
  var opts = (mode === 'dev') ? { debug: true } : {};

  return browserify(src + '/js/main.ts', opts)
    .plugin(tsify)
    .transform(babelify, {
      extensions: ['.tsx', '.ts', '.js', '.jsx'],
      presets: ['es2015']
    })
    .bundle()
    .on('error', function(error) { gutil.log(gutil.colors.red(error.message)); })
    .pipe(source('app.js'))
    .pipe(gulp.dest(dest));
}

gulp.task('html', function() {
  var context = require('./' + options.env);
  context.TARGET = options.target;

  return buildHtml('src', 'www', context);
});

gulp.task('styl', function() {
  return buildStyl('src/styl/index.styl', 'www', options.mode);
});

gulp.task('scripts', function() {
  return buildScripts('./src', 'www', options.mode);
});

gulp.task('watch-scripts', function() {
  var opts = watchify.args;
  opts.debug = true;

  var bundleStream = watchify(
    browserify('./src/js/main.ts', opts)
    .plugin(tsify)
    .transform(babelify, {
      extensions: ['.tsx', '.ts', '.js', '.jsx'],
      presets: ['es2015']
    })
  );

  function rebundle() {
    return bundleStream
      .bundle()
      .on('error', function(error) { gutil.log(gutil.colors.red(error.message)); })
      .pipe(source('app.js'))
      .pipe(gulp.dest('./www'));
  }

  bundleStream.on('update', rebundle);
  bundleStream.on('log', gutil.log);

  return rebundle();
});

// Watch Files For Changes
gulp.task('launch-watch', function() {
  gulp.watch(paths.styles, ['styl']);
  gulp.watch(['src/index.html', 'env.json'], ['html']);
});

gulp.task('default', ['html', 'styl', 'scripts']);
gulp.task('watch', ['html', 'styl', 'watch-scripts', 'launch-watch']);

module.exports = {
  buildHtml: buildHtml,
  buildStyl: buildStyl,
  buildScripts: buildScripts
};
<|endoftext|>


<commit_before>/**
 * Author: Olaolu Olawuyi

 * Date Created: 20/08/2015

 * Last Modified: 01/07/2016

 * Twitter: @whizkydee, @webtwic

 * Github: https://github.com/webtwic/webtwic-site

*/

var Webtwic = Webtwic || {};

var browser_name = bowser.name.toLowerCase();

var test_canvas = document.createElement( 'canvas' );
var canvascheck = ( test_canvas.getContext ) ? true : false;

Webtwic = {
	// Basic Information about Webtwic
	name: 'Webtwic',
	description: 'A community focused on code tweaks, articles and tutorials for newbie and professional developers.',
	repo: 'https://github.com/webtwic/webtwic-site',
	author: 'Olaolu Olawuyi',
	version: '1.0.0',

	// Start main functions for the object

	// Function to add browser name and version to body class
	showBrowser: function( b ) {
		b = (typeof b == 'undefined') ? browser_name : b.toLowerCase();
		if ( ! ( bowser.webkit ) )
			$( 'body' ).addClass( b + ' ' + b + parseInt( bowser.version ) );
		else
			$( 'body' ).addClass( 'webkit' + ' ' + b + ' ' + b + parseInt( bowser.version ) );
	},

	// Function to set attributes and values to elements
	setAttr: function( elem, name, val ) {
		$( elem, this ).attr( name, val );
	},

	// Function to push down .site-content
	adjustSiteContent: function() {
		if ( $( 'body' ).hasClass( 'default-body' ) ) {
			$( '.top-stripe' ).addClass( 'adjustedMargin' );
			$( '#header .logo' ).addClass( 'adjustedTop' );
			$( '.main-menu' ).addClass( 'adjustedMargin' );
			$( '#header' ).addClass( 'adjustSiteContent' );
		} else if ( $( 'body' ).hasClass( 'secondary-body' ) ) {
			$( '.site-content' ).addClass( 'adjustSiteContent' );
			$( '.secondary-header' ).addClass( 'adjustedMargin' );
		}
	},

	// Function to push up .site-content to default state
	undoSiteAdjust: function() {
		if ( $( 'body' ).hasClass( 'default-body' ) ) {
			$( '.top-stripe' ).removeClass( 'adjustedMargin' );
			$( '#header .logo' ).removeClass( 'adjustedTop' );
			$( '.main-menu' ).removeClass( 'adjustedMargin' );
			$( '#header' ).removeClass( 'adjustSiteContent' );
		} else if ( $( 'body' ).hasClass( 'secondary-body' ) ) {
			$( '.secondary-header' ).removeClass( 'adjustedMargin' );
		}
	},

	// Function to show Notifications before header
	showNotif: function( text ) {
		text = ( typeof text == 'undefined' ) ? notif_text : text;
		Webtwic.adjustSiteContent();
		$( 'body' ).prepend(
			'
'+text+''+close_button+'
'
		);

		$( '.close-button' ).on( 'click', function( e ) {
			e.preventDefault();
			Webtwic.undoReset();
		});
	},

	// Function to hide Notifications
	hideNotif: function() {
		$( '#notifBanner' ).removeClass( 'notif_vis' );
	},

	resetSite: function() {
		Webtwic.showNotif();
		Webtwic.adjustSiteContent();
	},

	undoReset: function() {
		Webtwic.hideNotif();
		Webtwic.undoSiteAdjust();
	},
};

var WBT = Webtwic,
	 $$ = Webtwic,
	 close_button = '',
	 browser_link = ' ' + 'browser.' + ' ',
	 notif_text = 'Whoa. Your browser currently dosen\'t support some important features. Please try refreshing this page or get a better' +browser_link;

// Detect when the DOM is ready

jQuery( document ).ready( function() {
	// Test for HTML5 support
	if ( window.Modernizr )
		if ( !Modernizr.canvas )
			Webtwic.showNotif ( "Oops. Looks like your browser doesn't support HTML5. Please get a better" +browser_link+ "for an awesome experience." );
		 else /* do nothing */ ;
	 else
		if ( canvascheck === false )
			Webtwic.showNotif ( "Oops. Looks like your browser doesn't support HTML5. Please get a better" +browser_link+ "for an awesome experience." );
		 else /* do nothing */ ;

	// Define Variables
	var $scroll_top = $( 'a.scroll_top' ),
	is_toggle_active = $( '.hamburger' ).hasClass( 'is_active' ),
	height = 200;

	// Performance Fixes

	// Start browser detection
	switch ( browser_name ) {
	   case 'microsoft edge':
	      Webtwic.showBrowser( 'msedge' );
	      break;
		default:
			Webtwic.showBrowser();
	}

	/*
		TODO: Rebuild Performance fixes for attributes
		See history of Performance fixes.
		Also, check StackOverflow.
		See Issue #12
	*/
	var M = Modernizr;

	var required_features = [
		Modernizr.flexbox,
		Modernizr.inlinesvg,
		Modernizr.svg,
		Modernizr.svgclippaths,
		Modernizr.fontface,
		Modernizr.boxshadow,
		Modernizr.borderradius,
		Modernizr.csstransforms
	];

	if ( window.Modernizr )
		if ( !( required_features ) )
			Webtwic.showNotif();
		else /* do nothing */ ;
	else /* do nothing */ ;

	// Start Main Page

	$( 'nav li ul.drop-nav' )
	.hide()
	.removeClass( 'dropNavFallback' );

	if ( $( window ).width() > 768 ) {
		$( 'nav li.dropdown' ).hover(function() {
			$( 'ul.drop-nav', this )
			.stop()
			.slideDown( 'fast' );
		}, function() {
			$( 'ul.drop-nav', this )
			.stop()
			.slideUp( 'fast' );
		});
	}

	$( '.active-item' ).append(
		'<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M 16.682,19.674c 0.010-0.012, 0.014-0.028, 0.024-0.040l 6.982-7.714c 0.39-0.434, 0.39-1.138,0-1.572 c-0.004-0.004-0.008-0.006-0.012-0.008C 23.496,10.13, 23.244,10, 22.964,10L 8.998,10 c-0.286,0-0.54,0.138-0.722,0.352L 8.272,10.348 c-0.39,0.434-0.39,1.138,0,1.572l 6.998,7.754C 15.66,20.108, 16.292,20.108, 16.682,19.674z"></path></svg>'
	);

	$( 'a.hamburger' ).on('click', function( e ) {
		$( this ).toggleClass( 'is_active' );

		e.preventDefault();
	});
	$( '.mobile-header .mobile-nav' ).hide();

	$( window ).on('scroll', function() {
		( $( this ).scrollTop() > height ) ? $scroll_top.addClass( 'topVisible' ): $scroll_top.removeClass( 'topVisible' );
	});

	// Styles for homepage article-social

	$( '.article .article-social a' ).hover(function() {
		$( 'span', this )
		.eq(1)
		.fadeIn(400);
	}, function() {
		$( 'span', this )
		.eq(1)
		.fadeOut(250);
	});

	// Functions for search-icon and ui-overlay-search

	$( '.header-follow-search .search-wrap' ).on( 'click', function() {
		openUiOverlay();
	});

	$( '.header-follow-search .close-icon' ).on( 'click', function( e ) {
		e.preventDefault();
		closeUiOverlay();
	});

	$( '.header-follow-search .close-icon' ).hover(
		function() {
			$( this ).addClass( 'spin' );
		}, function() {
			$( this ).removeClass( 'spin' );
	});

	function openUiOverlay() {
		$( '.ui-overlay-search' )
		.fadeIn(400)
		.addClass( 'is_open' );
	}

	function closeUiOverlay() {
		$( '.ui-overlay-search' )
		.fadeOut(400)
		.removeClass( 'is_open' );
	}

	$( '.ui-overlay-search .search-input input' ).on('focus', function() {
		$( '.search-input' ).attr( 'data-focused', 'true' );
		$( '.search-input input' ).addClass( '_is-focused' );
		$( '#__expand' ).addClass( 'visible' );
	});

	$( '.ui-overlay-search .search-input input' ).on('blur', function() {
		$( '.search-input' ).attr( 'data-focused', 'false' );
		$( '.search-input input' ).removeClass( '_is-focused' );
		$( '#__expand' ).removeClass( 'visible' );
	});

	$( '.post-meta .post-meta-inner .cta-btns a.is_inactive' ).on( 'click', function( e ) {
		e.preventDefault();
	});

	$( document ).keydown(function( e ) {
		if ( e.keyCode == 27 )
			closeUiOverlay();
		else /* do nothing */ ;
 	});

	$( '.mobile-nav' ).hide();

	// Functions for more-posts button click

	var loadMoreBtn = '.secondary-category-section .category-posts-column [data-clicked="false"]';

	function addLoader() {
		$( loadMoreBtn )
		.attr( 'data-clicked', 'true' )
		.append( '' );
	}

	$( loadMoreBtn ).on( 'click', function( e ) {
		$( this ).css({
			'background': '#50ABF1',
			'color': '#fff'
		});
		addLoader();
		e.preventDefault();
	});

	$scroll_top.on( 'click', function( e ) {
		$( 'body, html' ).animate({
			scrollTop: 0
		}, 1000);

		e.preventDefault();
	});

});
<commit_msg>Use jQuery.on() for document keydown event<commit_after>/**
 * Author: Olaolu Olawuyi

 * Date Created: 20/08/2015

 * Last Modified: 01/07/2016

 * Twitter: @whizkydee, @webtwic

 * Github: https://github.com/webtwic/webtwic-site

*/

var Webtwic = Webtwic || {};

var browser_name = bowser.name.toLowerCase();

var test_canvas = document.createElement( 'canvas' );
var canvascheck = ( test_canvas.getContext ) ? true : false;

Webtwic = {
	// Basic Information about Webtwic
	name: 'Webtwic',
	description: 'A community focused on code tweaks, articles and tutorials for newbie and professional developers.',
	repo: 'https://github.com/webtwic/webtwic-site',
	author: 'Olaolu Olawuyi',
	version: '1.0.0',

	// Start main functions for the object

	// Function to add browser name and version to body class
	showBrowser: function( b ) {
		b = (typeof b == 'undefined') ? browser_name : b.toLowerCase();
		if ( ! ( bowser.webkit ) )
			$( 'body' ).addClass( b + ' ' + b + parseInt( bowser.version ) );
		else
			$( 'body' ).addClass( 'webkit' + ' ' + b + ' ' + b + parseInt( bowser.version ) );
	},

	// Function to set attributes and values to elements
	setAttr: function( elem, name, val ) {
		$( elem, this ).attr( name, val );
	},

	// Function to push down .site-content
	adjustSiteContent: function() {
		if ( $( 'body' ).hasClass( 'default-body' ) ) {
			$( '.top-stripe' ).addClass( 'adjustedMargin' );
			$( '#header .logo' ).addClass( 'adjustedTop' );
			$( '.main-menu' ).addClass( 'adjustedMargin' );
			$( '#header' ).addClass( 'adjustSiteContent' );
		} else if ( $( 'body' ).hasClass( 'secondary-body' ) ) {
			$( '.site-content' ).addClass( 'adjustSiteContent' );
			$( '.secondary-header' ).addClass( 'adjustedMargin' );
		}
	},

	// Function to push up .site-content to default state
	undoSiteAdjust: function() {
		if ( $( 'body' ).hasClass( 'default-body' ) ) {
			$( '.top-stripe' ).removeClass( 'adjustedMargin' );
			$( '#header .logo' ).removeClass( 'adjustedTop' );
			$( '.main-menu' ).removeClass( 'adjustedMargin' );
			$( '#header' ).removeClass( 'adjustSiteContent' );
		} else if ( $( 'body' ).hasClass( 'secondary-body' ) ) {
			$( '.secondary-header' ).removeClass( 'adjustedMargin' );
		}
	},

	// Function to show Notifications before header
	showNotif: function( text ) {
		text = ( typeof text == 'undefined' ) ? notif_text : text;
		Webtwic.adjustSiteContent();
		$( 'body' ).prepend(
			'
'+text+''+close_button+'
'
		);

		$( '.close-button' ).on( 'click', function( e ) {
			e.preventDefault();
			Webtwic.undoReset();
		});
	},

	// Function to hide Notifications
	hideNotif: function() {
		$( '#notifBanner' ).removeClass( 'notif_vis' );
	},

	resetSite: function() {
		Webtwic.showNotif();
		Webtwic.adjustSiteContent();
	},

	undoReset: function() {
		Webtwic.hideNotif();
		Webtwic.undoSiteAdjust();
	},
};

var WBT = Webtwic,
	 $$ = Webtwic,
	 close_button = '',
	 browser_link = ' ' + 'browser.' + ' ',
	 notif_text = 'Whoa. Your browser currently dosen\'t support some important features. Please try refreshing this page or get a better' +browser_link;

// Detect when the DOM is ready

jQuery( document ).ready( function() {
	// Test for HTML5 support
	if ( window.Modernizr )
		if ( !Modernizr.canvas )
			Webtwic.showNotif ( "Oops. Looks like your browser doesn't support HTML5. Please get a better" +browser_link+ "for an awesome experience." );
		 else /* do nothing */ ;
	 else
		if ( canvascheck === false )
			Webtwic.showNotif ( "Oops. Looks like your browser doesn't support HTML5. Please get a better" +browser_link+ "for an awesome experience." );
		 else /* do nothing */ ;

	// Define Variables
	var $scroll_top = $( 'a.scroll_top' ),
	is_toggle_active = $( '.hamburger' ).hasClass( 'is_active' ),
	height = 200;

	// Performance Fixes

	// Start browser detection
	switch ( browser_name ) {
	   case 'microsoft edge':
	      Webtwic.showBrowser( 'msedge' );
	      break;
		default:
			Webtwic.showBrowser();
	}

	/*
		TODO: Rebuild Performance fixes for attributes
		See history of Performance fixes.
		Also, check StackOverflow.
		See Issue #12
	*/
	var M = Modernizr;

	var required_features = [
		Modernizr.flexbox,
		Modernizr.inlinesvg,
		Modernizr.svg,
		Modernizr.svgclippaths,
		Modernizr.fontface,
		Modernizr.boxshadow,
		Modernizr.borderradius,
		Modernizr.csstransforms
	];

	if ( window.Modernizr )
		if ( !( required_features ) )
			Webtwic.showNotif();
		else /* do nothing */ ;
	else /* do nothing */ ;

	// Start Main Page

	$( 'nav li ul.drop-nav' )
	.hide()
	.removeClass( 'dropNavFallback' );

	if ( $( window ).width() > 768 ) {
		$( 'nav li.dropdown' ).hover(function() {
			$( 'ul.drop-nav', this )
			.stop()
			.slideDown( 'fast' );
		}, function() {
			$( 'ul.drop-nav', this )
			.stop()
			.slideUp( 'fast' );
		});
	}

	$( '.active-item' ).append(
		'<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M 16.682,19.674c 0.010-0.012, 0.014-0.028, 0.024-0.040l 6.982-7.714c 0.39-0.434, 0.39-1.138,0-1.572 c-0.004-0.004-0.008-0.006-0.012-0.008C 23.496,10.13, 23.244,10, 22.964,10L 8.998,10 c-0.286,0-0.54,0.138-0.722,0.352L 8.272,10.348 c-0.39,0.434-0.39,1.138,0,1.572l 6.998,7.754C 15.66,20.108, 16.292,20.108, 16.682,19.674z"></path></svg>'
	);

	$( 'a.hamburger' ).on('click', function( e ) {
		$( this ).toggleClass( 'is_active' );

		e.preventDefault();
	});
	$( '.mobile-header .mobile-nav' ).hide();

	$( window ).on('scroll', function() {
		( $( this ).scrollTop() > height ) ? $scroll_top.addClass( 'topVisible' ): $scroll_top.removeClass( 'topVisible' );
	});

	// Styles for homepage article-social

	$( '.article .article-social a' ).hover(function() {
		$( 'span', this )
		.eq(1)
		.fadeIn(400);
	}, function() {
		$( 'span', this )
		.eq(1)
		.fadeOut(250);
	});

	// Functions for search-icon and ui-overlay-search

	$( '.header-follow-search .search-wrap' ).on( 'click', function() {
		openUiOverlay();
	});

	$( '.header-follow-search .close-icon' ).on( 'click', function( e ) {
		e.preventDefault();
		closeUiOverlay();
	});

	$( '.header-follow-search .close-icon' ).hover(
		function() {
			$( this ).addClass( 'spin' );
		}, function() {
			$( this ).removeClass( 'spin' );
	});

	function openUiOverlay() {
		$( '.ui-overlay-search' )
		.fadeIn(400)
		.addClass( 'is_open' );
	}

	function closeUiOverlay() {
		$( '.ui-overlay-search' )
		.fadeOut(400)
		.removeClass( 'is_open' );
	}

	$( '.ui-overlay-search .search-input input' ).on('focus', function() {
		$( '.search-input' ).attr( 'data-focused', 'true' );
		$( '.search-input input' ).addClass( '_is-focused' );
		$( '#__expand' ).addClass( 'visible' );
	});

	$( '.ui-overlay-search .search-input input' ).on('blur', function() {
		$( '.search-input' ).attr( 'data-focused', 'false' );
		$( '.search-input input' ).removeClass( '_is-focused' );
		$( '#__expand' ).removeClass( 'visible' );
	});

	$( '.post-meta .post-meta-inner .cta-btns a.is_inactive' ).on( 'click', function( e ) {
		e.preventDefault();
	});

	$( document ).on('keydown', function( e ) {
		if ( e.keyCode == 27 )
			closeUiOverlay();
		else /* do nothing */ ;
 	});

	$( '.mobile-nav' ).hide();

	// Functions for more-posts button click

	var loadMoreBtn = '.secondary-category-section .category-posts-column [data-clicked="false"]';

	function addLoader() {
		$( loadMoreBtn )
		.attr( 'data-clicked', 'true' )
		.append( '' );
	}

	$( loadMoreBtn ).on( 'click', function( e ) {
		$( this ).css({
			'background': '#50ABF1',
			'color': '#fff'
		});
		addLoader();
		e.preventDefault();
	});

	$scroll_top.on( 'click', function( e ) {
		$( 'body, html' ).animate({
			scrollTop: 0
		}, 1000);

		e.preventDefault();
	});

});
<|endoftext|>


<commit_before><commit_msg>Scrollmagic classes added<commit_after><|endoftext|>


<commit_before>var express = require('express');
var url = require('url');
var net = require('net');
var path = require('path');
var fs = require('fs');
var EventEmitter = require('events').EventEmitter;
var exnted = require('util')._extend;
var util = require('../util');
var rules = require('./rules');
var rulesUtil = require('./rules/util');
var connect = require('./proxy/connect');
var config = require('../package.json');

function tunnelProxy(server, proxy) {

	server.on('connect', function(req, reqSocket, head) {//ws, wss, https proxy
		var tunnelUrl = req.url = util.setProtocol(req.url, true);
		var options = parseUrl();
		var resSocket, proxySocket;

		if (!options.hostname) {
			tunnelUrl = req.url = util.setProtocol(req.headers.host, true);
			parseUrl();
		}

		abortIfUnavailable(reqSocket);
		function emitError(err) {
			resSocket && resSocket.destroy();
			proxySocket && proxySocket.destroy();
			reqSocket.destroy();
		}

		function abortIfUnavailable(socket) {
			socket.on('error', emitError).on('close', emitError);
		}

		function parseUrl(_tunnelUrl, port) {
			_tunnelUrl = _tunnelUrl || tunnelUrl;
			options = req.options = url.parse(_tunnelUrl);
			options.port = options.port || port || 443;
			return options;
		}

		function sendEstablished() {
			reqSocket.write('HTTP/1.1 200 Connection Established\r\nProxy-Agent: ' + config.name + '\r\n\r\n');
			return reqSocket;
		}

		function tunnel(url) {
			rules.resolveHost(url || tunnelUrl, function(err, ip) {
				req.host = ip = ip || options.hostname;
				req.clientHost  = reqSocket.remoteAddress;
				proxy.emit('tunnel', req);

				if (err) {
					emitError(err);
					return;
				}
				try {
					resSocket = net.connect(options.port, ip, function() {
						sendEstablished();
			            resSocket.pipe(reqSocket).pipe(resSocket);
			        });
				} catch(e) {
					emitError();
				}
				abortIfUnavailable(resSocket);
			});
		}

		var _rules = rules.resolveRules(tunnelUrl);
		var proxyUrl = util.rule.getMatcher(_rules.proxy);
		if (proxyUrl) {
			var _tunnelUrl = 'https:' + util.removeProtocol(proxyUrl);
			rules.resolveHost(_tunnelUrl, function(err, ip) {
				req.host = ip;
				parseUrl(_tunnelUrl, config.port);
				if (!err && util.isLocalAddress(ip) && options.port == config.port) {
					parseUrl();
					return tunnel();
				}
				proxy.emit('tunnelProxy', req);
				if (err) {
					emitError(err);
					return;
				}
				options.host = ip;
				connect(req, config, function(err, _proxySocket) {
					if (err) {
						return emitError();
					}
					proxySocket = _proxySocket;
					abortIfUnavailable(_proxySocket);
					sendEstablished().pipe(_proxySocket).pipe(reqSocket);
				});
			});
		} else {
			if (_rules.rule) {
				var _url = util.setProtocol(util.rule.getMatcher(_rules.rule), true);
				if (/^https:/i.test(_url)) {
					parseUrl(_url);
				} else {
					var port = util.getProtocol(_url);
					port = port.substring(0, port.length - 1);
					var localProtocol = port + 'sslport';
					if (port = config[localProtocol]) {
						proxy.emit(localProtocol, _url);
						parseUrl(_url);
						options.protocol = 'https:';
						options.hostname = '127.0.0.1';
						options.host = options.hostname + ':' + port;
						options.port = port;
						_url = 'ssl://' + options.host; //不解析_url的ip
					} else {
						_url = null;//如果规则无法处理，则直接访问
					}
				}
			}

			tunnel(_url);
		}
    });

	return server;
}

function proxy(conf) {
	if (conf) {
		['port', 'sockets', 'days', 'timeout',
		 'username', 'password', 'uipath', 'rules']
			.forEach(function(name) {
				if (conf[name]) {
					config[name] = conf[name];
				}
			});

		if (Array.isArray(conf.ports)) {
			config.ports = config.ports.concat(conf.ports);
		}
	}

	if (!conf || typeof conf.middlewares != 'string') {
		if (!Array.isArray(conf.middlewares)) {
			config.middlewares = [];
		}
	} else {
		config.middlewares = conf.middlewares.trim().split(/\s*,\s*/g);
	}

	config.middlewares.map(util.resolvePath);

	var port = config.port;
	config.ports.forEach(function(name) {
		config[name] = ++port;
	});

	var agentConfig = {maxSockets: config.sockets};
	config.httpAgent = new (require('http').Agent)(agentConfig);
	config.httpsAgent = new (require('https').Agent)(agentConfig);
	config.WEINRE_HOST = 'weinre.' + config.localUIHost;

	var app = express();
	var server = app.listen(config.port);
	var proxyEvents = new EventEmitter();
	var middlewares = ['./init',
	               '../biz']
				   .concat(require('./inspectors'))
				   .concat(config.middlewares)
	               .concat(require('./handlers'));

	proxyEvents.config = config;
	middlewares.forEach(function(mw) {
		mw && app.use((typeof mw == 'string' ? require(mw) : mw).bind(proxyEvents));
	});

	parseHosts(config.rules);
	exportInterfaces(proxyEvents);
	tunnelProxy(server, proxyEvents);
	require('./proxy')(proxyEvents);
	require('../biz/init')(proxyEvents);

	return proxyEvents;
}

function exportInterfaces(obj) {
	obj.rules = rules;
	obj.util = util;
	obj.rulesUtil = rulesUtil;
	return obj;
}

function parseHosts(rulesPath) {
	if (rulesPath) {
		try {
			rulesUtil.setPublicHosts(fs.readFileSync(path.resolve(rulesPath), {encoding: 'utf8'}));
			rulesUtil.enablePublicHosts();
		} catch(e) {}
	}

	rulesUtil.loadHosts();
}

process.on('uncaughtException', function(err){
	var stack = err.message + '\r\n' + err.stack;
	fs.writeFileSync(path.join(process.cwd(), config.name + '.log'), '\r\n' + util.formatDate()  + '\r\n' +  stack + '\r\n', {flag: 'a'});
	console.error(stack);
	process.exit(1);
});

module.exports = exportInterfaces(proxy);<commit_msg>local protocol<commit_after>var express = require('express');
var url = require('url');
var net = require('net');
var path = require('path');
var fs = require('fs');
var EventEmitter = require('events').EventEmitter;
var exnted = require('util')._extend;
var util = require('../util');
var rules = require('./rules');
var rulesUtil = require('./rules/util');
var connect = require('./proxy/connect');
var config = require('../package.json');

function tunnelProxy(server, proxy) {

	server.on('connect', function(req, reqSocket, head) {//ws, wss, https proxy
		var tunnelUrl = req.url = util.setProtocol(req.url, true);
		var options = parseUrl();
		var resSocket, proxySocket;

		if (!options.hostname) {
			tunnelUrl = req.url = util.setProtocol(req.headers.host, true);
			parseUrl();
		}

		abortIfUnavailable(reqSocket);
		function emitError(err) {
			resSocket && resSocket.destroy();
			proxySocket && proxySocket.destroy();
			reqSocket.destroy();
		}

		function abortIfUnavailable(socket) {
			socket.on('error', emitError).on('close', emitError);
		}

		function parseUrl(_tunnelUrl, port) {
			_tunnelUrl = _tunnelUrl || tunnelUrl;
			options = req.options = url.parse(_tunnelUrl);
			options.port = options.port || port || 443;
			return options;
		}

		function sendEstablished() {
			reqSocket.write('HTTP/1.1 200 Connection Established\r\nProxy-Agent: ' + config.name + '\r\n\r\n');
			return reqSocket;
		}

		function tunnel(url) {
			rules.resolveHost(url || tunnelUrl, function(err, ip) {
				req.host = ip = ip || options.hostname;
				req.clientHost  = reqSocket.remoteAddress;
				proxy.emit('tunnel', req);

				if (err) {
					emitError(err);
					return;
				}
				try {
					resSocket = net.connect(options.port, ip, function() {
						sendEstablished();
			            resSocket.pipe(reqSocket).pipe(resSocket);
			        });
				} catch(e) {
					emitError();
				}
				abortIfUnavailable(resSocket);
			});
		}

		var _rules = rules.resolveRules(tunnelUrl);
		var proxyUrl = util.rule.getMatcher(_rules.proxy);
		if (proxyUrl) {
			var _tunnelUrl = 'https:' + util.removeProtocol(proxyUrl);
			rules.resolveHost(_tunnelUrl, function(err, ip) {
				req.host = ip;
				parseUrl(_tunnelUrl, config.port);
				if (!err && util.isLocalAddress(ip) && options.port == config.port) {
					parseUrl();
					return tunnel();
				}
				proxy.emit('tunnelProxy', req);
				if (err) {
					emitError(err);
					return;
				}
				options.host = ip;
				connect(req, config, function(err, _proxySocket) {
					if (err) {
						return emitError();
					}
					proxySocket = _proxySocket;
					abortIfUnavailable(_proxySocket);
					sendEstablished().pipe(_proxySocket).pipe(reqSocket);
				});
			});
		} else {
			if (_rules.rule) {
				var _url = util.setProtocol(util.rule.getMatcher(_rules.rule), true);
				if (/^https:/i.test(_url)) {
					parseUrl(_url);
				} else {
					var port = util.getProtocol(_url);
					port = port.substring(0, port.length - 1);
					var localProtocol = port + 'sslport';
					if (port = config[localProtocol]) {
						proxy.emit(localProtocol, _url, tunnelUrl);
						parseUrl(_url);
						options.protocol = 'https:';
						options.hostname = '127.0.0.1';
						options.host = options.hostname + ':' + port;
						options.port = port;
						_url = 'ssl://' + options.host; //不解析_url的ip
					} else {
						_url = null;//如果规则无法处理，则直接访问
					}
				}
			}

			tunnel(_url);
		}
    });

	return server;
}

function proxy(conf) {
	if (conf) {
		['port', 'sockets', 'days', 'timeout',
		 'username', 'password', 'uipath', 'rules']
			.forEach(function(name) {
				if (conf[name]) {
					config[name] = conf[name];
				}
			});

		if (Array.isArray(conf.ports)) {
			config.ports = config.ports.concat(conf.ports);
		}
	}

	if (!conf || typeof conf.middlewares != 'string') {
		if (!Array.isArray(conf.middlewares)) {
			config.middlewares = [];
		}
	} else {
		config.middlewares = conf.middlewares.trim().split(/\s*,\s*/g);
	}

	config.middlewares.map(util.resolvePath);

	var port = config.port;
	config.ports.forEach(function(name) {
		config[name] = ++port;
	});

	var agentConfig = {maxSockets: config.sockets};
	config.httpAgent = new (require('http').Agent)(agentConfig);
	config.httpsAgent = new (require('https').Agent)(agentConfig);
	config.WEINRE_HOST = 'weinre.' + config.localUIHost;

	var app = express();
	var server = app.listen(config.port);
	var proxyEvents = new EventEmitter();
	var middlewares = ['./init',
	               '../biz']
				   .concat(require('./inspectors'))
				   .concat(config.middlewares)
	               .concat(require('./handlers'));

	proxyEvents.config = config;
	middlewares.forEach(function(mw) {
		mw && app.use((typeof mw == 'string' ? require(mw) : mw).bind(proxyEvents));
	});

	parseHosts(config.rules);
	exportInterfaces(proxyEvents);
	tunnelProxy(server, proxyEvents);
	require('./proxy')(proxyEvents);
	require('../biz/init')(proxyEvents);

	return proxyEvents;
}

function exportInterfaces(obj) {
	obj.rules = rules;
	obj.util = util;
	obj.rulesUtil = rulesUtil;
	return obj;
}

function parseHosts(rulesPath) {
	if (rulesPath) {
		try {
			rulesUtil.setPublicHosts(fs.readFileSync(path.resolve(rulesPath), {encoding: 'utf8'}));
			rulesUtil.enablePublicHosts();
		} catch(e) {}
	}

	rulesUtil.loadHosts();
}

process.on('uncaughtException', function(err){
	var stack = err.message + '\r\n' + err.stack;
	fs.writeFileSync(path.join(process.cwd(), config.name + '.log'), '\r\n' + util.formatDate()  + '\r\n' +  stack + '\r\n', {flag: 'a'});
	console.error(stack);
	process.exit(1);
});

module.exports = exportInterfaces(proxy);<|endoftext|>


<commit_before> //jscs:disable

 /**
 * toast.js
 * https://github.com/usablica/intro.js
 * MIT licensed
 *
 * Copyright (C) 2013 usabli.ca - A weekend project by Afshin Mehrabani (@afshinme

 /*jshint scripturl:true */
 /*jshint funcscope:true */
 /*jshint -W004 */
 /*jshint unused:false*/

 /* jshint -W099 */

!function ($) {
  "use strict";
   /*jshint validthis: true */
 /* BUTTON PUBLIC CLASS DEFINITION
  * ============================== */
  var template = '

<s class="msg-icon"></s>
';

  var Toast = function (options) {
  	var $toast = null;
    if(typeof options === typeof 'a'){
      this.options = $.extend({}, this.defaults);
      this.options.text = options;
      this.options.position= arguments[2];
      this.options.type = arguments[1];
    }else{
      this.options = $.extend({}, this.defaults, options);
    }
    return this.render();
  }

  Toast.prototype = {
    Constructor : Toast,
     render: function(){
      var options = this.options;
      var message = ".toast_message";
      var text = ".toast_text";
      var cssPrefix = "label-";
      $(message).remove();
      this.el = $(template);
      this.el.appendTo(document.body);
      $(text).html(options.text); //this.el.find(text)
      options.position.replace(/(\S+)/g, cssPrefix) ;
      this.el.addClass(options.position).addClass(cssPrefix+options.type);
      this.show();

      // if(options.closeButton){
      //   this.el.addClass('show-close-btn');
      // }
      if(options.closeOnClick){
        this.el.click($.proxy(this.hide,this));
      }
    },
    hide : function(callback){  // hide : function(duration, callback);
      this.el.removeClass('toast-in');
    },
    show : function(duration, callback){  // show : function(duration, callback);
      var classes = this.el.attr("class");
      var vertical = this.el.hasClass('top')&&"top"||this.el.hasClass('bottom')&&"bottom"||"middle";
      var horizontal = this.el.hasClass('left')&&"left"||this.el.hasClass('right')&&"right"||"center";
      if(horizontal=="center"){
        var mlwidth = -(this.el.width()/2);
        this.el.css("margin-left",mlwidth+"px");
      }
      if(vertical=="middle"){
        var mtheight = -(this.el.height()/2);
        this.el.css("margin-top",mtheight);
      }
      var addclass = function(){
        this.el.addClass('toast-in')
      }
      setTimeout($.proxy(addclass,this));
      setTimeout($.proxy(this.hide,this),this.options.timeout);
    }
  }

  var old = $.toast

  $.toast = function(arg1,arg2,arg3){
    return new Toast(arg1,arg2, arg3);
  }

  Toast.prototype.defaults = {
    position: 'top',
    type: 'danger',
    // speed: 500,
    timeout: 3000,
    // closeButton: false,
    closeOnClick: true,
    text:''
  };

  $.toast.Constructor = Toast;

 /* BUTTON NO CONFLICT
  * ================== */

  $.toast.noConflict = function () {
    $.toast = old;
    return this
  }

 /* BUTTON DATA-API
  * =============== */
}(window.jQuery);
<commit_msg>toast<commit_after> //jscs:disable

 /**
 * toast.js
 * https://github.com/usablica/intro.js
 * MIT licensed
 *
 * Copyright (C) 2013 usabli.ca - A weekend project by Afshin Mehrabani (@afshinme

 /*jshint scripturl:true */
 /*jshint funcscope:true */
 /*jshint -W004 */
 /*jshint unused:false*/

 /* jshint -W099 */

!function ($) {
  "use strict";
   /*jshint validthis: true */
 /* BUTTON PUBLIC CLASS DEFINITION
  * ============================== */
  var template = '

<s class="msg-icon"></s>
';

  var Toast = function (options) {
  	var $toast = null;
    if(typeof options === typeof 'a'){
      this.options = $.extend({}, this.defaults);
      this.options.text = options;
      this.options.position= arguments[2];
      this.options.type = arguments[1];
    }else{
      this.options = $.extend({}, this.defaults, options);
    }
    return this.render();
  }

  Toast.prototype = {
    Constructor : Toast,
     render: function(){
      var options = this.options;
      var message = ".toast_message";
      var text = ".toast_text";
      var cssPrefix = "label-";
      $(message).remove();
      this.el = $(template);
      this.el.appendTo(document.body);
      $(text).html(options.text); //this.el.find(text)
      options.position.replace(/(\S+)/g, cssPrefix) ;
      this.el.addClass(options.position).addClass(cssPrefix+options.type);
      this.show();

      // if(options.closeButton){
      //   this.el.addClass('show-close-btn');
      // }
      if(options.closeOnClick){
        this.el.click($.proxy(this.hide,this));
      }
    },
    hide : function(callback){  // hide : function(duration, callback);
      this.el.removeClass('toast-in');
      this.el.remove();
    },
    show : function(duration, callback){  // show : function(duration, callback);
      var classes = this.el.attr("class");
      var vertical = this.el.hasClass('top')&&"top"||this.el.hasClass('bottom')&&"bottom"||"middle";
      var horizontal = this.el.hasClass('left')&&"left"||this.el.hasClass('right')&&"right"||"center";
      if(horizontal=="center"){
        var mlwidth = -(this.el.width()/2);
        this.el.css("margin-left",mlwidth+"px");
      }
      if(vertical=="middle"){
        var mtheight = -(this.el.height()/2);
        this.el.css("margin-top",mtheight);
      }
      var addclass = function(){
        this.el.addClass('toast-in')
      }
      setTimeout($.proxy(addclass,this));
      setTimeout($.proxy(this.hide,this),this.options.timeout);
    }
  }

  var old = $.toast

  $.toast = function(arg1,arg2,arg3){
    return new Toast(arg1,arg2, arg3);
  }

  Toast.prototype.defaults = {
    position: 'top',
    type: 'danger',
    // speed: 500,
    timeout: 3000,
    // closeButton: false,
    closeOnClick: true,
    text:''
  };

  $.toast.Constructor = Toast;

 /* BUTTON NO CONFLICT
  * ================== */

  $.toast.noConflict = function () {
    $.toast = old;
    return this
  }

 /* BUTTON DATA-API
  * =============== */
}(window.jQuery);
<|endoftext|>