<commit_before>import { addSet, subtract, magnitude, rotateSet, scaleSet, mapListSet, addListSet, average } from 'pura/vector/tuple';
import { getRectanglePoints } from 'pura/geometry/tuple';
import { isPointInCircle } from 'pura/intersection/tuple';
import { fillPolygon, fillRectangle, fillText, fillOval, strokeOval } from 'pura/canvas/tuple';
import { perspective, perspective2d } from 'camera';
import { viewWidth, viewHeight } from 'dom';
import state from 'state';
import { islands } from 'overworld/island';
import { tulip } from 'emoji';
import { createBattleScene } from 'battle';
import {
  mkTree,
  mkTreeAlt,
  mkAvenger,
  mkChild,
  mkProtector,
  mkPersecutor,
  mkGem,
  mkMountain,
  mkTulip,
  mkGrass,
} from 'sprite';
import {
  makeAvengerPool,
  makeChildPool,
  makeProtectorPool,
  makePersecutorPool,
  makeOriginalPool,
  makeEvilPool,
} from 'overworld/pools';
import Scene from 'scene';
import ending from 'ending';

export let graphics = [];

const groundPlanePoints = mapListSet(
  addListSet(getRectanglePoints(10000, 1600), [0, 1600 / 2]),
  perspective2d,
);

// Island Geometry
const islandPosition = average(islands.map(({ position }) => position));
const islandRadius = Math.max(...islands.map(({ position }) => magnitude(subtract(position, islandPosition)))) + 200;

// Characters.
export const avngSprite = mkAvenger([...state.position], 0);
export const protSprite = mkProtector(addSet([0, 10], state.position), 0);
export const chldSprite = mkChild(addSet([-10, 0], state.position), 0);
export const persSprite = mkPersecutor(addSet([10, 0], state.position), 0);
export const gemSprite = mkGem(addSet([0, -10], state.position), 0);

graphics.push(avngSprite, protSprite, chldSprite, persSprite, gemSprite);

/*
  Miasma / Pool Creation
*/

const updateMiasma = (inc) => {
  state.miasma += 60 * inc;
  graphics = graphics.filter(([x, , , emoji]) => emoji !== tulip || x > state.miasma);
};

let triggerEnding = false;
let endingStart = 0;
const createPool =
  (maker, dialog, position) => maker(
    25,
    position,
    () => state.dialog.push(...dialog),
  );

const avengerAuthor = [avngSprite[3], `Avenger`];
const persecutorAuthor = [persSprite[3], `Persecutor`];
const protectorAuthor = [protSprite[3], `Protector`];
const childAuthor = [chldSprite[3], `Child`];
const originalAuthor = [gemSprite[3], `Origin`];

const pools = [];

const poolScript = [
  // LEVEL 1 - Adulthood.
  [makeAvengerPool, [
    [`I hate them, and everything they created.`, avengerAuthor],
    // [`I'll take them with me if I can.`, avengerAuthor]
  ]],
  [makePersecutorPool, [
    [`It couldn't hurt to try, right? Once - only once.`, persecutorAuthor]
  ]],
  [makeChildPool, [
    [`I have a new coat, with stars!`, childAuthor],
    // [`I'm going to do all my favorite things today.`, childAuthor]
  ]],
  [makeProtectorPool, [
    [`It takes so much effort at times, but we're worth all of it.`, protectorAuthor]
  ]],
  [makeEvilPool, [
    [`You take out groceries, and stack them in the pantry.`, originalAuthor],
    [`At least three of your things were already in there.`, originalAuthor],
    () => { updateMiasma(4); Scene(createBattleScene(8, 0, 0, `resentment`)) },
  ]],
  // LEVEL 2 - Young Adulthood.
  [makeChildPool, [
    [`I made a lot of new friends.`, childAuthor],
  ]],
  [makeProtectorPool, [
    [`Two years and we're beginning to take a turn.`, protectorAuthor],
  ]],
  [makePersecutorPool, [
    [`Liars can never get close to me.  I'm a liar too.`, persecutorAuthor],
  ]],
  [makeEvilPool, [
    [`Some of your friends only know one of you.`, originalAuthor],
    () => { updateMiasma(3); Scene(createBattleScene(6, 6, 0, `doubt`)) },
  ]],

  // LEVEL 3 - Teenhood.
  [makePersecutorPool, [
    [`That little piss hung up on me.`, persecutorAuthor]
  ]],
  [makeChildPool, [
    [`He said he doesn't like me anymore.`, childAuthor],
    // [`I was too hard to be around.`, childAuthor]
  ]],
  [makeEvilPool, [
    [`You went to his house for dinner.`, originalAuthor],
    // [`Everyone was was confused when you arrived.`, originalAuthor],
    [`There were confused.`, originalAuthor],
    [`You were afraid.`, originalAuthor],
    () => { updateMiasma(2); Scene(createBattleScene(0, 8, 2, `deceit`)) },
  ]],

  // LEVEL 4 - Childhood.

  [makeChildPool, [
    // [`I walked to school and back home every day.`, childAuthor],
    [`I stayed close behind the older kids.`, childAuthor],
    [`They threw cupcake and candy wrappers right on the sidewalk.`, childAuthor],
    [`I picked them up.`, childAuthor],
    [`The one watching wasn't someone I knew.`, childAuthor],
    // [`I listened to his stories.`, childAuthor]
  ]],

  [makeEvilPool, [
    [`When he kissed you, it wasn't the same.`, originalAuthor],
    () => { updateMiasma(100); Scene(createBattleScene(6, 6, 3, `harm`)) },
  ]],

  [makeOriginalPool, [
    () => {
      graphics = [];
      pools.splice(0, pools.length - 1);
      endingStart = Date.now();
      triggerEnding = true;
    }
  ]]
];

{
  const length = poolScript.length + 4;
  let i = -1;
  while(++i < length) {
    const [maker, text] = poolScript.shift();
    pools.push(createPool(maker, text, [
      i * 60 - 550,
      700 + Math.random() * 300 | 0,
    ]));
    if(maker === makeEvilPool)++i;
  }
}

// Props.
const props = [
  [mkTree, 50],
  [mkTreeAlt, 50],
  [mkMountain, 10],
  [mkTulip, 500],
  [mkGrass, 300]
];

const generatePropPosition =
  () =>
    addSet(
      scaleSet(
        rotateSet([0, 1], Math.random() * 2 * Math.PI),
        islandRadius * Math.random()
      ),
      islandPosition
    );

export const isOnIsland =
  (point) =>
    isPointInCircle(point, islandPosition, islandRadius) &&
    !!islands.find(({ collision }) => collision(point));

const isValidPropPosition =
  (point) =>
    isOnIsland(point) &&
    !pools.find(({ propCollision }) => propCollision(point));

const generateValidPropPoint =
  () => {
    let point = generatePropPosition();
    while(!isValidPropPosition(point)) point = generatePropPosition();
    return point;
  };

const len = Math.max(...props.map(([, count]) => count));
let i = -1;
while(++i < len) {
  for(const [prop, amount] of props) {
    if(i < amount) {
      graphics.push(prop(generateValidPropPoint(), 0));
    }
  }
}

// Colors
// ocean
const baseOcean = `#69D2E7`;
const seaFoam = `#fff`;

// sky
const skyBlue = `#90b4ec`;
updateMiasma(5);
export const render = () => {
  // Background
  fillRectangle(
    skyBlue,
    [0, 0],
    viewWidth * 2,
    viewHeight * 2,
    0,
  );

  fillPolygon(
    baseOcean,
    [0, 0],
    groundPlanePoints,
  );

  const waveScaleFactor = 1.2 - Math.abs(Date.now() % 7200 / (7200 / 2) - 1) / 10;

  islands.forEach(({ getShoreLine }) => strokeOval(
    { style: seaFoam, thickness: 4 },
    [0, 0],
    getShoreLine(waveScaleFactor),
  ));

  islands.forEach(({ getShoreLine }) => fillOval(
    `#fafac8`,
    [0, 0],
    getShoreLine(waveScaleFactor),
  ));

  islands.forEach(({ getBase }) => fillOval(
    `#00c864`,
    [0, 0],
    getBase(),
  ));

  // Ending segment within map.
  if(triggerEnding) {
    const diff = Date.now() - endingStart;

    if(diff > 3000) {
      Scene(ending);
      return;
    }

    pools.push(makeOriginalPool(25 + (diff / 3000) * (200 - 25), [350, 900]));
  }
  for(const pool of pools) {
    pool.render();
    pool.test(state.position);
  }

  // Dynamic
  graphics
    .map(point => [...perspective(point), point[2], point[3], point[4]])
    .sort((a, b) => b[2] - a[2])
    .forEach(([x, y, d, z, emoji, size]) => fillText(
      { font: `${(12 * size * (1 - 2 * (d - 10994) / 8248748)) | 0}px monospace` },
      [x, y - z],
      emoji
    ));

};
<commit_msg>Update Miasma placement<commit_after>import { addSet, subtract, magnitude, rotateSet, scaleSet, mapListSet, addListSet, average } from 'pura/vector/tuple';
import { getRectanglePoints } from 'pura/geometry/tuple';
import { isPointInCircle } from 'pura/intersection/tuple';
import { fillPolygon, fillRectangle, fillText, fillOval, strokeOval } from 'pura/canvas/tuple';
import { perspective, perspective2d } from 'camera';
import { viewWidth, viewHeight } from 'dom';
import state from 'state';
import { islands } from 'overworld/island';
import { tulip } from 'emoji';
import { createBattleScene } from 'battle';
import {
  mkTree,
  mkTreeAlt,
  mkAvenger,
  mkChild,
  mkProtector,
  mkPersecutor,
  mkGem,
  mkMountain,
  mkTulip,
  mkGrass,
} from 'sprite';
import {
  makeAvengerPool,
  makeChildPool,
  makeProtectorPool,
  makePersecutorPool,
  makeOriginalPool,
  makeEvilPool,
} from 'overworld/pools';
import Scene from 'scene';
import ending from 'ending';

export let graphics = [];

const groundPlanePoints = mapListSet(
  addListSet(getRectanglePoints(10000, 1600), [0, 1600 / 2]),
  perspective2d,
);

// Island Geometry
const islandPosition = average(islands.map(({ position }) => position));
const islandRadius = Math.max(...islands.map(({ position }) => magnitude(subtract(position, islandPosition)))) + 200;

// Characters.
export const avngSprite = mkAvenger([...state.position], 0);
export const protSprite = mkProtector(addSet([0, 10], state.position), 0);
export const chldSprite = mkChild(addSet([-10, 0], state.position), 0);
export const persSprite = mkPersecutor(addSet([10, 0], state.position), 0);
export const gemSprite = mkGem(addSet([0, -10], state.position), 0);

graphics.push(avngSprite, protSprite, chldSprite, persSprite, gemSprite);

/*
  Miasma / Pool Creation
*/

const updateMiasma = (inc) => {
  state.miasma += 50 * inc;
  graphics = graphics.filter(([x, , , emoji]) => emoji !== tulip || x > state.miasma);
};

let triggerEnding = false;
let endingStart = 0;
const createPool =
  (maker, dialog, position) => maker(
    25,
    position,
    () => state.dialog.push(...dialog),
  );

const avengerAuthor = [avngSprite[3], `Avenger`];
const persecutorAuthor = [persSprite[3], `Persecutor`];
const protectorAuthor = [protSprite[3], `Protector`];
const childAuthor = [chldSprite[3], `Child`];
const originalAuthor = [gemSprite[3], `Origin`];

const pools = [];

const poolScript = [
  // LEVEL 1 - Adulthood.
  [makeAvengerPool, [
    [`I hate them, and everything they created.`, avengerAuthor],
    // [`I'll take them with me if I can.`, avengerAuthor]
  ]],
  [makePersecutorPool, [
    [`It couldn't hurt to try, right? Once - only once.`, persecutorAuthor]
  ]],
  [makeChildPool, [
    [`I have a new coat, with stars!`, childAuthor],
    // [`I'm going to do all my favorite things today.`, childAuthor]
  ]],
  [makeProtectorPool, [
    [`It takes so much effort at times, but we're worth all of it.`, protectorAuthor]
  ]],
  [makeEvilPool, [
    [`You take out groceries, and stack them in the pantry.`, originalAuthor],
    [`At least three of your things were already in there.`, originalAuthor],
    () => { updateMiasma(5); Scene(createBattleScene(8, 0, 0, `resentment`)) },
  ]],
  // LEVEL 2 - Young Adulthood.
  [makeChildPool, [
    [`I made a lot of new friends.`, childAuthor],
  ]],
  [makeProtectorPool, [
    [`Two years and we're beginning to take a turn.`, protectorAuthor],
  ]],
  [makePersecutorPool, [
    [`Liars can never get close to me.  I'm a liar too.`, persecutorAuthor],
  ]],
  [makeEvilPool, [
    [`Some of your friends only know one of you.`, originalAuthor],
    () => { updateMiasma(4); Scene(createBattleScene(6, 6, 0, `doubt`)) },
  ]],

  // LEVEL 3 - Teenhood.
  [makePersecutorPool, [
    [`That little piss hung up on me.`, persecutorAuthor]
  ]],
  [makeChildPool, [
    [`He said he doesn't like me anymore.`, childAuthor],
    // [`I was too hard to be around.`, childAuthor]
  ]],
  [makeEvilPool, [
    [`You went to his house for dinner.`, originalAuthor],
    // [`Everyone was was confused when you arrived.`, originalAuthor],
    [`There were confused.`, originalAuthor],
    [`You were afraid.`, originalAuthor],
    () => { updateMiasma(2); Scene(createBattleScene(0, 8, 2, `deceit`)) },
  ]],

  // LEVEL 4 - Childhood.

  [makeChildPool, [
    // [`I walked to school and back home every day.`, childAuthor],
    [`I stayed close behind the older kids.`, childAuthor],
    [`They threw cupcake and candy wrappers right on the sidewalk.`, childAuthor],
    [`I picked them up.`, childAuthor],
    [`The one watching wasn't someone I knew.`, childAuthor],
    // [`I listened to his stories.`, childAuthor]
  ]],

  [makeEvilPool, [
    [`When he kissed you, it wasn't the same.`, originalAuthor],
    () => { updateMiasma(100); Scene(createBattleScene(6, 6, 3, `harm`)) },
  ]],

  [makeOriginalPool, [
    () => {
      graphics = [];
      pools.splice(0, pools.length - 1);
      endingStart = Date.now();
      triggerEnding = true;
    }
  ]]
];

{
  const length = poolScript.length + 4;
  let i = -1;
  while(++i < length) {
    const [maker, text] = poolScript.shift();
    pools.push(createPool(maker, text, [
      i * 50 - 550,
      650 + Math.random() * 400 | 0,
    ]));
    if(maker === makeEvilPool)++i;
  }
}

// Props.
const props = [
  [mkTree, 50],
  [mkTreeAlt, 50],
  [mkMountain, 10],
  [mkTulip, 500],
  [mkGrass, 300]
];

const generatePropPosition =
  () =>
    addSet(
      scaleSet(
        rotateSet([0, 1], Math.random() * 2 * Math.PI),
        islandRadius * Math.random()
      ),
      islandPosition
    );

export const isOnIsland =
  (point) =>
    isPointInCircle(point, islandPosition, islandRadius) &&
    !!islands.find(({ collision }) => collision(point));

const isValidPropPosition =
  (point) =>
    isOnIsland(point) &&
    !pools.find(({ propCollision }) => propCollision(point));

const generateValidPropPoint =
  () => {
    let point = generatePropPosition();
    while(!isValidPropPosition(point)) point = generatePropPosition();
    return point;
  };

const len = Math.max(...props.map(([, count]) => count));
let i = -1;
while(++i < len) {
  for(const [prop, amount] of props) {
    if(i < amount) {
      graphics.push(prop(generateValidPropPoint(), 0));
    }
  }
}

// Colors
// ocean
const baseOcean = `#69D2E7`;
const seaFoam = `#fff`;

// sky
const skyBlue = `#90b4ec`;
updateMiasma(5);
export const render = () => {
  // Background
  fillRectangle(
    skyBlue,
    [0, 0],
    viewWidth * 2,
    viewHeight * 2,
    0,
  );

  fillPolygon(
    baseOcean,
    [0, 0],
    groundPlanePoints,
  );

  const waveScaleFactor = 1.2 - Math.abs(Date.now() % 7200 / (7200 / 2) - 1) / 10;

  islands.forEach(({ getShoreLine }) => strokeOval(
    { style: seaFoam, thickness: 4 },
    [0, 0],
    getShoreLine(waveScaleFactor),
  ));

  islands.forEach(({ getShoreLine }) => fillOval(
    `#fafac8`,
    [0, 0],
    getShoreLine(waveScaleFactor),
  ));

  islands.forEach(({ getBase }) => fillOval(
    `#00c864`,
    [0, 0],
    getBase(),
  ));

  // Ending segment within map.
  if(triggerEnding) {
    const diff = Date.now() - endingStart;

    if(diff > 3000) {
      Scene(ending);
      return;
    }

    pools.push(makeOriginalPool(25 + (diff / 3000) * (200 - 25), [350, 900]));
  }
  for(const pool of pools) {
    pool.render();
    pool.test(state.position);
  }

  // Dynamic
  graphics
    .map(point => [...perspective(point), point[2], point[3], point[4]])
    .sort((a, b) => b[2] - a[2])
    .forEach(([x, y, d, z, emoji, size]) => fillText(
      { font: `${(12 * size * (1 - 2 * (d - 10994) / 8248748)) | 0}px monospace` },
      [x, y - z],
      emoji
    ));

};
<|endoftext|>


<commit_before>import React, { Component, Fragment } from 'react'
import Helmet from 'react-helmet'
import { api } from 'data.json'
import { Heading, Container, LargeButton } from '@hackclub/design-system'
import LeaderApplicationForm from 'components/apply/LeaderApplicationForm'
import Login from 'components/apply/Login'
import ApplyNav from 'components/apply/ApplyNav'
import LoadingAnimation from 'components/LoadingAnimation'
import Footer from 'components/Footer'

export default class extends Component {
  constructor(props) {
    super(props)

    this.state = {
      status: 'loading',
      formFields: undefined,
      id: undefined,
      authToken: undefined
    }
  }

  componentDidMount() {
    let id
    const params = window.location.search.slice(1).split(/&/)
    for (let i = 0; i < params.length; i++) {
      let param = params[i]
      if (param.split('=')[0] === 'id') {
        id = param.split('=')[1]
      }
    }
    const authToken = window.localStorage.getItem('authToken')
    this.setState({ id, authToken })
    const needsToAuth = authToken === null || id === null
    if (needsToAuth) {
      const status = 'needsToAuth'
      this.setState({ status })
    } else {
      fetch(`${api}/v1/leader_profiles/${id}`, {
        method: 'GET',
        headers: { Authorization: `Bearer ${authToken}` }
      })
        .then(res => {
          if (res.ok) {
            return res.json()
          } else {
            throw res
          }
        })
        .then(json => {
          this.setState({
            status: 'loaded',
            formFields: json
          })
        })
        .catch(e => {
          if (e.status === 401) {
            const status = 'needsToAuth'
            this.setState({ status })
          }
          alert(e)
        })
    }
  }

  content() {
    const { status, formFields, id, authToken } = this.state

    if (status === 'needsToAuth') {
      return <Login />
    } else if (status === 'loading') {
      return <LoadingAnimation />
    } else {
      return (
        <Fragment>
          <ApplyNav />
          <LeaderApplicationForm
            params={formFields}
            id={id}
            authToken={authToken}
          />
          <Heading.h4 align="center">
            Your form is automatically saved ✨
          </Heading.h4>
          <Container align="center" my={4}>
            <LargeButton.link to="/apply">« Back</LargeButton.link>
          </Container>
          <Footer />
        </Fragment>
      )
    }
  }

  render() {
    return (
      <Fragment>
        <Helmet title="Edit Leader Application – Hack Club" />
        {this.content()}
      </Fragment>
    )
  }
}
<commit_msg>Fix leader application form API url<commit_after>import React, { Component, Fragment } from 'react'
import Helmet from 'react-helmet'
import { url as apiUrl } from 'api'
import { Heading, Container, LargeButton } from '@hackclub/design-system'
import LeaderApplicationForm from 'components/apply/LeaderApplicationForm'
import Login from 'components/apply/Login'
import ApplyNav from 'components/apply/ApplyNav'
import LoadingAnimation from 'components/LoadingAnimation'
import Footer from 'components/Footer'

export default class extends Component {
  constructor(props) {
    super(props)

    this.state = {
      status: 'loading',
      formFields: undefined,
      id: undefined,
      authToken: undefined
    }
  }

  componentDidMount() {
    let id
    const params = window.location.search.slice(1).split(/&/)
    for (let i = 0; i < params.length; i++) {
      let param = params[i]
      if (param.split('=')[0] === 'id') {
        id = param.split('=')[1]
      }
    }
    const authToken = window.localStorage.getItem('authToken')
    this.setState({ id, authToken })
    const needsToAuth = authToken === null || id === null
    if (needsToAuth) {
      const status = 'needsToAuth'
      this.setState({ status })
    } else {
      fetch(`${apiUrl}/v1/leader_profiles/${id}`, {
        method: 'GET',
        headers: { Authorization: `Bearer ${authToken}` }
      })
        .then(res => {
          if (res.ok) {
            return res.json()
          } else {
            throw res
          }
        })
        .then(json => {
          this.setState({
            status: 'loaded',
            formFields: json
          })
        })
        .catch(e => {
          if (e.status === 401) {
            const status = 'needsToAuth'
            this.setState({ status })
          }
          alert(e)
        })
    }
  }

  content() {
    const { status, formFields, id, authToken } = this.state

    if (status === 'needsToAuth') {
      return <Login />
    } else if (status === 'loading') {
      return <LoadingAnimation />
    } else {
      return (
        <Fragment>
          <ApplyNav />
          <LeaderApplicationForm
            params={formFields}
            id={id}
            authToken={authToken}
          />
          <Heading.h4 align="center">
            Your form is automatically saved ✨
          </Heading.h4>
          <Container align="center" my={4}>
            <LargeButton.link to="/apply">« Back</LargeButton.link>
          </Container>
          <Footer />
        </Fragment>
      )
    }
  }

  render() {
    return (
      <Fragment>
        <Helmet title="Edit Leader Application – Hack Club" />
        {this.content()}
      </Fragment>
    )
  }
}
<|endoftext|>


<commit_before>L.provide('OML.network', ["d3/d3"], function () {

  OML['network'] = function(opts) {
    this.opts = opts || {};
    this.data = null;

    this.init = function() {
      var o = this.opts;

      var w = this.w = o['width'] || 700;
      var h = this.h = o['height'] || 400;

      var m = o['margin'] || {};
      var ml = m['left'] || 30;
      var mt = m['top'] || 20;
      var mr = m['right'] || 20;
      var mb = m['bottom'] || 20;
      var ca = this.chart_area = {x: ml, y: mb, w: w - ml - mr, h: h - mt - mb};

      var offset = o['offset'] || [0, 0];

      this.color = o['color'] || d3.scale.category10();

      var vis = this.init_svg(w, h);

      var g =  this.base_layer = vis.append("svg:g")
                 .attr("transform", "translate(0, " + h + ")")
                 ;

      this.color_func = {
        "green_yellow80_red": d3.scale.linear()
                                .domain([0, 0.8, 1])
                                .range(["green", "yellow", "red"]),
        "green_red":          d3.scale.linear()
                                .domain([0, 1])
                                .range(["green", "red"])
      };
      this.graph_layer = g.append("svg:g");

      var self = this;
      OHUB.bind("graph.highlighted", function(evt) {
        if (evt.source == self) return;
        self.on_highlighted(evt);
      });

      var data = this.data = o.data;
      if (data) this.redraw({});
    };

    this.append = function(a_data) {
      var data = this.data;
      data.nodes = $.extend(data.nodes, a_data.nodes);
      data.links = $.extend(data.links, a_data.links);
      this.redraw({});
    };

    this.update = function(data) {
      this.data = data;
      this.redraw({});
    };

    this.redraw = function(ropts) {
      var self = this;
      var data = this.data;
      var o = this.opts;
      var mapping = o.mapping || {};
      var ca = this.chart_area;

      var x = function(d) {
        var x = d.x * ca.w + ca.x;
        return x;
      };
      var y = function(d) {
        var y = -1 * (d.y * ca.h + ca.y);
        return y;
      };
      var c = d3.scale.linear()
          .domain([0, 0.8, 1])
          .range(["green", "yellow", "red"]);

      this._func = {};
      var lmapping = mapping.link;
      var lstroke = c(0);
      var lstroke_width = 4;
      if (typeof(lmapping) != "undefined") {
        lstroke_width = this.property_mapper('stroke_width', lmapping.stroke_width, lstroke_width);
        lstroke = this.property_mapper('stroke', lmapping.stroke_color, lstroke);
      }
      this._func.lstroke = lstroke;
      this._func.lstroke_width = lstroke_width;

      var nmapping = mapping.node;
      var nfill = "white";
      var nradius = 10;
      if (typeof(nmapping) != "undefined") {
        nfill = this.property_mapper('fill', nmapping.fill_color, nfill);
        nradius = this.property_mapper('radius', nmapping.radius, nradius);
      }
      this._func.nfill = nfill;
      this._func.nradius = nradius;

      var vis = this.base_layer;
      var link = vis.selectAll("line.link")
        .data(d3.values(data.links))
          .style("stroke", lstroke)
          .style("stroke-width", lstroke_width)
          .attr("x1", function(d) {
            var x1 = x(data.nodes[d.from]);
            return x(data.nodes[d.from]);
          })
          .attr("y1", function(d) { return y(data.nodes[d.from]); })
          .attr("x2", function(d) { return x(data.nodes[d.to]); })
          .attr("y2", function(d) { return y(data.nodes[d.to]); })
        .enter().append("svg:line")
          .attr("class", "link")
          .style("stroke", lstroke)
          .style("stroke-width", lstroke_width)
          .attr("x1", function(d) {
            var x1 = x(data.nodes[d.from]);
            return x(data.nodes[d.from]);
          })
          .attr("y1", function(d) { return y(data.nodes[d.from]); })
          .attr("x2", function(d) { return x(data.nodes[d.to]); })
          .attr("y2", function(d) { return y(data.nodes[d.to]); })
          .on("mouseover", function(data) {
            var name = data.name;
            self.on_highlighted({'elements': [{'name': name, 'type': 'link'}]});
          })
          .on("mouseout", function() {
            self.on_dehighlighted({});
          })

          // .on("mouseover", function() {
            // d3.select(this).transition()
             // .style("stroke-width", function(d) {
               // return d.stroke_width + 3
             // })
            // .delay(0)
            // .duration(300)
          // })
          // .on("mouseout", function() {
            // d3.select(this).transition()
             // .style("stroke-width", function(d) {return d.stroke_width})
             // .delay(0)
             // .duration(300)
          // })
          ;

     var node = vis.selectAll("circle.node")
       .data(d3.values(data.nodes))
         .attr("cx", function(d) { return x(d); })
         .attr("cy", function(d) { return y(d); })
         .attr("r", nradius)
         .style("fill", nfill)
       .enter().append("svg:circle")
         .attr("class", "node")
         .attr("cx", function(d) { return x(d); })
         .attr("cy", function(d) { return y(d); })
         .attr("r", nradius)
         .style("fill", nfill)
         .style("stroke", "gray")
         .style("stroke-width", 1)
         .attr("fixed", true)
         //.call(force.drag)
          .on("mouseover", function(data) {
            var name = data.name;
            self.on_highlighted({'elements': [{'name': name, 'type': 'node'}]});
          })
          .on("mouseout", function() {
            self.on_dehighlighted({});
          })
        .transition()
          .attr("r", nradius)
          .delay(0)
       ;
    };

    this.init_svg = function(w, h) {
      var opts = this.opts;

      //if (opts.svg) return opts.svg;

      var base_el = opts.base_el || "body";
      if (typeof(base_el) == "string") base_el = d3.select(base_el);
      var vis = opts.svg = base_el.append("svg:svg")
        .attr("width", w)
        .attr("height", h)
        .attr('class', 'oml-network');
      return vis;
    }

    this.on_highlighted = function(evt) {
      var els = evt.elements;
      var links = _.filter(els, function(el) { return  el.type == 'link'});
      if (links.length > 0) { this._on_links_highlighted(links); }
      var nodes = _.filter(els, function(el) { return  el.type == 'node'});
      if (nodes.length > 0) { this._on_nodes_highlighted(nodes); }

      if (evt.source == null) {
        evt.source = this;
        OHUB.trigger("graph.highlighted", evt);
      }
    }

    this.on_dehighlighted = function(evt) {
      this._on_links_dehighlighted();
      this._on_nodes_dehighlighted();

      if (evt.source == null) {
        evt.source = this;
        OHUB.trigger("graph.dehighlighted", evt);
      }
    }

    this._on_nodes_highlighted = function(nodes) {
      var names = _.map(nodes, function(el) { return el.name});
      var vis = this.base_layer;
      vis.selectAll("circle.node")
       .filter(function(d) {
         return ! _.include(names, d.name);
       })
       .transition()
         .style("stroke", "lightgray")
         .style("fill", "rgb(240,240,240)")
         .delay(0)
         .duration(300);
    }

    this._on_nodes_dehighlighted = function() {
      var vis = this.base_layer;
      var nfill = this._func.nfill;
      vis.selectAll("circle.node")
       .transition()
         .style("stroke", "gray")
         .style("fill", nfill)
         .delay(0)
         .duration(300);
    }

    this._on_links_highlighted = function(links) {
      var names = _.map(links, function(el) { return el.name});
      var vis = this.base_layer;
      vis.selectAll("line.link")
       .filter(function(d) {
         return ! _.include(names, d.name);
       })
       .transition()
         .style("opacity", 0.1)
         .delay(0)
         .duration(300);
    }

    this._on_links_dehighlighted = function() {
      var vis = this.base_layer;
      vis.selectAll("line.link")
       .transition()
         .style("opacity", 1.0)
         .delay(0)
         .duration(300)
    }

    this.property_mapper = function(name, sm, def_value) {
      var mapper_f;
      if (typeof(sm) != "undefined") {
        var prop = sm.property;
        var scale = sm.scale ? sm.scale : 1;
        var color_f = sm.color ? this.color_func[sm.color] : null;
        var max = sm.max ? sm.max : 10;
        var min = sm.min ? sm.min : 1;
        if (color_f == null) {
          mapper_f = function(d) {
            var v = d[prop] * scale;
            var t = typeof(v);
            if (v > max) {
              v = max;
            } else if (v < min) {
              v = min;
            } else if (isNaN(v)) {
              v = max;
            }
            d[name] = v;
            return v;
          }
        } else {
          mapper_f = function(d) {
            var v = d[prop] * scale;
            if (v > 1.0) {
              v = 1.0;
            } else if (v < 0) {
              v = 0;
            } else if (isNaN(v)) {
              v = 0;
            }
            v = color_f(v);
            d[name] = v;
            return v;
          }
        }
      } else {
        mapper_f = def_value;
      }
      return mapper_f;
    }

    this.init(opts);
  };
})

/*
  Local Variables:
  mode: Javascript
  tab-width: 2
  indent-tabs-mode: nil
  End:
*/<commit_msg>Visualizing links with curved lines to distinguish the two directions.<commit_after>L.provide('OML.network', ["d3/d3"], function () {

  OML['network'] = function(opts) {
    this.opts = opts || {};
    this.data = null;

    this.init = function() {
      var o = this.opts;

      var w = this.w = o['width'] || 700;
      var h = this.h = o['height'] || 400;

      var m = o['margin'] || {};
      var ml = m['left'] || 30;
      var mt = m['top'] || 20;
      var mr = m['right'] || 20;
      var mb = m['bottom'] || 20;
      var ca = this.chart_area = {x: ml, y: mb, w: w - ml - mr, h: h - mt - mb};

      var offset = o['offset'] || [0, 0];

      this.color = o['color'] || d3.scale.category10();

      var vis = this.init_svg(w, h);

      var g =  this.base_layer = vis.append("svg:g")
                 .attr("transform", "translate(0, " + h + ")")
                 ;

      this.color_func = {
        "green_yellow80_red": d3.scale.linear()
                                .domain([0, 0.8, 1])
                                .range(["green", "yellow", "red"]),
        "green_red":          d3.scale.linear()
                                .domain([0, 1])
                                .range(["green", "red"])
      };
      this.graph_layer = g.append("svg:g");

      var self = this;
      OHUB.bind("graph.highlighted", function(evt) {
        if (evt.source == self) return;
        self.on_highlighted(evt);
      });

      var data = this.data = o.data;
      if (data) this.redraw({});
    };

    this.append = function(a_data) {
      var data = this.data;
      data.nodes = $.extend(data.nodes, a_data.nodes);
      data.links = $.extend(data.links, a_data.links);
      this.redraw({});
    };

    this.update = function(data) {
      this.data = data;
      this.redraw({});
    };

    this.redraw = function(ropts) {
      var self = this;
      var data = this.data;
      var o = this.opts;
      var mapping = o.mapping || {};
      var ca = this.chart_area;

      var x = function(d) {
        var x = d.x * ca.w + ca.x;
        return x;
      };
      var y = function(d) {
        var y = -1 * (d.y * ca.h + ca.y);
        return y;
      };
      var c = d3.scale.linear()
          .domain([0, 0.8, 1])
          .range(["green", "yellow", "red"]);

      this._func = {};
      var lmapping = mapping.link;
      var lstroke = c(0);
      var lstroke_width = 4;
      if (typeof(lmapping) != "undefined") {
        lstroke_width = this.property_mapper('stroke_width', lmapping.stroke_width, lstroke_width);
        lstroke = this.property_mapper('stroke', lmapping.stroke_color, lstroke);
      }
      this._func.lstroke = lstroke;
      this._func.lstroke_width = lstroke_width;

      var nmapping = mapping.node;
      var nfill = "white";
      var nradius = 10;
      if (typeof(nmapping) != "undefined") {
        nfill = this.property_mapper('fill', nmapping.fill_color, nfill);
        nradius = this.property_mapper('radius', nmapping.radius, nradius);
      }
      this._func.nfill = nfill;
      this._func.nradius = nradius;

      var vis = this.base_layer;
      // var link = vis.selectAll("line.link")
        // .data(d3.values(data.links))
          // .style("stroke", lstroke)
          // .style("stroke-width", lstroke_width)
          // .attr("x1", function(d) {
            // var x1 = x(data.nodes[d.from]);
            // return x(data.nodes[d.from]);
          // })
          // .attr("y1", function(d) { return y(data.nodes[d.from]); })
          // .attr("x2", function(d) { return x(data.nodes[d.to]); })
          // .attr("y2", function(d) { return y(data.nodes[d.to]); })
        // .enter().append("svg:line")
          // .attr("class", "link")
          // .style("stroke", lstroke)
          // .style("stroke-width", lstroke_width)
          // .attr("x1", function(d) {
            // var x1 = x(data.nodes[d.from]);
            // return x(data.nodes[d.from]);
          // })
          // .attr("y1", function(d) { return y(data.nodes[d.from]); })
          // .attr("x2", function(d) { return x(data.nodes[d.to]); })
          // .attr("y2", function(d) { return y(data.nodes[d.to]); })
          // .on("mouseover", function(data) {
            // var name = data.name;
            // self.on_highlighted({'elements': [{'name': name, 'type': 'link'}]});
          // })
          // .on("mouseout", function() {
            // self.on_dehighlighted({});
          // })

      var line_f = function(d) {
        var a = 0.2;
        var b = 0.3;
        var o = 30;

        var x1 = x(data.nodes[d.from]);
        var y1 = y(data.nodes[d.from]);
        var x3 = x(data.nodes[d.to]);
        var y3 = y(data.nodes[d.to]);

        var dx = x3 - x1;
        var dy = y3 - y1;
        var l = Math.sqrt(dx * dx + dy * dy);

        var mx = x1 + a * dx;
        var my = y1 + a * dy;
        var x2 = mx - (dy * o / l)
        var y2 = my + (dx * o / l);

        var l = d3.svg.line().interpolate('basis');
        return l([[x1, y1], [x2, y2], [x3, y3]]);
      };

      var link2 = vis.selectAll("path.link")
        .data(d3.values(data.links))
          .style("stroke", lstroke)
          .style("stroke-width", lstroke_width)
          .attr("d", line_f)
        .enter().append("svg:path")
          .attr("class", "link")
          .style("stroke", lstroke)
          .style("stroke-width", lstroke_width)
          .attr("fill", "none")
          .attr("d", line_f)
          .on("mouseover", function(data) {
            var name = data.name;
            self.on_highlighted({'elements': [{'name': name, 'type': 'link'}]});
          })
          .on("mouseout", function() {
            self.on_dehighlighted({});
          })
          ;

          // .on("mouseover", function() {
            // d3.select(this).transition()
             // .style("stroke-width", function(d) {
               // return d.stroke_width + 3
             // })
            // .delay(0)
            // .duration(300)
          // })
          // .on("mouseout", function() {
            // d3.select(this).transition()
             // .style("stroke-width", function(d) {return d.stroke_width})
             // .delay(0)
             // .duration(300)
          // })
          ;

     var node = vis.selectAll("circle.node")
       .data(d3.values(data.nodes))
         .attr("cx", function(d) { return x(d); })
         .attr("cy", function(d) { return y(d); })
         .attr("r", nradius)
         .style("fill", nfill)
       .enter().append("svg:circle")
         .attr("class", "node")
         .attr("cx", function(d) { return x(d); })
         .attr("cy", function(d) { return y(d); })
         .attr("r", nradius)
         .style("fill", nfill)
         .style("stroke", "gray")
         .style("stroke-width", 1)
         .attr("fixed", true)
         //.call(force.drag)
          .on("mouseover", function(data) {
            var name = data.name;
            self.on_highlighted({'elements': [{'name': name, 'type': 'node'}]});
          })
          .on("mouseout", function() {
            self.on_dehighlighted({});
          })
        .transition()
          .attr("r", nradius)
          .delay(0)
       ;
    };

    this.init_svg = function(w, h) {
      var opts = this.opts;

      //if (opts.svg) return opts.svg;

      var base_el = opts.base_el || "body";
      if (typeof(base_el) == "string") base_el = d3.select(base_el);
      var vis = opts.svg = base_el.append("svg:svg")
        .attr("width", w)
        .attr("height", h)
        .attr('class', 'oml-network');
      return vis;
    }

    this.on_highlighted = function(evt) {
      var els = evt.elements;
      var links = _.filter(els, function(el) { return  el.type == 'link'});
      if (links.length > 0) { this._on_links_highlighted(links); }
      var nodes = _.filter(els, function(el) { return  el.type == 'node'});
      if (nodes.length > 0) { this._on_nodes_highlighted(nodes); }

      if (evt.source == null) {
        evt.source = this;
        OHUB.trigger("graph.highlighted", evt);
      }
    }

    this.on_dehighlighted = function(evt) {
      this._on_links_dehighlighted();
      this._on_nodes_dehighlighted();

      if (evt.source == null) {
        evt.source = this;
        OHUB.trigger("graph.dehighlighted", evt);
      }
    }

    this._on_nodes_highlighted = function(nodes) {
      var names = _.map(nodes, function(el) { return el.name});
      var vis = this.base_layer;
      vis.selectAll("circle.node")
       .filter(function(d) {
         return ! _.include(names, d.name);
       })
       .transition()
         .style("stroke", "lightgray")
         .style("fill", "rgb(240,240,240)")
         .delay(0)
         .duration(300);
    }

    this._on_nodes_dehighlighted = function() {
      var vis = this.base_layer;
      var nfill = this._func.nfill;
      vis.selectAll("circle.node")
       .transition()
         .style("stroke", "gray")
         .style("fill", nfill)
         .delay(0)
         .duration(300);
    }

    this._on_links_highlighted = function(links) {
      var names = _.map(links, function(el) { return el.name});
      var vis = this.base_layer;
      vis.selectAll("path.link")
       .filter(function(d) {
         return ! _.include(names, d.name);
       })
       .transition()
         .style("opacity", 0.1)
         .delay(0)
         .duration(300);
    }

    this._on_links_dehighlighted = function() {
      var vis = this.base_layer;
      vis.selectAll("path.link")
       .transition()
         .style("opacity", 1.0)
         .delay(0)
         .duration(300)
    }

    this.property_mapper = function(name, sm, def_value) {
      var mapper_f;
      if (typeof(sm) != "undefined") {
        var prop = sm.property;
        var scale = sm.scale ? sm.scale : 1;
        var color_f = sm.color ? this.color_func[sm.color] : null;
        var max = sm.max ? sm.max : 10;
        var min = sm.min ? sm.min : 1;
        if (color_f == null) {
          mapper_f = function(d) {
            var v = d[prop] * scale;
            var t = typeof(v);
            if (v > max) {
              v = max;
            } else if (v < min) {
              v = min;
            } else if (isNaN(v)) {
              v = max;
            }
            d[name] = v;
            return v;
          }
        } else {
          mapper_f = function(d) {
            var v = d[prop] * scale;
            if (v > 1.0) {
              v = 1.0;
            } else if (v < 0) {
              v = 0;
            } else if (isNaN(v)) {
              v = 0;
            }
            v = color_f(v);
            d[name] = v;
            return v;
          }
        }
      } else {
        mapper_f = def_value;
      }
      return mapper_f;
    }

    this.init(opts);
  };
})

/*
  Local Variables:
  mode: Javascript
  tab-width: 2
  indent-tabs-mode: nil
  End:
*/<|endoftext|>


<commit_before>import clone from "lodash/fp/clone";

class Workflow2Graph {

  constructor() {
  }

  convert(wfe, meta) {
    this._convert(wfe, meta);
    return {edges: this.edges, vertices: this.vertices, id: wfe.workflowId};
  }
  _convert(wfe = {}, meta = {}) {
    const subworkflows = {};
    const metaTasks = meta.tasks && clone(meta.tasks) || [];
    metaTasks.push({type:'final', name:'final', label: '', taskReferenceName: 'final', system: true});
    metaTasks.unshift({type:'start', name:'start', label: '', taskReferenceName: 'start', system: true});

    const forks = [];
    const tasks = wfe.tasks || [];
    tasks.forEach(tt=>{
      if(tt.taskType === 'FORK'){
        let wfts = [];
        let forkedTasks = tt.inputData && tt.inputData.forkedTasks || [];
        forkedTasks.forEach(ft =>{
          wfts.push({name: ft, referenceTaskName: ft, type: 'SIMPLE'});
        });
        forks[tt.referenceTaskName] = wfts;
      }
    });

    let nodes = [];
    let vertices = {};

    this.executedTasks = {};
    let joins = {};
    wfe.tasks.forEach(t => {
      this.executedTasks[t.referenceTaskName] = {status: t.status, input: t.inputData, output: t.outputData, taskType: t.taskType, reasonForIncompletion: t.reasonForIncompletion, task: t};
      if(t.taskType === 'JOIN' ){
        joins[t.referenceTaskName] = t.inputData.joinOn;
      }
    });

    this.executedTasks['final'] = {status: '', input: '', output: wfe.output, taskType: 'final', reasonForIncompletion: wfe.reasonForIncompletion, task: {}};
    this.executedTasks['start'] = {status: 'STARTED', input: wfe.input, output: '', taskType: 'final', reasonForIncompletion: '', task: {}};
    this.getTaskNodes(vertices, nodes, metaTasks, forks, subworkflows, true);

    this.edges = nodes;
    this.vertices = vertices;
    this.vertices['final'] = {name: 'final', ref: 'final', type: 'final', style: 'fill:#ffffff', shape: 'circle', system: true};
    this.vertices['start'] = {name: 'start', ref: 'start', type: 'start', style: 'fill: #ffffff', shape: 'circle', system: true};

    for(let v in this.vertices) {

      let et = this.executedTasks[v];
      let status = et ? et.status : '';

      let style = '';
      let labelStyle = '';
      switch (status) {
        case 'FAILED':
        case 'TIMED_OUT':
        case 'CANCELLED':
        case 'CANCELED':
        case 'FAILED_WITH_TERMINAL_ERROR':
          style = 'stroke: #ff0000; fill: #ff0000';
          labelStyle = 'fill:#ffffff; stroke-width: 1px';
          break;
        case 'IN_PROGRESS':
        case 'SCHEDULED':
          style = 'stroke: orange; fill: orange';
          labelStyle = 'fill:#ffffff; stroke-width: 1px';
          break;
        case 'COMPLETED':
          style = 'stroke: #48a770; fill: #48a770';
          labelStyle = 'fill:#ffffff; stroke-width: 1px';
          break;
        case 'COMPLETED_WITH_ERRORS':
          style = 'stroke: #FF8C00; fill: #FF8C00';
          labelStyle = 'fill:#ffffff; stroke-width: 1px';
          break;
        case 'SKIPPED':
          style = 'stroke: #cccccc; fill: #ccc';
          labelStyle = 'fill:#ffffff; stroke-width: 1px';
          break;
        case '':
          break;
        default:
          break;
      }
      if (status != '') {

        this.vertices[v].style = style;
        this.vertices[v].labelStyle = labelStyle;
        let tooltip = '
Input
' + JSON.stringify(et.input, null, 2) + '

Output
' + JSON.stringify(et.output, null, 2);
        tooltip += '

Status : ' + et.status + '
';
        if (status == 'FAILED') {
          tooltip += '
Failure Reason

' + et.reasonForIncompletion + '
';
        }
        this.vertices[v].data = et;
        this.vertices[v].tooltip = tooltip;
        this.vertices[v].tooltipTitle = et.taskType + ' - ' + et.status;
      }
    }

  }

  getTaskNodes(vertices, nodes, tasks, forks, subworkflows, isExecutingCase){
    if(tasks == null || tasks.length == null){
      return nodes;
    }
    for(let i = 1; i < tasks.length; i++){
      this.getNodes(vertices, nodes, tasks[i-1], tasks[i], forks, subworkflows, isExecutingCase);
    }
    return nodes;
  }

  getNodes(vertices, nodes, t1, t2, forks, subworkflows, isExecutingCase){

    let executed = 'stroke: #000000; fill: transparent';
    let defstyle = 'stroke: #ccc; fill: transparent; stroke-dasharray: 5, 5';
    let isExecuting = isExecutingCase;
    if(t1.type == 'final' && t1.type == t2.type){
      vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: 'simple', style: '', shape: 'circle', system: true, description: t1.description};
      return nodes;
    }

    if(t1.type == 'FORK_JOIN'){

      vertices[t1.taskReferenceName] = {name: 'FORK', ref: t1.taskReferenceName, type: 'simple', style: 'fill: #ff0', shape: 'house', system: true, description: t1.description};
      let r = t1.taskReferenceName;

      let fork = t1.forkTasks || [];
      fork.forEach(ft => {

        let tasks = ft;

        vertices[tasks[0].taskReferenceName] = {name: tasks[0].name, ref: tasks[0].taskReferenceName, type: tasks[0].type, style: '', shape: 'rect', description: tasks[0].description};

        let style = defstyle;
        if(this.executedTasks[tasks[0].taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
          style = executed;
        } else {
          isExecuting = false;
        }

        nodes.push({type: 'FORK', from: t1.taskReferenceName, to: tasks[0].taskReferenceName, label: '', style: style});

        this.getTaskNodes(vertices, nodes, tasks, forks, subworkflows);
        this.getNodes(vertices, nodes, tasks[tasks.length-1], t2, forks, subworkflows);
      });

    } else if(t1.type == 'FORK_JOIN_DYNAMIC'){

        vertices[t1.taskReferenceName] = {name: 'DYNAMIC_FORK', ref: t1.taskReferenceName, type: 'simple', style: 'fill: #ff0', shape: 'house', system: true, description: t1.description};
        let style = defstyle;
        if(this.executedTasks[t2.taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
          style = executed;
        } else {
          isExecuting = false;
        }
        let fts = forks[t1.taskReferenceName] || [];
        fts.forEach(ft=>{
          vertices[ft.referenceTaskName] = {name: ft.name, ref: ft.referenceTaskName, type: 'simple', style: 'fill: #ff0', shape: 'rect', description: ft.description};
          nodes.push({type: 'simple', from: t1.taskReferenceName, to: ft.referenceTaskName, label: '', style: style});
          nodes.push({type: 'simple', from: ft.referenceTaskName, to: t2.taskReferenceName, label: '', style: style});
        });
        if(fts.length == 0){
          nodes.push({type: 'simple', from: t1.taskReferenceName, to: t2.taskReferenceName, label: '', style: style});
        }

    } else if(t1.type == 'DECISION'){
      let caseExecuted = false;
      for (let k in t1.decisionCases){
          let tasks = t1.decisionCases[k];

          vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: t1.type, style: 'fill: #ff0', shape: 'diamond', system: true, description: t1.description};
          vertices[tasks[0].taskReferenceName] = {name: tasks[0].name, ref: tasks[0].taskReferenceName, type: tasks[0].type, style: '', shape: 'rect', description: tasks[0].description};

          let style = defstyle;
          if(this.executedTasks[tasks[0].taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
            style = executed;
            caseExecuted = true;
          }

          nodes.push({type: 'decision', from: t1.taskReferenceName, to: tasks[0].taskReferenceName, label: k, style: style});
          this.getTaskNodes(vertices, nodes, tasks, forks, subworkflows, isExecuting);
          this.getNodes(vertices, nodes, tasks[tasks.length-1], t2, forks, subworkflows, isExecuting);

      }

      let tasks = t1.defaultCase;
      if(tasks == null) tasks = [];
      if(tasks.length > 0) {
          vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: t1.type, style: 'fill: #ff0', shape: 'diamond', system: true, description: t1.description};
          vertices[tasks[0].taskReferenceName] = {name: tasks[0].name, ref: tasks[0].taskReferenceName, type: tasks[0].type, style: '', shape: 'rect', description: tasks[0].description};

          let style = defstyle;
          if(this.executedTasks[tasks[0].taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
            style = executed;
          }

          nodes.push({type: 'decision', from: t1.taskReferenceName, to: tasks[0].taskReferenceName, label: 'default', style: style});
          this.getTaskNodes(vertices, nodes, tasks, forks, subworkflows, isExecuting);
          this.getNodes(vertices, nodes, tasks[tasks.length - 1], t2, forks, subworkflows, isExecuting);
      } else {
        nodes.push({type: 'decision', from: t1.taskReferenceName, to: t2.taskReferenceName, label: "", style: !caseExecuted && isExecuting ? executed : defstyle});
      }

    } else if(t1.type == 'JOIN') {

      vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: 'simple', style: 'fill:#ff0', shape: 'ellipse', system:true, description: t1.description};

      let style = defstyle;
      if(this.executedTasks[t2.taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
        style = executed;
      } else {
        isExecuting = false;
      }
      nodes.push({type: 'simple', from: t1.taskReferenceName, to: t2.taskReferenceName, label: '', style: style});

    } else if(t1.type == 'EVENT') {

      vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: 'simple', style: 'fill:#ff0', shape: 'star', system:true, description: t1.description};

      let style = defstyle;
      if(this.executedTasks[t2.taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
        style = executed;
      } else {
        isExecuting = false;
      }
      nodes.push({type: 'simple', from: t1.taskReferenceName, to: t2.taskReferenceName, label: '', style: style});

    } else if(t1.type == 'SUB_WORKFLOW') {
          vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: 'simple', style: 'fill:#efefef', shape: 'rect', system:true, description: t1.description};

        let style = defstyle;
        if(this.executedTasks[t2.taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
          style = executed;
        } else {
          isExecuting = false;
        }
        nodes.push({type: 'simple', from: t1.taskReferenceName, to: t2.taskReferenceName, label: '', style: style});

    } else if(t1.type == 'EXCLUSIVE_JOIN') {

        vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: 'simple', style: 'fill:#ff0', shape: 'star', system:true, description: t1.description};

        let style = defstyle;
        if(this.executedTasks[t2.taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
          style = executed;
        } else {
          isExecuting = false;
        }
        nodes.push({type: 'simple', from: t1.taskReferenceName, to: t2.taskReferenceName, label: '', style: style});

      } else {
        vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: 'simple', style: '', shape: 'rect', description: t1.description};
    }

      let style = defstyle;
      if(this.executedTasks[t2.taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
        style = executed;
      } else {
        isExecuting = false;
      }
      nodes.push({type: 'simple', from: t1.taskReferenceName, to: t2.taskReferenceName, label: '', style: style});
    }
    return nodes;

  }
}

export default Workflow2Graph;
<commit_msg>Fix else condition block<commit_after>import clone from "lodash/fp/clone";

class Workflow2Graph {

  constructor() {
  }

  convert(wfe, meta) {
    this._convert(wfe, meta);
    return {edges: this.edges, vertices: this.vertices, id: wfe.workflowId};
  }
  _convert(wfe = {}, meta = {}) {
    const subworkflows = {};
    const metaTasks = meta.tasks && clone(meta.tasks) || [];
    metaTasks.push({type:'final', name:'final', label: '', taskReferenceName: 'final', system: true});
    metaTasks.unshift({type:'start', name:'start', label: '', taskReferenceName: 'start', system: true});

    const forks = [];
    const tasks = wfe.tasks || [];
    tasks.forEach(tt=>{
      if(tt.taskType === 'FORK'){
        let wfts = [];
        let forkedTasks = tt.inputData && tt.inputData.forkedTasks || [];
        forkedTasks.forEach(ft =>{
          wfts.push({name: ft, referenceTaskName: ft, type: 'SIMPLE'});
        });
        forks[tt.referenceTaskName] = wfts;
      }
    });

    let nodes = [];
    let vertices = {};

    this.executedTasks = {};
    let joins = {};
    wfe.tasks.forEach(t => {
      this.executedTasks[t.referenceTaskName] = {status: t.status, input: t.inputData, output: t.outputData, taskType: t.taskType, reasonForIncompletion: t.reasonForIncompletion, task: t};
      if(t.taskType === 'JOIN' ){
        joins[t.referenceTaskName] = t.inputData.joinOn;
      }
    });

    this.executedTasks['final'] = {status: '', input: '', output: wfe.output, taskType: 'final', reasonForIncompletion: wfe.reasonForIncompletion, task: {}};
    this.executedTasks['start'] = {status: 'STARTED', input: wfe.input, output: '', taskType: 'final', reasonForIncompletion: '', task: {}};
    this.getTaskNodes(vertices, nodes, metaTasks, forks, subworkflows, true);

    this.edges = nodes;
    this.vertices = vertices;
    this.vertices['final'] = {name: 'final', ref: 'final', type: 'final', style: 'fill:#ffffff', shape: 'circle', system: true};
    this.vertices['start'] = {name: 'start', ref: 'start', type: 'start', style: 'fill: #ffffff', shape: 'circle', system: true};

    for(let v in this.vertices) {

      let et = this.executedTasks[v];
      let status = et ? et.status : '';

      let style = '';
      let labelStyle = '';
      switch (status) {
        case 'FAILED':
        case 'TIMED_OUT':
        case 'CANCELLED':
        case 'CANCELED':
        case 'FAILED_WITH_TERMINAL_ERROR':
          style = 'stroke: #ff0000; fill: #ff0000';
          labelStyle = 'fill:#ffffff; stroke-width: 1px';
          break;
        case 'IN_PROGRESS':
        case 'SCHEDULED':
          style = 'stroke: orange; fill: orange';
          labelStyle = 'fill:#ffffff; stroke-width: 1px';
          break;
        case 'COMPLETED':
          style = 'stroke: #48a770; fill: #48a770';
          labelStyle = 'fill:#ffffff; stroke-width: 1px';
          break;
        case 'COMPLETED_WITH_ERRORS':
          style = 'stroke: #FF8C00; fill: #FF8C00';
          labelStyle = 'fill:#ffffff; stroke-width: 1px';
          break;
        case 'SKIPPED':
          style = 'stroke: #cccccc; fill: #ccc';
          labelStyle = 'fill:#ffffff; stroke-width: 1px';
          break;
        case '':
          break;
        default:
          break;
      }
      if (status != '') {

        this.vertices[v].style = style;
        this.vertices[v].labelStyle = labelStyle;
        let tooltip = '
Input
' + JSON.stringify(et.input, null, 2) + '

Output
' + JSON.stringify(et.output, null, 2);
        tooltip += '

Status : ' + et.status + '
';
        if (status == 'FAILED') {
          tooltip += '
Failure Reason

' + et.reasonForIncompletion + '
';
        }
        this.vertices[v].data = et;
        this.vertices[v].tooltip = tooltip;
        this.vertices[v].tooltipTitle = et.taskType + ' - ' + et.status;
      }
    }

  }

  getTaskNodes(vertices, nodes, tasks, forks, subworkflows, isExecutingCase){
    if(tasks == null || tasks.length == null){
      return nodes;
    }
    for(let i = 1; i < tasks.length; i++){
      this.getNodes(vertices, nodes, tasks[i-1], tasks[i], forks, subworkflows, isExecutingCase);
    }
    return nodes;
  }

  getNodes(vertices, nodes, t1, t2, forks, subworkflows, isExecutingCase){

    let executed = 'stroke: #000000; fill: transparent';
    let defstyle = 'stroke: #ccc; fill: transparent; stroke-dasharray: 5, 5';
    let isExecuting = isExecutingCase;
    if(t1.type == 'final' && t1.type == t2.type){
      vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: 'simple', style: '', shape: 'circle', system: true, description: t1.description};
      return nodes;
    }

    if(t1.type == 'FORK_JOIN'){

      vertices[t1.taskReferenceName] = {name: 'FORK', ref: t1.taskReferenceName, type: 'simple', style: 'fill: #ff0', shape: 'house', system: true, description: t1.description};
      let r = t1.taskReferenceName;

      let fork = t1.forkTasks || [];
      fork.forEach(ft => {

        let tasks = ft;

        vertices[tasks[0].taskReferenceName] = {name: tasks[0].name, ref: tasks[0].taskReferenceName, type: tasks[0].type, style: '', shape: 'rect', description: tasks[0].description};

        let style = defstyle;
        if(this.executedTasks[tasks[0].taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
          style = executed;
        } else {
          isExecuting = false;
        }

        nodes.push({type: 'FORK', from: t1.taskReferenceName, to: tasks[0].taskReferenceName, label: '', style: style});

        this.getTaskNodes(vertices, nodes, tasks, forks, subworkflows);
        this.getNodes(vertices, nodes, tasks[tasks.length-1], t2, forks, subworkflows);
      });

    } else if(t1.type == 'FORK_JOIN_DYNAMIC'){

        vertices[t1.taskReferenceName] = {name: 'DYNAMIC_FORK', ref: t1.taskReferenceName, type: 'simple', style: 'fill: #ff0', shape: 'house', system: true, description: t1.description};
        let style = defstyle;
        if(this.executedTasks[t2.taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
          style = executed;
        } else {
          isExecuting = false;
        }
        let fts = forks[t1.taskReferenceName] || [];
        fts.forEach(ft=>{
          vertices[ft.referenceTaskName] = {name: ft.name, ref: ft.referenceTaskName, type: 'simple', style: 'fill: #ff0', shape: 'rect', description: ft.description};
          nodes.push({type: 'simple', from: t1.taskReferenceName, to: ft.referenceTaskName, label: '', style: style});
          nodes.push({type: 'simple', from: ft.referenceTaskName, to: t2.taskReferenceName, label: '', style: style});
        });
        if(fts.length == 0){
          nodes.push({type: 'simple', from: t1.taskReferenceName, to: t2.taskReferenceName, label: '', style: style});
        }

    } else if(t1.type == 'DECISION'){
      let caseExecuted = false;
      for (let k in t1.decisionCases){
          let tasks = t1.decisionCases[k];

          vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: t1.type, style: 'fill: #ff0', shape: 'diamond', system: true, description: t1.description};
          vertices[tasks[0].taskReferenceName] = {name: tasks[0].name, ref: tasks[0].taskReferenceName, type: tasks[0].type, style: '', shape: 'rect', description: tasks[0].description};

          let style = defstyle;
          if(this.executedTasks[tasks[0].taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
            style = executed;
            caseExecuted = true;
          }

          nodes.push({type: 'decision', from: t1.taskReferenceName, to: tasks[0].taskReferenceName, label: k, style: style});
          this.getTaskNodes(vertices, nodes, tasks, forks, subworkflows, isExecuting);
          this.getNodes(vertices, nodes, tasks[tasks.length-1], t2, forks, subworkflows, isExecuting);

      }

      let tasks = t1.defaultCase;
      if(tasks == null) tasks = [];
      if(tasks.length > 0) {
          vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: t1.type, style: 'fill: #ff0', shape: 'diamond', system: true, description: t1.description};
          vertices[tasks[0].taskReferenceName] = {name: tasks[0].name, ref: tasks[0].taskReferenceName, type: tasks[0].type, style: '', shape: 'rect', description: tasks[0].description};

          let style = defstyle;
          if(this.executedTasks[tasks[0].taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
            style = executed;
          }

          nodes.push({type: 'decision', from: t1.taskReferenceName, to: tasks[0].taskReferenceName, label: 'default', style: style});
          this.getTaskNodes(vertices, nodes, tasks, forks, subworkflows, isExecuting);
          this.getNodes(vertices, nodes, tasks[tasks.length - 1], t2, forks, subworkflows, isExecuting);
      } else {
        nodes.push({type: 'decision', from: t1.taskReferenceName, to: t2.taskReferenceName, label: "", style: !caseExecuted && isExecuting ? executed : defstyle});
      }

    } else if(t1.type == 'JOIN') {

      vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: 'simple', style: 'fill:#ff0', shape: 'ellipse', system:true, description: t1.description};

      let style = defstyle;
      if(this.executedTasks[t2.taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
        style = executed;
      } else {
        isExecuting = false;
      }
      nodes.push({type: 'simple', from: t1.taskReferenceName, to: t2.taskReferenceName, label: '', style: style});

    } else if(t1.type == 'EVENT') {

      vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: 'simple', style: 'fill:#ff0', shape: 'star', system:true, description: t1.description};

      let style = defstyle;
      if(this.executedTasks[t2.taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
        style = executed;
      } else {
        isExecuting = false;
      }
      nodes.push({type: 'simple', from: t1.taskReferenceName, to: t2.taskReferenceName, label: '', style: style});

    } else if(t1.type == 'SUB_WORKFLOW') {
          vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: 'simple', style: 'fill:#efefef', shape: 'rect', system:true, description: t1.description};

        let style = defstyle;
        if(this.executedTasks[t2.taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
          style = executed;
        } else {
          isExecuting = false;
        }
        nodes.push({type: 'simple', from: t1.taskReferenceName, to: t2.taskReferenceName, label: '', style: style});

    } else if(t1.type == 'EXCLUSIVE_JOIN') {

        vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: 'simple', style: 'fill:#ff0', shape: 'star', system:true, description: t1.description};

        let style = defstyle;
        if(this.executedTasks[t2.taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
          style = executed;
        } else {
          isExecuting = false;
        }
        nodes.push({type: 'simple', from: t1.taskReferenceName, to: t2.taskReferenceName, label: '', style: style});

      } else {
        vertices[t1.taskReferenceName] = {name: t1.name, ref: t1.taskReferenceName, type: 'simple', style: '', shape: 'rect', description: t1.description};

        let style = defstyle;
        if(this.executedTasks[t2.taskReferenceName] != null && this.executedTasks[t1.taskReferenceName] != null){
          style = executed;
        } else {
          isExecuting = false;
        }
        nodes.push({type: 'simple', from: t1.taskReferenceName, to: t2.taskReferenceName, label: '', style: style});
    }
    return nodes;

  }
}

export default Workflow2Graph;
<|endoftext|>


<commit_before>var path = require('path');
var crdv = require('chromedriver');
var webdriver = require('selenium-webdriver');
var chai = require('chai');
var nconf = require('nconf');
var assert = chai.assert;

var extensionPath = path.resolve('./build/chrome');
var driver = null;

nconf.argv()
  .env()
  .file({ file: './config.json' });

describe('src/pageScript.js', function() {
  this.timeout(100000);

  before(function(done) {
    crdv.start();

    setTimeout(function() {

      driver = new webdriver.Builder()
        .usingServer('http://localhost:9515')
        .withCapabilities({
          chromeOptions: {
            args: [`load-extension=${extensionPath}`]
          }
        })
        .forBrowser('chrome')
        .build();

      // LOGIN
      driver.get('https://vk.com/')
        .then(function() {
          var $email = driver.findElement(webdriver.By.id('index_email'));
          var $pass = driver.findElement(webdriver.By.id('index_pass'));
          var $submit = driver.findElement(webdriver.By.id('index_login_button'));

          $email.sendKeys(nconf.get('vkManager:testLogin'));
          $pass.sendKeys(nconf.get('vkManager:testPassword'));

          $submit.click();

          driver.wait(webdriver.until.titleIs('News'), 20000);
        })
        .then(done)
        .catch(done);
    }, 2000);
  });

  after(function(done) {
    driver.quit()
      .then(function() {
        crdv.stop();
      })
      .then(done);
  });

  it('should change the last board crumb to a anchor', function(done) {
    driver.get(nconf.get('vkManager:boardLink'));
    driver.wait(webdriver.until.elementLocated(webdriver.By.css('a.ui_crumb:last-child')), 10000);
    var $discussionBoard = driver.findElement(webdriver.By.css('a.ui_crumb:last-child'));
    driver.wait(webdriver.until.elementTextContains($discussionBoard, 'Discussion board'), 10000);

    done();
  });

  it('should change the second crumb onClick attribute', function(done) {
    driver.get(nconf.get('vkManager:topicLink'));

    driver.findElement(webdriver.By.css('a.ui_crumb:nth-of-type(2)'))
      .getAttribute('onclick')
      .then(function(attr) {
        assert.deepEqual(attr, 'return nav.go(this, event);');
      })
      .then(done)
      .catch(done);
  });

  it('should play all gifs showing on the page', function(done) {
    driver.get(nconf.get('vkManager:topicLink'))
      .then(function() {
        return driver.findElements(webdriver.By.css('.photo.page_doc_photo_href'));
      })
      .then(function(docs) {
        var promises = docs.map(function(doc) {
          return !doc.isDisplayed();
        });

        return Promise.all(promises);
      })
      .then(function(isDisplayedArr) {
        isDisplayedArr.forEach(function(isDisplayed) {
          assert.isFalse(isDisplayed, 'gif thumb should not be visible');
        });
      })
      .then(function() {
        return driver.findElements(webdriver.By.css('.page_gif_preview.page_gif_loaded'));
      })
      .then(function(gifs) {
        var promises = gifs.map(function(gif) {
          return gif.isDisplayed();
        });

        return Promise.all(promises);
      })
      .then(function(isDisplayedArr) {
        isDisplayedArr.forEach(function(isDisplayed) {
          assert.isTrue(isDisplayed, 'gif should be visible');
        });
      })
      .then(done)
      .catch(done);
  });
});
<commit_msg>Changed env separator<commit_after>var path = require('path');
var crdv = require('chromedriver');
var webdriver = require('selenium-webdriver');
var chai = require('chai');
var nconf = require('nconf');
var assert = chai.assert;

var extensionPath = path.resolve('./build/chrome');
var driver = null;

nconf.argv()
  .env('_')
  .file({ file: './config.json' });

describe('src/pageScript.js', function() {
  this.timeout(100000);

  before(function(done) {
    crdv.start();

    setTimeout(function() {

      driver = new webdriver.Builder()
        .usingServer('http://localhost:9515')
        .withCapabilities({
          chromeOptions: {
            args: [`load-extension=${extensionPath}`]
          }
        })
        .forBrowser('chrome')
        .build();

      // LOGIN
      driver.get('https://vk.com/')
        .then(function() {
          var $email = driver.findElement(webdriver.By.id('index_email'));
          var $pass = driver.findElement(webdriver.By.id('index_pass'));
          var $submit = driver.findElement(webdriver.By.id('index_login_button'));

          $email.sendKeys(nconf.get('vkManager:testLogin'));
          $pass.sendKeys(nconf.get('vkManager:testPassword'));

          $submit.click();

          driver.wait(webdriver.until.titleIs('News'), 20000);
        })
        .then(done)
        .catch(done);
    }, 2000);
  });

  after(function(done) {
    driver.quit()
      .then(function() {
        crdv.stop();
      })
      .then(done);
  });

  it('should change the last board crumb to a anchor', function(done) {
    driver.get(nconf.get('vkManager:boardLink'));
    driver.wait(webdriver.until.elementLocated(webdriver.By.css('a.ui_crumb:last-child')), 10000);
    var $discussionBoard = driver.findElement(webdriver.By.css('a.ui_crumb:last-child'));
    driver.wait(webdriver.until.elementTextContains($discussionBoard, 'Discussion board'), 10000);

    done();
  });

  it('should change the second crumb onClick attribute', function(done) {
    driver.get(nconf.get('vkManager:topicLink'));

    driver.findElement(webdriver.By.css('a.ui_crumb:nth-of-type(2)'))
      .getAttribute('onclick')
      .then(function(attr) {
        assert.deepEqual(attr, 'return nav.go(this, event);');
      })
      .then(done)
      .catch(done);
  });

  it('should play all gifs showing on the page', function(done) {
    driver.get(nconf.get('vkManager:topicLink'))
      .then(function() {
        return driver.findElements(webdriver.By.css('.photo.page_doc_photo_href'));
      })
      .then(function(docs) {
        var promises = docs.map(function(doc) {
          return !doc.isDisplayed();
        });

        return Promise.all(promises);
      })
      .then(function(isDisplayedArr) {
        isDisplayedArr.forEach(function(isDisplayed) {
          assert.isFalse(isDisplayed, 'gif thumb should not be visible');
        });
      })
      .then(function() {
        return driver.findElements(webdriver.By.css('.page_gif_preview.page_gif_loaded'));
      })
      .then(function(gifs) {
        var promises = gifs.map(function(gif) {
          return gif.isDisplayed();
        });

        return Promise.all(promises);
      })
      .then(function(isDisplayedArr) {
        isDisplayedArr.forEach(function(isDisplayed) {
          assert.isTrue(isDisplayed, 'gif should be visible');
        });
      })
      .then(done)
      .catch(done);
  });
});
<|endoftext|>


<commit_before>/**
 * The MIT License
 * Copyright (c) 2014 Essoduke Chang http://essoduke.org
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Javascript Internationalization (i18n)
 * The easy way to perform i18n to your javascript project..
 *
 * @author Essoduke Chang
 * @see http://app.essoduke.org/i18n/
 * @version 1.1
 *
 * Last Modified Thu, 3 April 2014 07:47:04 GMT
 */
var i18n = (function (window, undefined) {

    'use strict';

    /*
     * Check the client timezone to adjust DST
     */
    var DST = function () {
        var rightNow = new Date(),
            temp  = '',
            date1 = new Date(rightNow.getFullYear(), 0, 1, 0, 0, 0, 0),
            date2 = new Date(rightNow.getFullYear(), 6, 1, 0, 0, 0, 0),
            date3 = '',
            date4 = '',
            hoursDiffStdTime = 0,
            hoursDiffDaylightTime = 0;
        temp = date1.toGMTString();
        date3 = new Date(temp.substring(0, temp.lastIndexOf(" ") - 1));
        temp = date2.toGMTString();
        date4 = new Date(temp.substring(0, temp.lastIndexOf(" ") - 1));
        hoursDiffStdTime = (date1 - date3) / (1000 * 60 * 60);
        hoursDiffDaylightTime = (date2 - date4) / (1000 * 60 * 60);
        return (hoursDiffDaylightTime !== hoursDiffStdTime) ? true : false;
    },

    //language code
    lang = '',

    // language file's path
    path = '',

    //localize object
    localize = {},

    //default setting
    setting = {
        "UTC" : -4,
        "format": "Y-m-d H:i:s",
        "AM" : "AM",
        "PM": "PM"
    },

    //fetch lauguage string in JSON object
    locale = function (langcode) {

        var result = {},
            xmlhttp = {},
            url = (0 !== path.length ? path.replace(/\/$/, '') + '/' : '') + langcode + '.js';

        // Use jQuery ajax
        if (window.jQuery) {
            jQuery.ajax({
                url: url,
                async: false,
                cache: true,
                dataType: 'JSON'
            })
            .fail(function (xhr, status, error) {
                console.dir(status);
            })
            .done(function (resp) {
                result = resp;
            });
        } else {
            // Native XMLHttpRequest
            var callback = function () {
                if (xmlhttp.readyState === 4) {
                    if (xmlhttp.status === 200) {
                        try {
                            if ('function' === typeof JSON.parse) {
                                result = JSON.parse(xmlhttp.responseText);
                            }
                        } catch (ignore) {
                        }
                    }
                }
            };
            if (window.XMLHttpRequest) {
                xmlhttp = new XMLHttpRequest();
                if (xmlhttp.overrideMimeType) {
                    xmlhttp.overrideMimeType('application/json; charset=UTF-8');
                }
            } else if (window.ActiveXObject) {
                var activexName = ['MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'];
                for (var i = 0; i < activexName.length; i += 1) {
                    try {
                        xmlhttp = new ActiveXObject(activexName[i]);
                        break;
                    } catch (ignore) {
                    }
                }
            }
            xmlhttp.onreadystatechange = callback;
            xmlhttp.open('GET', url, false);
            xmlhttp.send(null);
        }
        return result;
    };

    /**
     * _hasOwnProperty for compatibility IE
     * @param {Object} obj Object
     * @param {string} property Property name
     * @return {boolean}
     * @version 2.4.3
     */
    function _hasOwnProperty (obj, property) {
        try {
            return (!window.hasOwnProperty) ?
                   Object.prototype.hasOwnProperty.call(obj, property.toString()) :
                   obj.hasOwnProperty(property.toString());
        } catch (ignore) {
        }
    }

    /*
     * Datetime format
     */
    Date.prototype.format = function (format) {
        var returnStr = '',
            replace = Date.replaceChars,
            curChar = '',
            i = 0;
        replace.reload();
        for (i = 0; i < format.length; i += 1) {
            curChar = format.charAt(i);
            returnStr += (replace[curChar] ? replace[curChar].call(this) : curChar);
        }
        return returnStr;
    };

    /*
     * Datetime function object
     * @see http://jacwright.com/projects/javascript/date_format (unavailable)
     * @see http://code.google.com/p/omeglelogger/source/browse/trunk/dateformat.js?spec=svn2&r=2
     */
    Date.replaceChars = {
        reload: function () {
            this.shortMonths = _hasOwnProperty(localize, 'shortMonths') ?
                               localize.shortMonths :
                               ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
            this.longMonths = _hasOwnProperty(localize, 'longMonths') ?
                              localize.longMonths :
                              ['January','February','March','April','May','June','July','August','September','October','November','December'];
            this.shortDays = _hasOwnProperty(localize, 'shortDays') ?
                             localize.shortDays :
                             ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
            this.longDays = _hasOwnProperty(localize, 'longDays') ?
                            localize.longDays :
                            ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
        },
        shortMonths: [],
        longMonths: [],
        shortDays: [],
        longDays: [],
        d: function () {
            return (this.getUTCDate() < 10 ? '0' : '') + this.getUTCDate();
        },
        D: function () {
            return Date.replaceChars.shortDays[this.getUTCDay()];
        },
        j: function () {
            return this.getUTCDate();
        },
        l: function () {
            return Date.replaceChars.longDays[this.getUTCDay()];
        },
        N: function () {
            return this.getDay() + 1;
        },
        S: function () {
            return (
                this.getUTCDate() % 10 === 1 && this.getUTCDate() !== 11 ?
                'st' :
                (this.getUTCDate() % 10 === 2 && this.getUTCDate() !== 12 ? 'nd' :
                    (this.getUTCDate() % 10 === 3 && this.getUTCDate() !== 13 ? 'rd' : 'th')
                )
            );
        },
        w: function () {
            return this.getUTCDay();
        },
        z: function () {
            return '';
        },
        W: function () {
            return '';
        },
        F: function () {
            return Date.replaceChars.longMonths[this.getUTCMonth()];
        },
        m: function () {
            return (this.getUTCMonth() < 9 ? '0' : '') + (this.getUTCMonth() + 1);
        },
        M: function () {
            return Date.replaceChars.shortMonths[this.getUTCMonth()];
        },
        n: function () {
            return this.getUTCMonth() + 1;
        },
        t: function () {
            return '';
        },
        L: function () {
            return '';
        },
        o: function () {
            return '';
        },
        Y: function () {
            return this.getUTCFullYear();
        },
        y: function () {
            return ('' + this.getUTCFullYear()).substr(2);
        },
        a: function () {
            var set = _hasOwnProperty(localize, 'setting') ? localize.setting : setting;
            return this.getUTCHours() < 12 ? set.AM : set.PM;
        },
        A: function () {
            var set = _hasOwnProperty(localize, 'setting') ? localize.setting : setting;
            return this.getUTCHours() < 12 ? set.AM : set.PM;
        },
        B: function () {
            return '';
        },
        g: function () {
            return this.getUTCHours() %12 || 12;
        },
        G: function () {
            return this.getUTCHours();
        },
        h: function () {
            return ((this.getUTCHours() % 12 || 12 ) < 10 ? '0' : '' ) +
                    (this.getUTCHours() %12 || 12);
        },
        H: function () {
            return (this.getUTCHours() < 10 ? '0' : '') + this.getUTCHours();
        },
        i: function () {
            return (this.getUTCMinutes() < 10 ? '0' : '') +
            this.getUTCMinutes();
        },
        s: function () {
            return (this.getUTCSeconds() < 10 ? '0' : '') +
            this.getUTCSeconds();
        },
        e: function () {
            return '';
        },
        I: function () {
            return '';
        },
        O: function () {
            return (-this.getTimezoneOffset() < 0 ? '-' : '+') +
            (Math.abs(this.getTimezoneOffset() / 60) < 10 ? '0' : '') +
            (Math.abs(this.getTimezoneOffset() / 60)) + '00';
        },
        T: function () {
            var m = this.getUTCMonth();
            this.setMonth(0);
            var result = this.toTimeString().replace(/^.+ \(?([^\)]+)\)?$/, '$1');
            this.setMonth(m);
            return result;
        },
        Z: function () {
            return -this.getTimezoneOffset() * 60;
        },
        c: function () {
            return '';
        },
        r: function () {
            return this.toString();
        },
        U: function () {
            return this.getUTCTime() / 1000;
        }
    };

    /*
     * Similar the ASP Dateadd function
     */
    var DateAdd = function (interval, number, date ) {
        var d;
        number = parseInt(number, 10);
        if ('string' === typeof date) {
            date = date.split(/\D/);
            date[1] -= 1;
            d = new Date(date.join(','));
        }
        d = ('object' === typeof d) ? d : date;
        switch (interval) {
            case 'y':
                d.setFullYear(d.getFullYear() + number);
                break;
            case 'm':
                d.setMonth(d.getMonth() + number);
                break;
            case 'd':
                d.setDate(d.getDate() + number);
                break;
            case 'w':
                d.setDate(d.getDate() + 7 * number);
                break;
            case 'h':
                d.setHours(d.getHours() + number);
                break;
            case 'n':
                d.setMinutes(d.getMinutes() + number);
                break;
            case 's':
                d.setSeconds(d.getSeconds() + number);
                break;
            case 'l':
                d.setMilliseconds(d.getMilliseconds() + number);
                break;
        }
        return d;
    };

    /*
     * Public functions
     */
    return {

        /*
         * i18n setting
         */
        set: function (options) {
            if (null !== options && 'object' === typeof options) {
                lang = options.hasOwnProperty('lang') ? options.lang : null;
                path = options.hasOwnProperty('path') ? options.path : path;
            }
            localize = locale(lang || (navigator.browserLanguage || navigator.language).toLowerCase());
        },

        /*
         * Core of the datetime replace
         */
        datetime: function (d) {
            var set = localize.hasOwnProperty('setting') ?
                      localize.setting :
                      setting,
                r   = set.format ?
                      DateAdd('h', set.UTC, d ? new Date(d) : new Date()) :
                      (d ? new Date(d) : new Date());
            return r.format(set.format);
        },

        /*
         * Core of the strings replace
         */
        _: function (string) {
            try {
                string = string.toString() || '';
                var args = arguments,
                    pattern = (args.length > 0) ?
                              new RegExp('%([1-' + args.length.toString() + '])', 'g') :
                              null,
                    str = '',
                    array = -1 !== string.indexOf('.') ?
                            string.split(/\./gi) :
                            string;

                if ('string' === typeof array) {
                    str = localize.hasOwnProperty(array) ?
                          localize[array] :
                          array;
                } else {
                    str = _hasOwnProperty(localize, array[0]) ?
                          (
                              _hasOwnProperty(localize[array[0]], array[1]) ?
                              localize[array[0]][array[1]] :
                              array.join('.')
                          ) :
                          array.join('.');
                }
                return String(str).replace(pattern, function (match, index) {
                    return args[index];
                });
            } catch (ignore) {
                console.dir(ignore);
            }
        }
    };
}(window));
<commit_msg>v1.2<commit_after>/**
 * Javascript Internationalization (i18n)
 * The easy way to perform i18n to your javascript project..
 * Copyright (c) 2015 Essoduke Chang http://essoduke.org, Licensed MIT.
 *
 * @author Essoduke Chang
 * @see http://app.essoduke.org/i18n/
 * @version 1.2
 *
 * Last Modified 2015.07.10.165852
 */
var i18n = (function (window, undefined) {

    'use strict';

    /**
     * Check the client timezone to adjust DST
     */
    var DST = function () {
        var rightNow = new Date(),
            temp  = '',
            date1 = new Date(rightNow.getFullYear(), 0, 1, 0, 0, 0, 0),
            date2 = new Date(rightNow.getFullYear(), 6, 1, 0, 0, 0, 0),
            date3 = '',
            date4 = '',
            hoursDiffStdTime = 0,
            hoursDiffDaylightTime = 0;
        temp = date1.toGMTString();
        date3 = new Date(temp.substring(0, temp.lastIndexOf(" ") - 1));
        temp = date2.toGMTString();
        date4 = new Date(temp.substring(0, temp.lastIndexOf(" ") - 1));
        hoursDiffStdTime = (date1 - date3) / (1000 * 60 * 60);
        hoursDiffDaylightTime = (date2 - date4) / (1000 * 60 * 60);
        return (hoursDiffDaylightTime !== hoursDiffStdTime) ? true : false;
    },

    //language code
    lang = '',

    // language file's path
    path = '',

    //localize object
    localize = {},

    //default setting
    setting = {
        "UTC"    : -4,
        "format" : "Y-m-d H:i:s",
        "AM"     : "AM",
        "PM"     : "PM"
    },

    //fetch lauguage string in JSON object
    locale = function (langcode) {

        var result   = {},
            xmlhttp  = {},
            url      = [(0 !== path.length ? path.replace(/\/$/, '') + '/' : ''), langcode, '.js'].join(''),
            callback = {};

        // Use jQuery ajax
        if (window.jQuery) {
            jQuery.ajax({
                'url'     : url,
                'async'   : false,
                'cache'   : true,
                'dataType': 'JSON'
            })
            .fail(function (xhr, status, error) {
            })
            .done(function (resp) {
                result = resp;
            });
        } else {
            // XMLHttpRequest callback
            callback = function () {
                if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
                    try {
                        if ('function' === typeof JSON.parse) {
                            result = JSON.parse(xmlhttp.responseText);
                        }
                    } catch (ignore) {
                        console.warn(ignore.message);
                    }
                }
            };
            // Native XMLHttpRequest
            if (window.XMLHttpRequest) {
                xmlhttp = new XMLHttpRequest();
                if (xmlhttp.overrideMimeType) {
                    xmlhttp.overrideMimeType('application/json; charset=UTF-8');
                }
            } else if (window.ActiveXObject) {
                var activexName = ['MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'],
                    i = 0;
                for (i = 0; i < activexName.length; i += 1) {
                    try {
                        xmlhttp = new ActiveXObject(activexName[i]);
                        break;
                    } catch (ignore) {
                        console.warn(ignore.message);
                    }
                }
            }
            xmlhttp.onreadystatechange = callback;
            xmlhttp.open('GET', url, false);
            xmlhttp.send(null);
        }
        return result;
    };

    /**
     * _hasOwnProperty for compatibility IE
     * @param {Object} obj Object
     * @param {string} property Property name
     * @return {boolean}
     * @version 2.4.3
     */
    function _hasOwnProperty (obj, property) {
        try {
            return (!window.hasOwnProperty) ?
                   Object.prototype.hasOwnProperty.call(obj, property.toString()) :
                   obj.hasOwnProperty(property.toString());
        } catch (ignore) {
            console.warn(ignore.message);
        }
    }

    /**
     * Datetime format
     */
    Date.prototype.format = function (format) {
        var returnStr = '',
            replace   = Date.replaceChars,
            curChar   = '',
            i = 0;
        replace.reload();
        for (i = 0; i < format.length; i += 1) {
            curChar = format.charAt(i);
            returnStr += (replace[curChar] ? replace[curChar].call(this) : curChar);
        }
        return returnStr;
    };

    /**
     * Datetime function object
     * @see {@link http://jacwright.com/projects/javascript/date_format (unavailable)}
     * @see {@link http://code.google.com/p/omeglelogger/source/browse/trunk/dateformat.js?spec=svn2&r=2}
     */
    Date.replaceChars = {

        reload: function () {
            this.shortMonths = _hasOwnProperty(localize, 'shortMonths') ?
                               localize.shortMonths :
                               ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
            this.longMonths  = _hasOwnProperty(localize, 'longMonths') ?
                               localize.longMonths :
                               ['January','February','March','April','May','June','July','August','September','October','November','December'];
            this.shortDays   = _hasOwnProperty(localize, 'shortDays') ?
                               localize.shortDays :
                               ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
            this.longDays    = _hasOwnProperty(localize, 'longDays') ?
                               localize.longDays :
                               ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
        },
        shortMonths: [],
        longMonths : [],
        shortDays  : [],
        longDays   : [],
        d: function () {
            return (this.getUTCDate() < 10 ? '0' : '') + this.getUTCDate();
        },
        D: function () {
            return Date.replaceChars.shortDays[this.getUTCDay()];
        },
        j: function () {
            return this.getUTCDate();
        },
        l: function () {
            return Date.replaceChars.longDays[this.getUTCDay()];
        },
        N: function () {
            return this.getDay() + 1;
        },
        S: function () {
            return (
                this.getUTCDate() % 10 === 1 && this.getUTCDate() !== 11 ?
                'st' :
                (this.getUTCDate() % 10 === 2 && this.getUTCDate() !== 12 ? 'nd' :
                    (this.getUTCDate() % 10 === 3 && this.getUTCDate() !== 13 ? 'rd' : 'th')
                )
            );
        },
        w: function () {
            return this.getUTCDay();
        },
        z: function () {
            return '';
        },
        W: function () {
            return '';
        },
        F: function () {
            return Date.replaceChars.longMonths[this.getUTCMonth()];
        },
        m: function () {
            return (this.getUTCMonth() < 9 ? '0' : '') + (this.getUTCMonth() + 1);
        },
        M: function () {
            return Date.replaceChars.shortMonths[this.getUTCMonth()];
        },
        n: function () {
            return this.getUTCMonth() + 1;
        },
        t: function () {
            return '';
        },
        L: function () {
            return '';
        },
        o: function () {
            return '';
        },
        Y: function () {
            return this.getUTCFullYear();
        },
        y: function () {
            return ('' + this.getUTCFullYear()).substr(2);
        },
        a: function () {
            var set = _hasOwnProperty(localize, 'setting') ? localize.setting : setting;
            return this.getUTCHours() < 12 ? set.AM : set.PM;
        },
        A: function () {
            var set = _hasOwnProperty(localize, 'setting') ? localize.setting : setting;
            return this.getUTCHours() < 12 ? set.AM : set.PM;
        },
        B: function () {
            return '';
        },
        g: function () {
            return this.getUTCHours() %12 || 12;
        },
        G: function () {
            return this.getUTCHours();
        },
        h: function () {
            return ((this.getUTCHours() % 12 || 12 ) < 10 ? '0' : '' ) +
                    (this.getUTCHours() %12 || 12);
        },
        H: function () {
            return (this.getUTCHours() < 10 ? '0' : '') + this.getUTCHours();
        },
        i: function () {
            return (this.getUTCMinutes() < 10 ? '0' : '') +
            this.getUTCMinutes();
        },
        s: function () {
            return (this.getUTCSeconds() < 10 ? '0' : '') +
            this.getUTCSeconds();
        },
        e: function () {
            return '';
        },
        I: function () {
            return '';
        },
        O: function () {
            return (-this.getTimezoneOffset() < 0 ? '-' : '+') +
            (Math.abs(this.getTimezoneOffset() / 60) < 10 ? '0' : '') +
            (Math.abs(this.getTimezoneOffset() / 60)) + '00';
        },
        T: function () {
            var m = this.getUTCMonth();
            this.setMonth(0);
            var result = this.toTimeString().replace(/^.+ \(?([^\)]+)\)?$/, '$1');
            this.setMonth(m);
            return result;
        },
        Z: function () {
            return -this.getTimezoneOffset() * 60;
        },
        c: function () {
            return '';
        },
        r: function () {
            return this.toString();
        },
        U: function () {
            return this.getUTCTime() / 1000;
        }
    };

    /**
     * Similar the ASP Dateadd function
     */
    var DateAdd = function (interval, number, date ) {
        var d;
        number = parseInt(number, 10);
        if ('string' === typeof date) {
            date = date.split(/\D/);
            date[1] -= 1;
            d = new Date(date.join(','));
        }
        d = ('object' === typeof d) ? d : date;
        switch (interval) {
        case 'y':
            d.setFullYear(d.getFullYear() + number);
            break;
        case 'm':
            d.setMonth(d.getMonth() + number);
            break;
        case 'd':
            d.setDate(d.getDate() + number);
            break;
        case 'w':
            d.setDate(d.getDate() + 7 * number);
            break;
        case 'h':
            d.setHours(d.getHours() + number);
            break;
        case 'n':
            d.setMinutes(d.getMinutes() + number);
            break;
        case 's':
            d.setSeconds(d.getSeconds() + number);
            break;
        case 'l':
            d.setMilliseconds(d.getMilliseconds() + number);
            break;
        }
        return d;
    };

    /**
     * Public functions
     */
    return {

        /**
         * i18n setting
         */
        set: function (options) {
            if ('object' === typeof options) {
                lang = _hasOwnProperty(options, 'lang') ? options.lang : null;
                path = _hasOwnProperty(options, 'path') ? options.path : path;
            }
            localize = locale(lang || (navigator.browserLanguage || navigator.language).toLowerCase());
        },

        /**
         * Core of the datetime replace
         */
        datetime: function (d) {
            var set = _hasOwnProperty(localize, 'setting') ?
                      localize.setting :
                      setting,
                r   = set.format ?
                      DateAdd('h', set.UTC, d ? new Date(d) : new Date()) :
                      (d ? new Date(d) : new Date());
            return r.format(set.format);
        },

        /**
         * Core of the strings replace
         */
        t: function (string) {
            try {
                string = string.toString() || '';
                var args = arguments,
                    pattern = (args.length > 0) ?
                              new RegExp('%([1-' + args.length.toString() + '])', 'g') :
                              null,
                    str = '',
                    array = ~string.indexOf('.') ?
                            string.split(/\./gi) :
                            string;

                if ('string' === typeof array) {
                    str = _hasOwnProperty(localize, array) ?
                          localize[array] :
                          array;
                } else if (Object.prototype.toString.call(array) === '[object Array]' && 2 === array.length) {
                    str = _hasOwnProperty(localize, array[0]) ?
                          (
                              _hasOwnProperty(localize[array[0]], array[1]) ?
                              localize[array[0]][array[1]] :
                              array.join('.')
                          ) :
                          array.join('.');
                }
                return String(str).replace(pattern, function (match, index) {
                    return args[index];
                });
            } catch (ignore) {
                console.dir(ignore);
            }
        }
    };
}(window));
//#EOF

<|endoftext|>